Reputation: 9803
In the following piece of code, what does *(int32 *) 0 = 0;
mean?
void
function (void)
{
...
for (;;)
*(int32 *) 0 = 0; /* What does this line do? */
}
A few notes:
int32
is typedef
'ed but you shouldn't care too much about it.Upvotes: 37
Views: 4972
Reputation: 6947
The original IBM PC stored the interrupt vector table in the lowest 1 KiB of memory. Hence actually writing a 32-bit value to the address 0 on such an architecture would overwrite the address for INT 00h
. INT 00h looks unused in the PC.
On basically anything modern (meaning in x86/x86-64 parlace anything running in protected or long mode), it will trigger a segmentation fault unless you are in ring 0 (kernel mode) because you are stepping outside of your process' allowed address dereference range.
As the dereference is undefined behavior (as already stated), a segmentation fault is a perfectly acceptable way to handle that situation. If you know that on the target architecture a zero address dereference causes a segmentation fault, it's seems to be a pretty sure way to get the application to crash. If exit()
returns, that's probably what you want to do, since something just went horribly wrong. That the code is from a particular compiler's runtime means whoever wrote it can take advantage of knowledge of the internal workings of the compiler and runtime, as well as tailor it to the specific target architecture's behavior.
Upvotes: 3
Reputation: 10931
It could be that the compiler doesn't know exit()
doesn't return, but it does know this construct does not return.
Upvotes: 1
Reputation: 223254
Since the OP states the code was written by experienced compiler engineers, it is possible this is the intent of the code:
*(int32 *) 0 = 0;
is recognized by this specific C implementation as code that causes behavior not defined by the C standard and known to this implementation to be illegal.for (;;)
additionally indicates that this code is never exited.This sort of reasoning is possible only if you have specific knowledge of the internal operation of a C implementation. It is the sort of thing a compiler engineer might include in special headers for a C implementation, perhaps to mark that certain code (such as code after an abort
call) is never reached. It should never be used in normal programming.
1 For example, consider this code:
if (a)
for (;;)
*(int 32 *) 0 = 0;
else
foo();
The compiler can recognize that the then-clause is permitted to have any behavior. Therefore, the compiler is free to choose what behavior it has. For simplicity, it chooses it to have the same behavior as foo();
. Then the code becomes:
if (a)
foo();
else
foo();
and can be further simplified to:
foo();
Upvotes: 27
Reputation: 1277
The code is doing the following:
for (;;) // while(true)
*(int32 *) 0 = 0; // Treat 0 as an address, de-reference the 0 address and try and store 0 into it.
This should segfault, null pointer de-reference.
EDIT
Compiled and ran for further information:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(void){
*(int32_t *) 0 = 0;
printf("done\n");
return 0;
}
gcc -g null.c; ./a.out
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cd in main () at null.c:7
7 *(int32_t *) 0 = 0;
Upvotes: 33
Reputation: 4085
In fact that this code seg-faulting doesn't explain why it's exists =)
I think that's from runtime of some MCU.. and reason it is there because if program execution will get to this point such instruction will either initiate software reset for an MCU, so program will be restarted (which is common practice in embedded development) OR if MCU configured with hardware watchdog, force MCU restart because of hardware watchdog and never ending loop.
Main goal of such constructions to invoke an interrupt which can be handled either by OS or by hardware for initiate certain actions.
Knowing that its x86 it will depend on a CPU mode... in Real Mode nothing will really happened instantly if there is no watchdog, at address 0 there is an address of 'divide by 0' handler, so if it's some old MS-DOS or embedded x86 runtime it will change an address of the 'Divide by 0' handler to 0, so as soon as it happens and this interrupt is not masked CPU will jump to location 0:0 and probably will just restart because of illegal instruction.. if it's protected or VM x86 code then it's a way to notify OS or any other supervisor that there is a problem in runtime and software should be 'killed' externally.
Upvotes: 21
Reputation: 166
Mike's comment is pretty well correct: it's storing the VALUE zero at the ADDRESS 0.
Which will be a crash on most machines.
Upvotes: 3
Reputation: 7868
for(;;)
is equivalent to while(1)
,
*(int32 *) 0 = 0;
writes 0 to a dereferenced null pointer, which is expected to cause a crash, but actually won't at all times on certain compilers: Crashing threads with *(int*)NULL = 1; problematic?
Upvotes: 6
Reputation: 6608
It's an infinite loop of undefined behavior (dereferencing a null pointer). It's likely to crash with a segfault on *n*x or Access Violation on Windows.
Upvotes: 3