如果 “运行时” 一个指针
p
使得 p == nullptr
被取消引用并且读取/写入其“指向对象”,会发生什么?
这是否意味着 100% 存在分段错误,因为内存地址 0 不能被读取/写入?
我之所以写“在运行时”,是因为我知道编译器在看到
p != nullptr
(使用*p
原始指针)时会假设p
,所以一些 *p
可能会因 UB 而消失,并且在运行时有效地不会取消引用 nullptr
,并且程序将继续穿过未定义行为的小巷。
例如,给定这个 TU,
int* bar();
int foo(int* i) {
return *i;
}
int work() {
int* b = bar();
int f = foo(b);
return b != nullptr ? 0 : (f + *bar());
}
编译器只需查看其返回值被
bar() =! nullptr
的主体取消引用即可假定 foo
,这只能在 bar() != nullptr
时完成。事实上,函数 work
被编译为
work():
sub rsp, 8
call bar()
xor eax, eax
add rsp, 8
ret
其中
bar()
返回的值实际上从未被解除引用,即使 *bar()
位于源代码中。
但是
foo
被编译为
foo(int*):
mov eax, DWORD PTR [rdi]
ret
因此,如果这个 TU 与另一个调用
foo(nullptr)
的 TU 链接,那么 mov
指令肯定会尝试从 rdi
中的地址读取,这就是 nullptr
编译到的地址,我猜是 0。
这是否意味着分段错误是不可避免的? (我并不是说我想避免 segv,恰恰相反,我只是想知道事情是否会变得如此糟糕,以至于没有 segv 并且程序继续运行,谁知道在哪里!)
(1)我知道取消引用空指针是否是UB的问题仍然没有解决,但这不是我之前的问题的重复。
空指针的运行时取消引用是否总是导致分段错误?
不,它只是具有未定义的行为 - 所以它是未定义将会发生什么。