In the following piece of code, what does *(int32 *) 0 = 0;
mean?
在下面的代码中,*(int32 *)0 = 0;意思?
void
function (void)
{
...
for (;;)
*(int32 *) 0 = 0; /* What does this line do? */
}
A few notes:
几点说明:
- The code seems to not be reachable, as there is an exit statement before that particular piece of code.
- 代码似乎无法访问,因为在该特定代码段之前有一个退出语句。
-
int32
istypedef
'ed but you shouldn't care too much about it. - int32是typedef'ed但你不应该太在意它。
- This piece of code is from a language's runtime in a compiler, for anyone interested.
- 对于感兴趣的人来说,这段代码来自编译器中语言的运行时。
8 个解决方案
#1
32
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.
这应该是segfault,null指针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
gcc -g null.c; ./a.out
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cd in main () at null.c:7
7 *(int32_t *) 0 = 0;
#2
26
Since the OP states the code was written by experienced compiler engineers, it is possible this is the intent of the code:
由于OP声明代码是由经验丰富的编译工程师编写的,因此这可能是代码的意图:
-
*(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. - *(int32 *)0 = 0;被这个特定的C实现识别为导致C标准未定义且该实现已知的行为是非法的代码。
- The
for (;;)
additionally indicates that this code is never exited. - for(;;)还表示永远不会退出此代码。
- The compiler engineers know that the optimizer will recognize this code and deduce that it may be “optimized away”, because any program that reaches this code is permitted to have any behavior, so the optimizer may choose to give it the behavior as if the code is never reached.1
- 编译器工程师知道优化器将识别此代码并推断它可能“被优化掉”,因为任何到达此代码的程序都被允许具有任何行为,因此优化器可以选择给它行为,就像代码一样永远不会到达
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.
只有具备C实现的内部操作的特定知识,才有可能进行这种推理。这是编译器工程师可能包含在C实现的特殊头文件中的东西,可能是为了标记某些代码(例如中止调用后的代码)永远不会到达。它永远不应该用于普通编程。
1 For example, consider this code:
1例如,请考虑以下代码:
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:
编译器可以识别允许then子句具有任何行为。因此,编译器可以*选择它具有的行为。为简单起见,它选择它与foo();具有相同的行为。然后代码变成:
if (a)
foo();
else
foo();
and can be further simplified to:
并可进一步简化为:
foo();
#3
22
In fact that this code seg-faulting doesn't explain why it's exists =)
事实上,这段代码seg-faulting并没有解释为什么它存在=)
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.
我认为这是来自某些MCU的运行时间...并且它的存在是因为如果程序执行到了这一点,这样的指令将启动MCU的软件复位,因此程序将重新启动(这是嵌入式开发中的常见做法)或者如果MCU配置了硬件看门狗,则由于硬件看门狗和永不结束的循环而强制MCU重启。
Main goal of such constructions to invoke an interrupt which can be handled either by OS or by hardware for initiate certain actions.
这种结构的主要目标是调用可由OS或硬件处理以启动某些操作的中断。
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.
知道它的x86它将取决于CPU模式......在实模式下,如果没有看门狗就不会立即发生任何事情,在地址0处有一个“除以0”处理程序的地址,所以如果它是一些旧的MS- DOS或嵌入式x86运行时它会将'Divide by 0'处理程序的地址更改为0,因此只要它发生并且此中断未被屏蔽,CPU将跳转到位置0:0并且可能因非法指令而重新启动..如果它受到保护或VM x86代码,那么它是一种通知操作系统或任何其他主管在运行时出现问题的方法,软件应该在外部被“杀死”。
#4
6
for(;;)
is equivalent to while(1)
,
for(;;)相当于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?
*(int32 *)0 = 0;将0写入一个取消引用的空指针,这可能会导致崩溃,但实际上不会在某些编译器上发生崩溃:崩溃线程带*(int *)NULL = 1;有问题?
#5
3
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.
这是一个未定义行为的无限循环(取消引用空指针)。它可能会因为* n * x上的段错误或Windows上的访问冲突而崩溃。
#6
3
Mike's comment is pretty well correct: it's storing the VALUE zero at the ADDRESS 0.
迈克的评论非常正确:它在地址0处存储了VALUE零。
Which will be a crash on most machines.
这将是大多数机器上的崩溃。
#7
3
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.
最初的IBM PC将中断向量表存储在最低1 KiB的内存中。因此,实际上在这种架构上将32位值写入地址0将覆盖INT 00h的地址。 INT 00h在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.
在基本上任何现代的东西(意思是在x86 / x86-64 parlace任何在受保护或长模式下运行),它将触发分段错误,除非你在第0环(内核模式),因为你正在进入你的进程之外'允许的地址取消引用范围。
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.
由于取消引用是未定义的行为(如前所述),因此分段错误是处理该情况的完全可接受的方式。如果您知道在目标体系结构上零地址解引用会导致分段错误,那么这似乎是让应用程序崩溃的一种非常可靠的方法。如果exit()返回,那可能就是你想要做的事情,因为有些事情发生了可怕的错误。代码来自特定编译器的运行时意味着编写它的人可以利用编译器和运行时的内部工作知识,并根据特定目标体系结构的行为进行定制。
#8
1
It could be that the compiler doesn't know exit()
doesn't return, but it does know this construct does not return.
可能是编译器不知道exit()没有返回,但它确实知道这个构造不会返回。
#1
32
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.
这应该是segfault,null指针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
gcc -g null.c; ./a.out
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cd in main () at null.c:7
7 *(int32_t *) 0 = 0;
#2
26
Since the OP states the code was written by experienced compiler engineers, it is possible this is the intent of the code:
由于OP声明代码是由经验丰富的编译工程师编写的,因此这可能是代码的意图:
-
*(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. - *(int32 *)0 = 0;被这个特定的C实现识别为导致C标准未定义且该实现已知的行为是非法的代码。
- The
for (;;)
additionally indicates that this code is never exited. - for(;;)还表示永远不会退出此代码。
- The compiler engineers know that the optimizer will recognize this code and deduce that it may be “optimized away”, because any program that reaches this code is permitted to have any behavior, so the optimizer may choose to give it the behavior as if the code is never reached.1
- 编译器工程师知道优化器将识别此代码并推断它可能“被优化掉”,因为任何到达此代码的程序都被允许具有任何行为,因此优化器可以选择给它行为,就像代码一样永远不会到达
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.
只有具备C实现的内部操作的特定知识,才有可能进行这种推理。这是编译器工程师可能包含在C实现的特殊头文件中的东西,可能是为了标记某些代码(例如中止调用后的代码)永远不会到达。它永远不应该用于普通编程。
1 For example, consider this code:
1例如,请考虑以下代码:
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:
编译器可以识别允许then子句具有任何行为。因此,编译器可以*选择它具有的行为。为简单起见,它选择它与foo();具有相同的行为。然后代码变成:
if (a)
foo();
else
foo();
and can be further simplified to:
并可进一步简化为:
foo();
#3
22
In fact that this code seg-faulting doesn't explain why it's exists =)
事实上,这段代码seg-faulting并没有解释为什么它存在=)
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.
我认为这是来自某些MCU的运行时间...并且它的存在是因为如果程序执行到了这一点,这样的指令将启动MCU的软件复位,因此程序将重新启动(这是嵌入式开发中的常见做法)或者如果MCU配置了硬件看门狗,则由于硬件看门狗和永不结束的循环而强制MCU重启。
Main goal of such constructions to invoke an interrupt which can be handled either by OS or by hardware for initiate certain actions.
这种结构的主要目标是调用可由OS或硬件处理以启动某些操作的中断。
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.
知道它的x86它将取决于CPU模式......在实模式下,如果没有看门狗就不会立即发生任何事情,在地址0处有一个“除以0”处理程序的地址,所以如果它是一些旧的MS- DOS或嵌入式x86运行时它会将'Divide by 0'处理程序的地址更改为0,因此只要它发生并且此中断未被屏蔽,CPU将跳转到位置0:0并且可能因非法指令而重新启动..如果它受到保护或VM x86代码,那么它是一种通知操作系统或任何其他主管在运行时出现问题的方法,软件应该在外部被“杀死”。
#4
6
for(;;)
is equivalent to while(1)
,
for(;;)相当于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?
*(int32 *)0 = 0;将0写入一个取消引用的空指针,这可能会导致崩溃,但实际上不会在某些编译器上发生崩溃:崩溃线程带*(int *)NULL = 1;有问题?
#5
3
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.
这是一个未定义行为的无限循环(取消引用空指针)。它可能会因为* n * x上的段错误或Windows上的访问冲突而崩溃。
#6
3
Mike's comment is pretty well correct: it's storing the VALUE zero at the ADDRESS 0.
迈克的评论非常正确:它在地址0处存储了VALUE零。
Which will be a crash on most machines.
这将是大多数机器上的崩溃。
#7
3
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.
最初的IBM PC将中断向量表存储在最低1 KiB的内存中。因此,实际上在这种架构上将32位值写入地址0将覆盖INT 00h的地址。 INT 00h在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.
在基本上任何现代的东西(意思是在x86 / x86-64 parlace任何在受保护或长模式下运行),它将触发分段错误,除非你在第0环(内核模式),因为你正在进入你的进程之外'允许的地址取消引用范围。
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.
由于取消引用是未定义的行为(如前所述),因此分段错误是处理该情况的完全可接受的方式。如果您知道在目标体系结构上零地址解引用会导致分段错误,那么这似乎是让应用程序崩溃的一种非常可靠的方法。如果exit()返回,那可能就是你想要做的事情,因为有些事情发生了可怕的错误。代码来自特定编译器的运行时意味着编写它的人可以利用编译器和运行时的内部工作知识,并根据特定目标体系结构的行为进行定制。
#8
1
It could be that the compiler doesn't know exit()
doesn't return, but it does know this construct does not return.
可能是编译器不知道exit()没有返回,但它确实知道这个构造不会返回。