what is issue in dangling pointer? - c

whenever I read dangling pointers article. I can not anticipate the potential risk here.
What is the issue in below code if I do not initialize the pointer, or I do not assign ptr to NULL after deal locating malloc? Why it becomes dangling, what is the risk here?
int main()
{
int *ptr; //what is risk here?
ptr = (int *)malloc(sizeof(int));
// After below free call, ptr becomes a
// dangling pointer
free(ptr);
//ptr = NULL; //what is risk here if i do not assign NULL?
}

There is only a dangling pointer risk if you use a pointer when the data it points to is no longer valid. That is not the case in your code snippet provided.
If you do use it while the data it points to is invalid (uninitialised before the malloc or dangling after the free), all bets are off, that's undefined behaviour (UB).
It's also UB if you use the NULL that may be returned if your malloc failed, you should always check for that. And, because of that, setting it to NULL after the memory it points to ceases to be valid will not help you at all. It's just as much UB to dereference NULL as it is to dereference memory that's been freed.
You can make your code a lot safer with something like:
int main(void) {
int *ptr = malloc(sizeof(int));
if (ptr == NULL) {
puts("Could not allocate");
return 1;
}
// safe to use pointer here.
free(ptr);
// but not here.
}

The risk is not in the code shown, the risk is in the code after maintenance, modification and reuse. Or in "cargo-cult" copying of the anti-pattern. If for example you added a great deal of code between the initialised ptr declaration and the malloc(), it may no longer be clear that the pointer is not yet valid.
Dereferencing a null pointer "by accident" will normally be trapped as a run-time error, so likely to be detected during testing and development and reported at the point of error. Dereferencing a pointer that is a valid address but say refers to a block returned to the heap for re-use may have no immediate observable impact, but may later cause unrelated code to fail, possibly after deployment and in unpredictable ways - those bugs are very difficult to track down.
Dereferencing a pointer that simply has not been initialised, will have undefined behaviour, it may appear to work, it may trigger an exception, it may cause the code to appear to fail at an unrelated location in the code - again such bugs are hard to track down unless you were lucky enough for it to fail immediately - if it happened to be NULL or an invalid address triggering an exception for example.
Besides that, there are no advantages to the "unsafe" code:
int *ptr; //what is risk here?
ptr = (int *)malloc(sizeof(int));
over both safer and simpler code thus:
int* ptr = malloc( sizeof(*ptr) ) ;
Note other improvements in this:
do not cast a void-pointer to the destination type,
use the sizeof the object pointed to (or a multiple thereof) rather than an explicit type.
Remember in modern C, is is no longer necessary to declare all variables at the start of a brace-block ({...}) - though you will still see that anti-pattern too - so there are few excuses for not initialising a pointer with a useful value on instantiation.

int main()
{
int *ptr; //what is risk here?
ptr = (int *)malloc(sizeof(int));
Here you have 2 risks. The first one is that in real project between these 2 lines of code it could be a lot of another code. And there is a chance that you (or somebody else who maintains this code) will try to dereference this pointer before it's initialised.
The second one is that the return value of malloc is not checked, so in case if malloc failed, you will not know that it failed.
free(ptr);
//ptr = NULL; //what is risk here if i do not assign NULL?
When you make free() you don't really "free" the memory (you don't set all bits in allocated chunk of memory to '0') you just mark this memory as "it could be allocated again in future allocations). But your pointer is still points to this chunk of memory. So after some period of time this chunk of memory could be used for another allocation. Some new data will be stored to this chunk (data will be overwritten). And your pointer will point to the memory that stores not relevant data. And you (or worth - somebody else who maintains your project) could use this pointer without knowing that he points to non-relevant data.

Related

Double NULL(*ing) in C

