I just saw in a code the following line :
#define ERR_FATAL( str, a, b, c ) {while(1) {*(unsigned int *)0 = 0xdeadbeef;} }
I know that 0xdeadbeef means error, but what putting this value mean when it's in address 0 ? What address 0 represents ?
I just saw in a code the following line :
#define ERR_FATAL( str, a, b, c ) {while(1) {*(unsigned int *)0 = 0xdeadbeef;} }
I know that 0xdeadbeef means error, but what putting this value mean when it's in address 0 ? What address 0 represents ?
The address 0x0 is recognized by the compiler as a NULL pointer and is going to be an implementation defined invalid memory address, on some systems is quite literally at the first addressable location in the system memory but on others it's just a placeholder in the code for some generic invalid memory address. From the point of view of the C code we don't know what address that will be, only that it's invalid to access it. Essentially what this code snippet is trying to do is to write to an "illegal" memory address, with the value 0xdeadbeef. The value itself is some hex that spells out "dead beef" hence indicating that the program is dead beef (ie. a problem), if you aren't a native english speaker I can see how this might not be so clear :). The idea is that this will trigger a segmentation fault or similar, with the intention of informing you that there is a problem by immediately terminating the program with no cleanup or other operations performed in the interim (the macro name ERR_FATAL
hints at that). Most operating systems don't give programs direct access to all the memory in the system and the code presumes that the operating system won't let you directly access memory that's located at address 0x0. Given that you tagged this question with the linux tag this is the behavior you will see (because linux will not allow an access to that memory address). Note that if you are working on something like an embedded system where there's no such guarantee then this could cause a bunch of problems as you might be overwriting something important.
Note that there's going to be better ways out there to report problems than this that don't depend on certain types of undefined behaviors causing certain side effects. Using things like assert is going to likely be a better choice. If you want to terminate the program using abort() is a better choice as it in the standard library and does exactly what you want. See the answer from ComicSansMS for more about why this is preferable.
Putting this value (or any value for that matter) in address 0 is supposed to terminate the program immediately.
A fatal error indicates an error situation so severe that the program cannot safely continue execution without risking further data corruption.
In particular, no pending cleanup operations are to be executed, as they could have an undesired effect. Think of flushing a buffer of corrupted data to the filesystem. Instead, the program is to terminate immediately and allow further examination of the situation via a core dump or an attached debugger.
Note that C already provides a standard library function for this purpose: abort(). Calling abort
would be preferable for this purpose for a number of reasons:
deadbeef
give some hints, it is still unnecessarily obscure. Also, note that the name of the macro will not be visible when looking at the disassembled code in a debugger.SIGSEGV
as a result, which is a signal indicating memory corruption. abort()
on the other hand causes SIGABRT
which indicates an abnormal program termination. Unless the reason for the fatal error was indeed a memory corruption, throwing SIGSEGV
in this case obscures why the program is failing and might be misleading to a developer trying to hunt down the error. This is particularly delicate when you think that the signal might not be caught by a debugger, but by an automated signal handler, which might then invoke unfitting code for error handling.Therefore, if the sole intent of the macro is to signal a fatal error (as the name suggests), calling abort
would be a better implementation.
Dereferencing an invalid pointer (which is what the above code is trying to do) results in Undefined Behavior. As such the system could do anything - it could crash, it could do nothing, or demons can fly out of your nose. This page is an excellent page on what every C programmer should know about Undefined Behavior.
Thus the above code is the wrong way to cause a crash. As a comenter pointed out, it would be better to call abort().