LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

CVI debugger: unable to read memory

Solved!
Go to solution

Thanks! ...and sorry for looking into your dark corners without a bulb Smiley Wink

0 Kudos
Message 11 of 13
(1,940 Views)

Hello,

 

it seems I had to reopen this discution...

 

My problem is that after free-ing an allocated pointer (without carying type ) in debug mode I have a memory leak, that grows in time (in debug mode with Extended - debug mode).

 

Ex:

double *pDouble;
unsigned int  uiPointer;

pDouble = malloc(sizeof(double));
uiPointer = (unsigned int) pDouble;
free((double*) uiPointer);

 

 

How can I fix this leak?

 

Thank you in advance,

 

Daniel

0 Kudos
Message 12 of 13
(1,894 Views)

Hello Daniel,

 

When you malloc some memory, we attach internal information to the pointer that helps us perform run-time checking on the pointer (out of bounds etc). We free the information again when you free the pointer. We call this mechanism "user-protection".

 

Unfortunately by casting the pointer to an integer you lose the link between the original pointer and its internal user-protection information. When you free the "integer", we don't know where it came from and if it ever had user-protection information associated with it. So we leak the user-protection information.

 

We document this in our online help:

 

http://zone.ni.com/reference/en-XX/help/370051Y-01/cvi/programmerref/disablinguserprotectionforindiv...

 

The important part is that you do not cast a pointer to an int and then back to a pointer. That drops the user-protection information. It's safe to cast from one pointer type to a different pointer type. But casting to an integer and back is risky.

 

You can fix this by freeing the original pointer pDouble:

 

double *pDouble;
uintptr_t  uiPointer; // use uintptr_t instead of unsigned int to guarantee it can hold
// a pointer-sized value in 32-bit and 64-bit programs pDouble = malloc(sizeof(double)); uiPointer = (uintptr_t) pDouble; free(pDouble); // free original pointer

Or by changing the type of uiPointer to actually be a pointer, for example, void *uiPointer:

 

double *pDouble;
void *uiPointer;

pDouble = malloc(sizeof(double)); // note: it's important to assign to pDouble
// because it implicitly casts the newly allocated
// memory to (double*). another implementation quirk. uiPointer = pDouble; free(uiPointer);

If uiPointer has to be an integer type, then it's preferable to cast it to an integer type where it's used. I know it's annoying but that's how it is unfortunately. You can also declare uiPointer twice and then use them as needed:

 

double *pDouble;
void *uiPointer;
uintptr_t uiPointerInt;

pDouble = malloc(sizeof(double));
uiPointer = pDouble;
uiPointerInt = (uintptr_t)pDouble;
free(uiPointer);

 Now, you may be tempted to define a union that holds both types:

 

union {
void *pointer; // THIS DOES NOT WORK!!!
uintptr_t integer;
} uiValue;

Unfortunately, this doesn't work because we throw away user-protection information for pointers in unions. There's just no way for us to verify that the pointer information is still valid for the pointer in the union. It's really the same reason why we throw away user-protection when you cast a pointer to an integer. We cannot track the information through unions or integers because we cannot (and don't want to) intercept all accesses to unions and integers to cover this corner case.

 

Best regards,

 

Peter

Message 13 of 13
(1,884 Views)