While I was doing my assignment I came across an issue. I know that double freeing cause undefined behavior.
When a program calls free() twice with the same argument, the program's memory management data structures become corrupted. This corruption can cause the program to crash or, in some circumstances, cause two later calls to malloc() to return the same pointer. If malloc() returns the same value twice and the program later gives the attacker control over the data that is written into this doubly-allocated memory, the program becomes vulnerable to a buffer overflow attack.
CWE-415: Double Free
However, while fuzzing I encountered double NULL(set NULL twice(one after another) for one variable) where pointer was NULL(ed) twice.
Is that same with double freeing and cause undefined behaviour?
e.g.
int *p;
p = (int*)malloc(10*sizeof(int));
p = NULL;
p = NULL; (**seconds time)**
I'm not quite sure what you're asking about, but:
if you try to free() the same memory block twice in a row:
void* ptr = malloc(120);
free(ptr);
free(ptr);
then the second call to free() will probably corrupt the heap;
however, if you set your pointer variable to NULL after freeing the pointed block:
void* ptr = malloc(120);
free(ptr);
ptr = NULL;
// ....do some other stuff
// (but no assignment to ptr!)
free(ptr);
ptr = NULL;
then the second call to free() passes a NULL pointer to it, and free() returns with no harm.
Setting ptr to NULL does not free the allocated memory. This would work e.g. in Java, where the virtual machine tracks all references to objects and deletes those no longer used. In that context the first ptr = null; would make a pointed object eligible for deleting (provided no other references to it exist), and another ptr = null; would not change anything.
In C you must 'manually' release memory you allocated and that is quite separate from nullifying any pointer variables.
If you do
int *p;
p = (int*)malloc(10*sizeof(int));
p = NULL;
p = NULL;
then you: declare a p variable; allocate a block of memory and store its address in the p variable; overwrite the stored address with a NULL pointer (thus effectively you loose access to the allocated memory block); and overwrite it once again with the same NULL value.
That does not affect the allocated block. It remains allocated till the end of your program execution, but without the pointer value returned from malloc() you can't use it or even free() it. That's what we call a memory leak.
A pointer can be "nulled" twice, because its just assigning a value to it. The memory however is still allocated. Setting the pointer to null won't change that. This is why you can do this as often as you like.
With free()-ing the pointer however, you're deallocating the memory. This means is could be used for other variables and such.
Once the memory was deallocated, you can't deallocate it a second time, this is why it causes undefined behaviour.
Have a look at this question for reference.
NULL is a macro that most of the times stands for 0. So all you do is, assign 0 twice to a variable. So pretty defined behaviour...

What is the issue with double free()?

I've been seeing quite a bit of erroneous code around the web and in my Advanced C class (such as the code below). While I understand that it's obviously bad coding practice, I'm having a difficult time as to what it does that's so bad other than waste CPU cycles. From my understanding so far, if a pointer allocation is not located in the "malloc table" (for lack of a better word), it is usually ignored. I'd appreciate if someone here could provide me with a better understanding as to why this is bad and (other than the fact that it's a silly thing to do) and the consequences of it are.
char* ptr = malloc(1);
...
free(ptr);
...
free(ptr);
Consider in your example after free(ptr) you did following
char* ptr = malloc(1);
free(ptr) // <-- This will delete the pointer
ptr2 = malloc(1) // <-- now you request again
now malloc is what it is and can return the same pointer as ptr and if it does and if now you do
// if you call me again and if ptr2 == ptr oops!
free(ptr)
-- your ptr2 is freed causing unexpected behavior with lots of crash, pain and hours of debugging..
This is not just a waste of CPU cycles. Double free() is undefined behaviour, which means that the program is allowed to behave in arbitrary ways.
The program might work just fine, or it might blow up in testing, or it might pass all your tests and then blow up in your customer's face, or it might corrupt some data, or it might launch a nuclear strike, etc. All of these are valid manifestations of undefined behaviour.
C11, section 7.22.3.3 says that:
[...] Otherwise, if the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
A good advise: nullify pointer after free. In your case you have undefined behaviour, because computer can allocate memory, which is pointed by ptr, or may not allocate this piece of memory, or this chunk of memory could be added to other chunk of memory during defragmentation, etc.
On the other hand, free(NULL) is defined and will do nothing.
char* ptr = malloc(1);
...
free(ptr);
ptr = NULL;
...
free(ptr);

