Many C code freeing pointers calls:
if (p)
free(p);
But why? I thought C standard say the free function doesn't do anything given a NULL pointer. So why another explicit check?
The construct:
free(NULL);
has always been OK in C, back to the original UNIX compiler written by Dennis Ritchie. Pre-standardisation, some poor compilers might not have fielded it correctly, but these days any compiler that does not cannot legitimately call itself a compiler for the C language. Using it typically leads to clearer, more maintainable code.
As I understand, the no-op on NULL was not always there.
In the bad old days of C (back around
1986, on a pre-ANSI standard cc
compiler) free(NULL) would dump core.
So most devs tested for NULL/0 before
calling free.
The world has come a long way, and it
appears that we don't need to do the
test anymore. But old habits die
hard;)
http://discuss.joelonsoftware.com/default.asp?design.4.194233.15
I tend to write "if (p) free(p)" a lot, even if I know it's not needed.
I partially blame myself because I learned C the old days when free(NULL) would segfault and I still feel uncomfortable not doing it.
But I also blame the C standard for not being consistent. Would, for example, fclose(NULL) be well defined, I would not have problems in writing:
free(p);
fclose(f);
Which is something that happens very often when cleaning up things.
Unfortunately, it seems strange to me to write
free(p);
if (f) fclose(f);
and I end up with
if (p) free(p);
if (f) fclose(f);
I know, it's not a rational reason but that's my case :)
Compilers, even when inlining are not smart enough to know the function will return immediately. Pushing parameters etc on stack and setting the call up up is obviously more expensive than testing a pointer. I think it is always good practice to avoid execution of anything, even when that anything is a no-op.
Testing for null is a good practice. An even better practice is to ensure your code does not reach this state and therefore eliminate the need for the test altogether.
There are two distinct reasons why a pointer variable could be NULL:
because the variable is used for what in type theory is called an option type, and holds either a pointer to an object, or NULL to represent nothing,
because it points to an array, and may therefore be NULL if the array has zero length (as malloc(0) is allowed to return NULL, implementation-defined).
Although this is only a logical distinction (in C there are neither option types nor special pointers to arrays and we just use pointers for everything), it should always be made clear how a variable is used.
That the C standard requires free(NULL) to do nothing is the necessary counterpart to the fact that a successful call to malloc(0) may return NULL. It is not meant as a general convenience, which is why for example fclose() does require a non-NULL argument. Abusing the permission to call free(NULL) by passing a NULL that does not represent a zero-length array feels hackish and wrong.
If you rely on that free(0) is OKAY, and it's normal for your pointer to be null at this point, please say so in comment // may be NULL
This may be merely self-explanatory code, saying yes I know, I also use p as a flag.
there can be a custom implementation of free() in mobile environment.
In that case free(0) can cause a problem.
(yeah, bad implementation)
if (p)
free(p);
why another explicit check?
If I write something like that, it's to convey the specific knowledge that the pointer may be NULL...to assist in readability and code comprehension. Because it looks a bit weird to make that an assert:
assert(p || !p);
free(p);
(Beyond looking strange, compilers are known to complain about "condition always true" if you turn your warnings up in many such cases.)
So I see it as good practice, if it's not clear from the context.
The converse case, of a pointer being expected to be non null, is usually evident from the previous lines of code:
...
Unhinge_Widgets(p->widgets);
free(p); // why `assert(p)`...you just dereferenced it!
...
But if it's non-obvious, having the assert may be worth the characters typed.
Related
I'm making a data structures and algorithms library in C for learning purposes (so this doesn't necessarily have to be bullet-proof), and I'm wondering how void functions should handle errors on preconditions. If I have a function for destroying a list as follows:
void List_destroy(List* list) {
/*
...
free()'ing pointers in the list. Nothing to return.
...
*/
}
Which has a precondition that list != NULL, otherwise the function will blow up in the caller's face with a segfault.
So as far as I can tell I have a few options: one, I throw in an assert() statement to check the precondition, but that means the function would still blow up in the caller's face (which, as far as I have been told, is a big no-no when it comes to libraries), but at least I could provide an error message; or two, I check the precondition, and if it fails I jump to an error block and just return;, silently chugging along, but then the caller doesn't know the List* was NULL.
Neither of these options seem particularly appealing. Moreover, implementing a return value for a simple destroy() function seems like it should be unnecessary.
EDIT: Thank you everyone. I settled on implementing (in all my basic list functions, actually) consistent behavior for NULL List* pointers being passed to the functions. All the functions jump to an error block and exit(1) as well as report an error message to stderr along the lines of "Cannot destroy NULL list." (or push, or pop, or whatever). I reasoned that there's really no sensible reason why a caller should be passing NULL List* pointers anyway, and if they didn't know they were then by all means I should probably let them know.
Destructors (in the abstract sense, not the C++ sense) should indeed never fail, no matter what. Consistent with this, free is specified to return without doing anything if passed a null pointer. Therefore, I would consider it reasonable for your List_destroy to do the same.
However, a prompt crash would also be reasonable, because in general the expectation is that C library functions crash when handed invalid pointers. If you take this option, you should crash by going ahead and dereferencing the pointer and letting the kernel fire a SIGSEGV, not by assert, because assert has a different crash signature.
Absolutely do not change the function signature so that it can potentially return a failure code. That is the mistake made by the authors of close() for which we are still paying 40 years later.
Generally, you have several options if a constraint of one of your functions is violated:
Do nothing, successfully
Return some value indicating failure (or set something pointed-to by an argument to some error code)
Crash randomly (i.e. introduce undefined behaviour)
Crash reliably (i.e. use assert or call abort or exit or the like)
Where (but this is my personal opinion) this is a good rule of thumb:
the first option is the right choice if you think it's OK to not obey the constraints (i.e. they aren't real constraints), a good example for this is free.
the second option is the right choice, if the caller can't know in advance if the call will succeed; a good example is fopen.
the third and fourth option are a good choice if the former two don't apply. A good example is memcpy. I prefer the use of assert (one of the fourth options) because it enables both: Crashing reliably if someone is unwilling to read your documentation and introduce undefined behaviour for people who do read it (they will prevent that by obeying your constraints), depending on whether they compile with NDEBUG defined or not. Dereferencing a pointer argument can serve as an assert, because it will make your program crash (which is the right thing, people not reading your documentation should crash as early as possible) if these people pass an invalid pointer.
So, in your case, I would make it similar to free and would succeed without doing anything.
HTH
If you wish not to return any value from function, then it is good idea to have one more argument for errCode.
void List_destroy(List* list, int* ErrCode) {
*ErrCode = ...
}
Edit:
Changed & to * as question is tagged for C.
I would say that simply returning in case the list is NULL would make sense at this would indicate that list is empty(not an error condition). If list is an invalid pointer, you cant detect that and let kernel handle it for you by giving a seg fault and let programmer fix it.
Suppose I came across an instance in a program where I would either free a NULL pointer, or first check whether it was NULL and skip the free() function call.
Would it be more efficient to simply free a NULL pointer? I searched around a bit and apparently, for implementations post C89, it is harmless to free a NULL pointer - so the decision comes down to efficiency.
My presumption is that there may potentially entail quite a bit of overhead when calling free(). As such, perhaps the simple logical check before calling the free() function is quite necessary.
tl;dr version,
What is happening internally when a call to free() is made that may make it more or less efficient to first check whether or pointer is NULL before freeing?
The C standard guarantees that calling free(NULL) is harmless and has no effect. So, unless you believe that calling free() on a NULL pointer indicates that you've got a logic error elsewhere in your program, there's no reason to double-check that.
Don't check for nullness yourself. free already has to do that anyway and is guaranteed to do nothing when called with a null pointer. Simple as that.
The Open Group specification for free() states that:
If ptr is a null pointer, no action shall occur.
This implies that the implementation of free() will probably begin with something to the effect of:
if (ptr == NULL)
return;
which will have very little overhead. No guarantees, but there isn't much work the function could do before it makes that check, so checking on your own is unnecessary.
I was looking through the manuals on strcpy() and strcat(). Seems there's no way to evaluate the "success" of the function call. (ie return value will never be NULL), is that correct?
It's just assumed that if you follow the rules for the input of these functions that the output will be valid? Just wanted to make sure I wasn’t missing anything here…
These functions cannot fail in any well-defined way. They will either succeed, or things have gone horribly wrong (e.g. missing 0 char or too small output buffer), and anything could happen.
Because I don't think functions like that really have any way of knowing what "success" is. For instance, strcpy is really just memcpy. So as far as C is concerned, it is just taking data from one memory location and copying it to another. It doesn't know how the data is supposed to look, or be formatted in ways you expect. I guess the only real way you'd know if there is a success or not is if you end up getting a segfault or not.
These functions are guaranteed to work, provided that you're not invoking undefined behaviour. In particular, the memory that you're writing to needs to be allocated. There is really no way for them to fail except crashing your program.
Generally, because it can be hard to tell how many bytes will be written, use of these functions is discouraged. Use strncpy and strncat if you can.
Clang's scan-build reports quite a few dereference of null pointers in my project, however, I don't really see any unusual behavior (in 6 years of using it), ie:
Dereference of null pointer (loaded from variable chan)
char *tmp;
CList *chan = NULL;
/* This is weird because chan is set via do_lookup so why could it be NULL? */
chan = do_lookup(who, me, UNLINK);
if (chan)
tmp = do_lookup2(you,me,0);
prot(get_sec_var(chan->zsets));
^^^^
I know null derefs can cause crashes but is this really a big security concern as some people make it out to be? What should I do in this case?
It is Undefined Behavior to dereference a NULL pointer. It can show any behavior, it might crash or not but you MUST fix those!
The truth about Undefined Behavior is that it obeys Murphy's Law
"Anything that can go wrong will go wrong"
It makes no sense checking chan for NULL at one point:
if (chan)
tmp = do_lookup2(you,me,0); /* not evaluated if `chan` is NULL */
prot(get_sec_var(chan->zsets)); /* will be evaluated in any case */
... yet NOT checking it right at the next line.
Don't you have to execute both these statements within if branch?
Clang is warning you because you check for chan being NULL, and then you unconditionally dereference it in the next line anyway. This cannot possibly be correct. Either do_lookup cannot return NULL, then the check is useless and should be removed. Or it can, then the last line can cause undefined behaviour and MUST be fixed. Als is 100% correct: NULL pointer dereferences are undefined behaviour and are always a potential risk.
Probably you want to enclose your code in a block, so that all of it is governed by the check for NULL, and not just the next line.
You have to fix these as soon as possible. Or probably sooner. The Standard says that the NULL pointer is a pointer that points to "no valid memory location", so dereferencing it is undefined behaviour. It means that it may work, it may crash, and it may do strange things at other parts of your program, or maybe cause daemons to fly out of your nose.
Fix them. Now.
Here's how: put the dereference statement inside the if - doing otherwise (as you do: checking for NULL then dereferencing anyways) makes no sense.
if (pointer != NULL) {
something = pointer->field;
}
^^ this is good practice.
If you have never experienced problems with this code, it's probably because:
do_lookup(who, me, UNLINK);
always returns a valid pointer.
But what will it happen if this function changes? Or its parameters vary?
You definitely have to check for NULL pointers before dereferencing them.
if (chan)
prot(get_sec_var(chan->zsets));
If you are absolutely sure that neither do_lookup or its parameters will change in the future (and you can bet the safe execution of your program on it), and the cost of changing all the occurrences of similar functions is excessively high compared to the benefits that you would have in doing so, then:
you may decide to leave your code broken.
Many programmers did that in the past, and many more will do that in the future. Otherwise what would explain the existence of Windows ME?
If your program crashes because of a NULL pointer dereference, this can be classified as a Denial of Service (DoS).
If this program is used together with other programs (e.g. they invoke it), the security aspects now start to depend on what those other programs do when this one crashes. The overall effect can be the same DoS or something worse (exploitation, sensitive info leakage, and so on).
If your program does not crash because of a NULL pointer dereference and instead continues running while corrupting itself and possibly the OS and/or other programs within the same address space, you can have a whole spectrum of security issues.
Don't put on the line (or online) broken code, unless you can afford dealing with consequences of potential hacking.
Why is strlen() not checking for NULL?
if I do strlen(NULL), the program segmentation faults.
Trying to understand the rationale behind it (if any).
The rational behind it is simple -- how can you check the length of something that does not exist?
Also, unlike "managed languages" there is no expectations the run time system will handle invalid data or data structures correctly. (This type of issue is exactly why more "modern" languages are more popular for non-computation or less performant requiring applications).
A standard template in c would look like this
int someStrLen;
if (someStr != NULL) // or if (someStr)
someStrLen = strlen(someStr);
else
{
// handle error.
}
The portion of the language standard that defines the string handling library states that, unless specified otherwise for the specific function, any pointer arguments must have valid values.
The philosphy behind the design of the C standard library is that the programmer is ultimately in the best position to know whether a run-time check really needs to be performed. Back in the days when your total system memory was measured in kilobytes, the overhead of performing an unnecessary runtime check could be pretty painful. So the C standard library doesn't bother doing any of those checks; it assumes that the programmer has already done it if it's really necessary. If you know you will never pass a bad pointer value to strlen (such as, you're passing in a string literal, or a locally allocated array), then there's no need to clutter up the resulting binary with an unnecessary check against NULL.
The standard does not require it, so implementations just avoid a test and potentially an expensive jump.
A little macro to help your grief:
#define strlens(s) (s==NULL?0:strlen(s))
Three significant reasons:
The standard library and the C language are designed assuming that the programmer knows what he is doing, so a null pointer isn't treated as an edge case, but rather as a programmer's mistake that results in undefined behaviour;
It incurs runtime overhead - calling strlen thousands of times and always doing str != NULL is not reasonable unless the programmer is treated as a sissy;
It adds up to the code size - it could only be a few instructions, but if you adopt this principle and do it everywhere it can inflate your code significantly.
size_t strlen ( const char * str );
http://www.cplusplus.com/reference/clibrary/cstring/strlen/
Strlen takes a pointer to a character array as a parameter, null is not a valid argument to this function.