为什么 __builtin_return_address 在 Clang 中崩溃?
Why does __builtin_return_address crash in Clang?
我有以下 C/C++ 代码,它使用 __builtin_return_address
:
#include <stdio.h>
#ifdef __clang__
# define optnone __attribute__((optnone))
#else
# define optnone __attribute__((optimize("O0")))
#endif
void *f() {
return __builtin_extract_return_addr(__builtin_return_address(2));
}
optnone void nest1() {
printf("%p\n", f());
}
optnone void nest2() {
nest1();
}
optnone void nest3() {
nest2();
}
optnone void nest4() {
nest3();
}
optnone int main() {
nest4();
}
GCC generates the following assembly 并且工作正常(不会崩溃):
f:
push rbp
mov rbp, rsp
mov rax, QWORD PTR [rbp+0]
pop rbp
mov rax, QWORD PTR [rax]
mov rax, QWORD PTR [rax+8]
ret
Clang 编译以下程序集,crashes:
f: # @f
push rbp
mov rbp, rsp
mov rax, qword ptr [rbp]
mov rax, qword ptr [rax]
mov rax, qword ptr [rax + 8]
pop rbp
ret
崩溃的原因是什么?
__builtin_return_address()
,正如您从程序集中看到的那样,尝试遍历堆栈上的帧指针链。但这仅在您上面的调用者实际设置堆栈帧并推送其帧指针时才有效。您可以看到 gcc 是这种情况(每个其他函数都以 push rbp / mov rbp, rsp
开头),但 clang 不是。您可以使用 -fno-omit-frame-pointer
强制 clang 这样做,然后您的代码再次运行。
我有以下 C/C++ 代码,它使用 __builtin_return_address
:
#include <stdio.h>
#ifdef __clang__
# define optnone __attribute__((optnone))
#else
# define optnone __attribute__((optimize("O0")))
#endif
void *f() {
return __builtin_extract_return_addr(__builtin_return_address(2));
}
optnone void nest1() {
printf("%p\n", f());
}
optnone void nest2() {
nest1();
}
optnone void nest3() {
nest2();
}
optnone void nest4() {
nest3();
}
optnone int main() {
nest4();
}
GCC generates the following assembly 并且工作正常(不会崩溃):
f:
push rbp
mov rbp, rsp
mov rax, QWORD PTR [rbp+0]
pop rbp
mov rax, QWORD PTR [rax]
mov rax, QWORD PTR [rax+8]
ret
Clang 编译以下程序集,crashes:
f: # @f
push rbp
mov rbp, rsp
mov rax, qword ptr [rbp]
mov rax, qword ptr [rax]
mov rax, qword ptr [rax + 8]
pop rbp
ret
崩溃的原因是什么?
__builtin_return_address()
,正如您从程序集中看到的那样,尝试遍历堆栈上的帧指针链。但这仅在您上面的调用者实际设置堆栈帧并推送其帧指针时才有效。您可以看到 gcc 是这种情况(每个其他函数都以 push rbp / mov rbp, rsp
开头),但 clang 不是。您可以使用 -fno-omit-frame-pointer
强制 clang 这样做,然后您的代码再次运行。