Malloc and free: memory being freed was not allocated

The following is from the Libaiff library. I get the following error completely randomly (i.e. sometimes my program works flawlessly and sometimes it gets stuck with this error and it always breaks at the same point within this function).
(1949,0x7fff7b82d310) malloc: * error for object 0xd00000000b400: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
My question is, if r->buffer2 has already been freed, then is it possible for the control to get past the statement if (r->buffer2) and into the block to try and execute free(r->buffer2)? In other words, if r->buffer2 has been freed, shouldn't the if (r->buffer2) prevent the freeing from trying to happen again?
static void AIFF_ReadClose(AIFF_Ref r)
{
if (r->buffer)
free(r->buffer);
if (r->buffer2)
free(r->buffer2); // THIS IS WHERE THE BREAK OCCURS EVERYTIME
Unprepare(r);
fclose(r->fd);
free(r);
return;
}
EDIT:
The following is the definition for AIFF_Ref:
struct s_AIFF_Ref {
FILE* fd;
int flags;
int stat; /* status */
int segmentSize;
int bitsPerSample;
int nMarkers;
int nChannels;
double samplingRate;
uint64_t nSamples;
int markerPos;
uint64_t len;
uint64_t soundLen;
uint64_t pos;
uint64_t sampleBytes;
uint64_t commonOffSet;
uint64_t soundOffSet;
uint64_t markerOffSet;
IFFType format;
IFFType audioFormat;
void* decoder;
void* pdata;
void* buffer;
size_t buflen;
void* buffer2;
size_t buflen2;
int tics;
};
typedef struct s_AIFF_Ref* AIFF_Ref;
Can anyone suggest why this strange behavior might be happening and how I might solve it?
Thanks.
From the documentation,
The free function deallocates a memory block (memblock) that was
previously allocated by a call to calloc, malloc, or realloc.( Assume first free case )
If memblock is NULL, the pointer is ignored and free immediately returns. (You never came here because, you never set your pointer to NULL)
Attempting to free an invalid pointer (a pointer to a memory block
that was not allocated by calloc, malloc, or realloc) may affect
subsequent allocation requests and cause errors. ( Assume second free case )
if (r->buffer2)
{
free(r->buffer2);
r->buffer2 = NULL ; // Always set the pointer to NULL,
// if you doubt that you may gonna 'free' the memory again,
// somewhere else.
}
if (r->buffer2)
{
free(r->buffer2);
r->buffer2 = NULL ;
}
This is because, when you free the memory, the free assures you that the memory will be free'd but it doesn't assures you that it will delete or NULL'ify the value written in the pointer variable. So, if( r->buffer2 ) holds TRUE for your case and hence, the flow enters the if block.
When you received the error message, one possibility was that it had been freed before, another possibility was that the value of the pointer had been changed to point to another memory.
To avoid this, you must pay attention not to change the pointer before you free it and after having freed memory, you should set the point to NULL.
According to the documentation you liked to, you're already provided with open and close functions, namely
AIFF_Ref AIFF_OpenFile(const char* name, int flags) ;
and
int AIFF_CloseFile(AIFF_Ref r) ;
This call should deallocate memory. Have you tried that?
The short answer to your question is no. Calling free(r->buffer2) does not prevent if (r->buffer2) from evaluating to true and subsequently calling free again. The reason is that free(r->buffer2) does not modify the value of r->buffer2. Think of it this way: if you hired a demolition company to go destroy a building, and you handed them a card with the address of the building you wanted destroyed, would the address written on the card suddenly disappear after they destroyed the building? No. A pointer is no different. It's just an address, stored in a variable that we call a "pointer" because it identifies a memory address. The piece of memory it points to is not the same thing as the pointer itself.
As to what is causing the duplicate call to free(), you haven't provided enough information to ascertain that, so one can only speculate.
Please find your question to response and some additional information which might be useful.
if r->buffer2 has been freed, shouldn't the if (r->buffer2) prevent
the freeing from trying to happen again?
There is no way to know the information that whether memory has already been freed or not. As someone has pointed out that checking pointer with 'null' does some sanity check and normally we do in that way. But this would work only when is your logic somebody set the pointer with 'null' after freeing the memory, otherwise the 'null' check would not work and your current code would execute the 'free' as the pointer is not assigned to 'null' while freeing the memory.
By looking the address, it looked to me that the 'buffer2' has some garbage value and you should be getting different address value whenever you might be running your program. This might occur in the scenario where 'AIFF_Ref' object might not have been initialized properly and still it holds some garbage value. One way to do it is to set
memset((void*)r, 0, sizeof(struct s_AIFF_Ref));
This would intialize all with default values. This may avoid the chances of any garbage value assigned to yout 'buffer2' variables.
You have mentioned that these are logic of some library hence I would recommend you to use some dynamic tool to understand the error quickly and and at the point where problem is happening.From your description it is also possible that your program has some sort of memory corruption. I think my previous post might be useful for this problem as well.
If your program is windows specific, you should see the following link:
https://stackoverflow.com/a/22074401/2724703
If your program is Gnu/Linux specific, you should see the following link:
https://stackoverflow.com/a/22085874/2724703

