可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
In my company there is a coding rule that says, after freeing any memory, reset the variable to NULL. For example ...
void some_func ()
{
int *nPtr;
nPtr = malloc (100);
free (nPtr);
nPtr = NULL;
return;
}
I feel that, in cases like the code shown above, setting to NULL does not have any meaning. Or am I missing something?
If there is no meaning in such cases, I am going to take it up with the \"quality team\" to remove this coding rule. Please advice.
回答1:
Setting unused pointers to NULL is a defensive style, protecting against dangling pointer bugs. If a dangling pointer is accessed after it is freed, you may read or overwrite random memory. If a null pointer is accessed, you get an immediate crash on most systems, telling you right away what the error is.
For local variables, it may be a little bit pointless if it is \"obvious\" that the pointer isn\'t accessed anymore after being freed, so this style is more appropriate for member data and global variables. Even for local variables, it may be a good approach if the function continues after the memory is released.
To complete the style, you should also initialize pointers to NULL before they get assigned a true pointer value.
回答2:
Setting a pointer to NULL
after free
is a dubious practice that is often popularized as a \"good programming\" rule on a patently false premise. It is one of those fake truths that belong to the \"sounds right\" category but in reality achieve absolutely nothing useful (and sometimes leads to negative consequences).
Allegedly, setting a pointer to NULL
after free
is supposed to prevent the dreaded \"double free\" problem when the same pointer value is passed to free
more than once. In reality though, in 9 cases out of 10 the real \"double free\" problem occurs when different pointer objects holding the same pointer value are used as arguments for free
. Needless to say, setting a pointer to NULL
after free
achieves absolutely nothing to prevent the problem in such cases.
Of course, it is possible to run into \"double free\" problem when using the same pointer object as an argument to free
. However, in reality situations like that normally indicate a problem with the general logical structure of the code, not a mere accidental \"double free\". A proper way to deal with the problem in such cases is to review and rethink the structure of the code in order to avoid the situation when the same pointer is passed to free
more than once. In such cases setting the pointer to NULL
and considering the problem \"fixed\" is nothing more than an attempt to sweep the problem under the carpet. It simply won\'t work in general case, because the problem with the code structure will always find another way to manifest itself.
Finally, if your code is specifically designed to rely on the pointer value being NULL
or not NULL
, it is perfectly fine to set the pointer value to NULL
after free
. But as a general \"good practice\" rule (as in \"always set your pointer to NULL
after free
\") it is, once again, a well-known and pretty useless fake, often followed by some for purely religious, voodoo-like reasons.
回答3:
Most of the responses have focused on preventing a double free, but setting the pointer to NULL has another benefit. Once you free a pointer, that memory is available to be reallocated by another call to malloc. If you still have the original pointer around you might end up with a bug where you attempt to use the pointer after free and corrupt some other variable, and then your program enters an unknown state and all kinds of bad things can happen (crash if you\'re lucky, data corruption if you\'re unlucky). If you had set the pointer to NULL after free, any attempt to read/write through that pointer later would result in a segfault, which is generally preferable to random memory corruption.
For both reasons, it can be a good idea to set the pointer to NULL after free(). It\'s not always necessary, though. For example, if the pointer variable goes out of scope immediately after free(), there\'s not much reason to set it to NULL.
回答4:
This is considered good practice to avoid overwriting memory. In the above function, it is unnecessary, but oftentimes when it is done it can find application errors.
Try something like this instead:
#if DEBUG_VERSION
void myfree(void **ptr)
{
free(*ptr);
*ptr = null;
}
#else
#define myfree(p) do { void ** __p = (p); free(*(__p)); *(__p) = null; } while (0)
#endif
The DEBUG_VERSION lets you profile frees in debugging code, but both are functionally the same.
Edit: Added do ... while as suggested below, thanks.
回答5:
If you reach pointer that has been free()d, it might break or not. That memory might be reallocated to another part of your program and then you get memory corruption,
If you set the pointer to NULL, then if you access it, the program always crashes with a segfault. No more ,,sometimes it works\'\', no more ,,crashes in unpredictible way\'\'. It\'s way easier to debug.
回答6:
Setting the pointer to the free
\'d memory means that any attempt to access that memory through the pointer will immediately crash, instead of causing undefined behavior. It makes it much easier to determine where things went wrong.
I can see your argument: since nPtr
is going out of scope right after nPtr = NULL
, there doesn\'t seem to be a reason to set it to NULL
. However, in the case of a struct
member or somewhere else where the pointer is not immediately going out of scope, it makes more sense. It\'s not immediately apparent whether or not that pointer will be used again by code that shouldn\'t be using it.
It\'s likely the rule is stated without making a distinction between these two cases, because it\'s much more difficult to automatically enforce the rule, let alone for the developers to follow it. It doesn\'t hurt to set pointers to NULL
after every free, but it has the potential of pointing out big problems.
回答7:
the most common bug in c is the double free. Basically you do something like that
free(foobar);
/* lot of code */
free(foobar);
and it end up pretty bad, the OS try to free some already freed memory and generally it segfault. So the good practice is to set to NULL
, so you can make test and check if you really need to free this memory
if(foobar != null){
free(foobar);
}
also to be noted that free(NULL)
won\'t do anything so you don\'t have to write the if statement. I am not really an OS guru but I am pretty even now most OSes would crash on double free.
That\'s also a main reason why all languages with garbage collection (Java, dotnet) was so proud of not having this problem and also not having to leave to developers the memory management as a whole.
回答8:
The idea behind this, is to stop accidental reuse of the freed pointer.
回答9:
This (can) actually be important. Although you free the memory, a later part of the program could allocate something new that happens to land in the space. Your old pointer would now point to a valid chunk of memory. It is then possible that someone would use the pointer, resulting in invalid program state.
If you NULL out the pointer, then any attempt to use it is going to dereference 0x0 and crash right there, which is easy to debug. Random pointers pointing to random memory is hard to debug. It\'s obviously not necessary but then that\'s why it\'s in a best practices document.
回答10:
From the ANSI C standard:
void free(void *ptr);
The free function causes the space
pointed to by ptr to be deallocated,
that is, made available for further
allocation. If ptr is a null pointer,
no action occurs. Otherwise, if the
argument does not match a pointer
earlier returned by the calloc ,
malloc , or realloc function, or if
the space has been deallocated by a
call to free or realloc , the behavior
is undefined.
\"the undefined behavior\" is almost always a program crash. So as to avoid this it is safe to reset the pointer to NULL. free() itself cannot do this as it is passed only a pointer, not a pointer to a pointer. You can also write a safer version of free() that NULLs the pointer:
void safe_free(void** ptr)
{
free(*ptr);
*ptr = NULL;
}
回答11:
I find this to be little help as in my experience when people access a freed memory allocation it\'s almost always because they have another pointer to it somewhere. And then it conflicts with another personal coding standard which is \"Avoid useless clutter\", so I don\'t do it as I think it rarely helps and makes the code slightly less readable.
However - I won\'t set the variable to null if the pointer isn\'t supposed to be used again, but often the higher level design gives me a reason to set it to null anyway. For example if the pointer is a member of a class and I\'ve deleted what it points to then the \"contract\" if you like of the class is that that member will point to something valid at any time so it must be set to null for that reason. A small distinction but I think an important one.
In c++ it\'s important to always be thinking who owns this data when you allocate some memory (unless you are using smart pointers but even then some thought is required). And this process tends to lead to pointers generally being a member of some class and generally you want a class to be in a valid state at all times, and the easiest way to do that is to set the member variable to NULL to indicate it points to nothing now.
A common pattern is to set all the member pointers to NULL in the constructor and have the destructor call delete on any pointers to data that your design says that class owns. Clearly in this case you have to set the pointer to NULL when you delete something to indicate that you don\'t own any data before.
So to summarise, yes i often set the pointer to NULL after deleting something, but it\'s as part of a larger design and thoughts on who owns the data rather than due to blindly following a coding standard rule. I wouldn\'t do so in your example as I think there is no benefit to doing so and it adds \"clutter\" which in my experience is just as responsible for bugs and bad code as this kind of thing.
回答12:
Recently I come across the same question after I was looking for the answer. I reached this conclusion:
It is best practice, and one must follow this to make it portable on all (embedded) systems.
free()
is a library function, which varies as one changes the platform, so you should not expect that after passing pointer to this function and after freeing memory, this pointer will be set to NULL. This may not be the case for some library implemented for the platform.
so always go for
free(ptr);
ptr = NULL;
回答13:
This rule is useful when you\'re trying to avoid the following scenarios:
1) You have a really long function with complicated logic and memory management and you don\'t want to accidentally reuse the pointer to deleted memory later in the function.
2) The pointer is a member variable of a class that has fairly complex behavior and you don\'t want to accidentally reuse the pointer to deleted memory in other functions.
In your scenario, it doesn\'t make a whole lot of sense, but if the function were to get longer, it might matter.
You may argue that setting it to NULL may actually mask logic errors later on, or in the case where you assume it is valid, you still crash on NULL, so it doesn\'t matter.
In general, I would advise you to set it to NULL when you think it is a good idea, and not bother when you think it isn\'t worth it. Focus instead on writing short functions and well designed classes.
回答14:
To add to what other have said, one good method of pointer usage is to always check whether it is a valid pointer or not. Something like:
if(ptr)
ptr->CallSomeMethod();
Explicitly marking the pointer as NULL after freeing it allows for this kind of usage in C/C++.
回答15:
This might be more an argument to initialize all pointers to NULL, but something like this can be a very sneaky bug:
void other_func() {
int *p; // forgot to initialize
// some unrelated mallocs and stuff
// ...
if (p) {
*p = 1; // hm...
}
}
void caller() {
some_func();
other_func();
}
p
ends up in the same place on the stack as the former nPtr
, so it might still contain a seemingly valid pointer. Assigning to *p
might overwrite all kinds of unrelated things and lead to ugly bugs. Especially if the compiler initializes local variables with zero in debug mode but doesn\'t once optimizations are turned on. So the debug builds don\'t show any signs of the bug while release builds blow up randomly...
回答16:
Set the pointer that has just been freed to NULL is not mandatory but a good practice. In this way , you can avoid 1) using a freed pointed 2)free it towice
回答17:
Settings a pointer to NULL is to protect agains so-called double-free - a situation when free() is called more than once for the same address without reallocating the block at that address.
Double-free leads to undefined behaviour - usually heap corruption or immediately crashing the program. Calling free() for a NULL pointer does nothing and is therefore guaranteed to be safe.
So the best practice unless you now for sure that the pointer leaves scope immediately or very soon after free() is to set that pointer to NULL so that even if free() is called again it is now called for a NULL pointer and undefined behaviour is evaded.
回答18:
There are two reasons:
Avoid crashes when double-freeing
Written by RageZ in a duplicate question.
The most common bug in c is the double
free. Basically you do something like
that
free(foobar);
/* lot of code */
free(foobar);
and it end up pretty bad, the OS try
to free some already freed memory and
generally it segfault. So the good
practice is to set to NULL
, so you
can make test and check if you really
need to free this memory
if(foobar != null){
free(foobar);
}
also to be noted that free(NULL)
won\'t do anything so you don\'t have to
write the if statement. I am not
really an OS guru but I am pretty even
now most OSes would crash on double
free.
That\'s also a main reason why all
languages with garbage collection
(Java, dotnet) was so proud of not
having this problem and also not
having to leave to developer the
memory management as a whole.
Avoid using already freed pointers
Written by Martin v. Löwis in a another answer.
Setting unused pointers to NULL is a
defensive style, protecting against
dangling pointer bugs. If a dangling
pointer is accessed after it is freed,
you may read or overwrite random
memory. If a null pointer is accessed,
you get an immediate crash on most
systems, telling you right away what
the error is.
For local variables, it may be a
little bit pointless if it is
\"obvious\" that the pointer isn\'t
accessed anymore after being freed, so
this style is more appropriate for
member data and global variables. Even
for local variables, it may be a good
approach if the function continues
after the memory is released.
To complete the style, you should also
initialize pointers to NULL before
they get assigned a true pointer
value.
回答19:
The idea is that if you try to dereference the no-longer-valid pointer after freeing it, you want to fail hard (segfault) rather than silently and mysteriously.
But... be careful. Not all systems cause a segfault if you dereference NULL. On (at least some versions of) AIX, *(int *)0 == 0, and Solaris has optional compatibility with this AIX \"feature.\"
回答20:
To the original question:
Setting the pointer to NULL directly after freeing the contents is a complete waste of time, provided the code meets all requirements, is fully debugged and will never be modified again. On the other hand, defensively NULLing a pointer that has been freed can be quite useful when someone thoughtlessly adds a new block of code beneath the free(), when the design of the original module isn\'t correct, and in the case of it-compiles-but-doesn\'t-do-what-I-want bugs.
In any system, there is an unobtainable goal of making it easiest to the right thing, and the irreducible cost of inaccurate measurements. In C we\'re offered a set of very sharp, very strong tools, which can create many things in the hands of a skilled worker, and inflict all sorts of metaphoric injuries when handled improperly. Some are hard to understand or use correctly. And people, being naturally risk averse, do irrational things like checking a pointer for NULL value before calling free with it…
The measurement problem is that whenever you attempt to divide good from less good, the more complex the case, the more likely you get an ambiguous measurement. If the goal is do keep only good practices, then some ambiguous ones get tossed out with the actually not good. IF your goal is to eliminate the not good, then the ambiguities may stay with the good. The two goals, keep only good or eliminate clearly bad, would seem to be diametrically opposed, but there is usually a third group that\'s neither one nor the other, some of both.
Before you make a case with the quality department, try looking through the bug data base to see how often, if ever, invalid pointer values caused problems that had to be written down. If you want to make real difference, identify the most common problem in your production code and propose three ways to prevent it
回答21:
As you have a quality assurance team in place, let me add a minor point about QA. Some automated QA tools for C will flag assignments to freed pointers as \"useless assignment to ptr
\". For example PC-lint/FlexeLint from Gimpel Software says
tst.c 8 Warning 438: Last value assigned to variable \'nPtr\' (defined at line 5) not used
There are ways to selectively suppress messages, so you can still satisfy both QA requirements, should your team decide so.
回答22:
It is always advisable to declare a pointer variable with NULL such as,
int *ptr = NULL;
Let\'s say, ptr is pointing to 0x1000 memory address.
After using free(ptr)
, it\'s always advisable to nullify the pointer variable by declaring again to NULL.
e.g.:
free(ptr);
ptr = NULL;
If not re-declared to NULL, the pointer variable still keeps on pointing to the same address (0x1000), this pointer variable is called a dangling pointer.
If you define another pointer variable (let\'s say, q) and dynamically allocate address to the new pointer, there is a chance of taking the same address (0x1000) by new pointer variable. If in case, you use the same pointer (ptr) and update the value at the address pointed by the same pointer (ptr), then the program will end up writing a value to the place where q is pointing (since p and q are pointing to the same address (0x1000)).
e.g.
*ptr = 20; //Points to 0x1000
free(ptr);
int *q = (int *)malloc(sizeof(int) * 2); //Points to 0x1000
*ptr = 30; //Since ptr and q are pointing to the same address, so the value of the address to which q is pointing would also change.
回答23:
Long story short: You do not want to accidentally (by mistake) access the address that you have freed. Because, when you free the address, you allow that address in the heap to be allocated to some other application.
However, if you do not set the pointer to NULL, and by mistake try to de-reference the pointer, or change the value of that address; YOU CAN STILL DO IT. BUT NOT SOMETHING THAT YOU WOULD LOGICALLY WANT TO DO.
Why can I still access the memory location that I have freed? Because: You may have free the memory, but the pointer variable still had information about the heap memory address. So, as a defensive strategy, please set it to NULL.