is it necessary to call pointer = NULL when initializing?

when I create a pointer to certain struct, do I have to set it to NULL, then alloc it then use it? and why?
No, you don't have to set it to NULL, but some consider it good practice as it gives a new pointer a value that makes it explicit it's not pointing at anything (yet).
If you are creating a pointer and then immediately assigning another value to it, then there's really not much value in setting it to NULL.
It is a good idea to set a pointer to NULL after you free the memory it was pointing to, though.
No, there is no requirement (as far as the language is concerned) to initialize a pointer variable to anything when declaring it. Thus
T* ptr;
is a valid declaration that introduces a variable named ptr with an indeterminate value. You can even use the variable in certain ways without first allocating anything or setting it to any specific value:
func(&ptr);
According to the C standard, not initializing an automatic storage variable leaves its value indeterminate.
You are definitely encouraged to set pointers to NULL whenever the alternative is your pointer having an indeterminate value. Usage of pointers with an indeterminate value is undefined behavior, a concept that you might not grasp properly if you're used to C programming and come from higher level languages.
Undefined behavior means that anything could happen, and this is a part of the C standard since the philosophy of C is letting the programmer have the burden to control things, instead of protecting him from his mistakes.
You want to avoid undefined behaviors in code: it is very hard to debug stuff when any behavior can occurr. It is not caught by a compiler, and your tests may always pass, leaving the bug unnoticed until it is very expensive to correct it.
If you do something like this:
char *p;
if(!p) puts("Pointer is NULL");
You don't actually know whether that if control will be true or false. This is extremely dangerous in large programs where you may declare your variable and then use it somewhere very far in space and time.
Same concept when you reference freed memory.
free(p);
printf("%s\n", p);
p = q;
You don't actually know what you're going to get with the last two statements. You can't test it properly, you cannot be sure of your outcome. Your code may seem to work because freed memory is recycled even if it may have been altered... you could even overwrite memory, or corrupt other variables that share the same memory. So you still have a bug that sooner or later will manifest itself and could be very hard to debug it.
If you set the pointer to NULL, you protect yourself from these dangerous situations: during your tests, your program will have a deterministic, predictable behavior that will fail fast and cheaply. You get a segfault, you catch the bug, you fix the bug. Clean and simple:
#include <stdio.h>
#include <stdlib.h>
int main(){
char* q;
if(!q) puts("This may or may not happen, who knows");
q = malloc(10);
free(q);
printf("%s\n", q); // this is probably don't going to crash, but you still have a bug
char* p = NULL;
if(!p) puts("This is always going to happen");
p = malloc(10);
free(p);
p = NULL;
printf("%s\n", p); // this is always going to crash
return 0;
}
So, when you initialize a pointer, especially in large programs, you want them to be explicitely initliazed or set to NULL. You don't want them to get an indeterminate value, never. I should say unless you know what you are doing, but I prefer never instead.
No, don't forget that initialization has to be to a null pointer at all. A very convenient idiom in modern C is to declare variables at their first use
T * ptr = malloc(sizeof *ptr);
This avoids you a lot of hussle of remembering the type and whether or not a variable is already initialized. Only if you don't know where (or even if) it is later initialized, then you definitively should initialize it to a null pointer.
So as a rule of thumb, always initialize variables to the appropriate value. The "proper 0 for the type" is always a good choice if you don't have a better one at hand. For all types, C is made like that, such that it works.
Not initializing a variable is premature optimization in most cases. Only go through your variables when you see that there is a real performance bottleneck, there. In particular if there is an assignment inside the same function before a use of the initial value, andy modern compiler will optimize you the initialization out. Think correctness of your program first.
You dont have to unless you dont want it to dangle a while. You know you should after freeing(defensive style).
You do not have to initialize to NULL. If you intend to allocate it immediately, you can skip it.
At can be useful for error handling like in the following example. In this case breaking to the end after p allocation would leave q uninitialized.
int func(void)
{
char *p;
char *q;
p = malloc(100);
if (!p)
goto end;
q = malloc(100);
if (!q)
goto end;
/* Do something */
end:
free(p);
free(q);
return 0;
}
Also, and this is my personal taste, allocate structs always with calloc. Strings may be allocated uninitialized with malloc

What's the point of malloc(0)?

I just saw this code:
artist = (char *) malloc(0);
...and I was wondering why would one do this?
According to the specifications, malloc(0) will return either "a null pointer or a unique pointer that can be successfully passed to free()".
This basically lets you allocate nothing, but still pass the "artist" variable to a call to free() without worry. For practical purposes, it's pretty much the same as doing:
artist = NULL;
The C standard (C17 7.22.3/1) says:
If the size of the space requested is zero, the behavior is implementation defined:
either a null pointer is returned, or the behavior is as if the size were some
nonzero value, except that the returned pointer shall not be used to access an object.
So, malloc(0) could return NULL or a valid pointer that may not be dereferenced. In either case, it's perfectly valid to call free() on it.
I don't really think malloc(0) has much use, except in cases when malloc(n) is called in a loop for example, and n might be zero.
Looking at the code in the link, I believe that the author had two misconceptions:
malloc(0) returns a valid pointer always, and
free(0) is bad.
So, he made sure that artist and other variables always had some "valid" value in them. The comment says as much: // these must always point at malloc'd data.
malloc(0) behaviour is implementation specific. The library can return NULL or have the regular malloc behaviour, with no memory allocated. Whatever it does, it must be documented somewhere.
Usually, it returns a pointer that is valid and unique but should NOT be dereferenced. Also note that it CAN consume memory even though it did not actually allocate anything.
It is possible to realloc a non null malloc(0) pointer.
Having a malloc(0) verbatim is not much use though. It's mostly used when a dynamic allocation is zero byte and you didn't care to validate it.
There's an answer elsewhere on this page that begins "malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory". This statement is incorrect (I don't have enough reputation to comment on that answer directly, so can't put this comment directly under there).
Doing malloc(0) will not automatically allocate memory of correct size. The malloc function is unaware of what you're casting its result to. The malloc function relies purely on the size number that you give as its argument. You need to do malloc(sizeof(int)) to get enough storage to hold an int, for example, not 0.
There are a lot of half true answers around here, so here are the hard facts. The man-page for malloc() says:
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be
successfully passed to free().
That means, there is absolutely no guarantee that the result of malloc(0) is either unique or not NULL. The only guarantee is provided by the definition of free(), again, here is what the man-page says:
If ptr is NULL, no operation is performed.
So, whatever malloc(0) returns, it can safely be passed to free(). But so can a NULL pointer.
Consequently, writing artist = malloc(0); is in no way better than writing artist = NULL;
malloc(0) doesn't make any sense to me, unless the code is relying on behaviour specific to the implementation. If the code is meant to be portable, then it has to account for the fact that a NULL return from malloc(0) isn't a failure. So why not just assign NULL to artist anyway, since that's a valid successful result, and is less code, and won't cause your maintenance programmers to take time figuring it out?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO) or malloc(some_variable_which_might_be_zero) perhaps could have their uses, although again you have to take extra care not to treat a NULL return as a failure if the value is 0, but a 0 size is supposed to be OK.
Why you shouldn't do this...
Since malloc's return value is implementation dependent, you may get a NULL pointer or some other address back. This can end up creating heap-buffer overflows if error handling code doesn't check both size and returned value, leading to stability issues (crashes) or even worse security issues.
Consider this example, where further accessing memory via returned address will corrupt heap iff size is zero and implementation returns a non NULL value back.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
See this Secure Coding page from CERT Coding Standards where I took the example above for further reading.
Admittedly, I have never seen this before, this is the first time I've seen this syntax, one could say, a classic case of function overkill. In conjunction to Reed's answer, I would like to point out that there is a similar thing, that appears like an overloaded function realloc:
foo is non-NULL and size is zero, realloc(foo, size);. When you pass in a non-NULL pointer and size of zero to realloc, realloc behaves as if you’ve called free(…)
foo is NULL and size is non-zero and greater than 1, realloc(foo, size);. When you pass in a NULL pointer and size is non-zero, realloc behaves as if you’ve called malloc(…)
Hope this helps,
Best regards,
Tom.
In Windows:
void *p = malloc(0); will allocate a zero-length buffer on the local heap. The pointer returned is a valid heap pointer.
malloc ultimately calls HeapAlloc using the default C runtime heap which then calls RtlAllocateHeap, etc.
free(p); uses HeapFree to free the 0-length buffer on the heap. Not freeing it would result in a memory leak.
To actually answer the question made: there is no reason to do that
malloc(0) will return NULL or a valid pointer which can be rightly passed to free. And though it seems like the memory that it points to is useless or it can't be written to or read from, that is not always true. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
We expect a segmentation fault here, but surprisingly, this prints 100! It is because malloc actually asks for a huge chunk of memory when we call malloc for the first time. Every call to malloc after that, uses memory from that big chunk. Only after that huge chunk is over, new memory is asked for.
Use of malloc(0): if you are in a situation where you want subsequent malloc calls to be faster, calling malloc(0) should do it for you (except for edge cases).
Not sure, according to some random malloc source code I found, an input of 0 results in a return value of NULL. So it's a crazy way of setting the artist pointer to NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Its actually quite useful, and (obviously IMHO), the allowed behavior of returning a NULL pointer is broken. A dynamic pointer is useful not only for what it points at, but also the fact that it's address is unique. Returning NULL removes that second property. All of the embedded mallocs I program (quite frequently in fact) have this behavior.
Here is the analysis after running with valgrind memory check tool.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
and here's my sample code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
By default 1024 bytes is allocated. If I increase the size of malloc, the allocated bytes will increase by 1025 and so on.
According to Reed Copsey answer and the man page of malloc , I wrote some examples to test. And I found out malloc(0) will always give it a unique value.
See my example :
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
The output will be "Got a valid pointer", which means ptr is not null.
Just to correct a false impression here:
artist = (char *) malloc(0); will never ever return NULL; it's not the same as artist = NULL;. Write a simple program and compare artist with NULL. if (artist == NULL) is false and if (artist) is true.
malloc(0) will return a valid memory address and whose range will depend on the type of pointer which is being allocated memory. Also you can assign values to the memory area but this should be in range with the type of pointer being used. You can also free the allocated memory. I will explain this with an example:
int *p=NULL;
p=(int *)malloc(0);
free(p);
The above code will work fine in a gcc compiler on Linux machine. If you have a 32 bit compiler then you can provide values in the integer range, i.e. -2147483648 to 2147483647. Same applies for characters also. Please note that if type of pointer declared is changed then range of values will change regardless of malloc typecast, i.e.
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p will take a value from 0 to 255 of char since it is declared an unsigned int.

Resources