Clang如何设法将其用未定义的行为编译到此计算机代码中
How does clang manage to compile this code with undefined behavior into this machine code?
这是来自此推文的代码变体,只是较短,不会造成任何损坏NOBS。我们有此代码:
typedef int (*Function)();
static Function DoSmth;
static int Return7()
{
return 7;
}
void NeverCalled()
{
DoSmth = Return7;
}
int main()
{
return DoSmth();
}
您看到NeverCalled()
从未在代码中调用,不是吗?这是编译器资源管理器在选择
-Os -std=c++11 -Wall
发射的代码是:
NeverCalled():
retq
main:
movl $7, %eax
retq
好像NeverCalled()
在DoSmth()
之前实际调用,并将DoSmth
功能指针设置为Return7()
函数。
如果功能指针分配从NeverCalled()
内部删除,如下所示:
void NeverCalled() {}
然后发出代码是:
NeverCalled():
retq
main:
ud2
后者是很期待的。编译器知道功能指针肯定是null,并且使用NULL函数指针调用函数是未定义的行为。
并不是真正的预期。以某种方式编译器决定将 Return7()
调用,尽管它不是直接调用的任何地方,并且功能指针分配是在函数内部未调用的。
是的,我知道允许使用C 标准的编译器面向不确定行为的编译器。它是如何做到的?
叮当声如何发射此特定的机器代码?
NeverCalled
是错误的指示。任何全局函数都可能被调用(例如,由不同翻译单元中的全局对象的构造函数)。
顺便说一句,这是该图可能会纳入没有UB的程序中的唯一方法。在这种情况下,main
返回7。
使NeverCalled
静态,main
将编译为空代码。
clang做的路径可能是;
的行-
DoSmth
是static
,因此初始化为零。由于它是一个指针(函数),具有初始化对NULL
指针(或nullptr
)
的效果 -
main()
做return DoSmth()
因此,DoSmth
不能为NULL
的原因,因为这会导致return DoSmth()
表现出不确定的行为; - 然后在编译单元中有关其他代码的原因,发现
NeverCalled()
中有一个分配DoSmth = Return7
; - 因为这是汇编单元中唯一的语句将
DoSmth
设置为非null,并且它认为DoSmth
不是null,所以Clang假设NeverCalled()
必须以某种方式称为;
>
- 由于上述推理的结果结论是
DoSmth
必须等于Return7
的地址; - 由于现在已经认为
DoSmth == Return7
,Clang将return DoSmth()
转换为return Return7()
; -
Return7()
在同一编译单元中
任何人的猜测是在内部如何做到这一点的细节。但是,代码优化的各种步骤可能导致推理链类似上述。
关键是您的代码(如它所处的代码)具有不确定的行为。未定义行为的一个可爱功能是,允许编译器(与要求不同),以理论您的代码实际上具有明确定义的行为。反过来,这允许编译器认为确保有明确定义的行为的某些代码被神奇地执行。
相关文章:
- 在Linux for Windows上编译C++代码时出错
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在程序中编写脚本来编写和编译代码
- 未定义的引用 .. 使用 OpenCV 编译 C++ 代码时,从命令行
- 在macos上编译代码的未解析符号
- 使用个人C++库编译代码时,与头文件一起使用时会中断
- 使用指针编译代码后,.cpp文件将变为随机字符
- VS Express 无法正确编译代码(?
- 如何在Ubuntu中使用Visual Studio代码编译C++代码
- 使用 Android NDK 使用 clang++ 编译C++代码时对"_Unwind_Resume"的未定义引用
- 无法使用两个包装不同下一层的ssl_stream编译代码
- 编译代码时"[Warning] extra tokens at end of"
- 无法编译代码,因为它已在 C++11 中弃用
- 如何在 Azure 应用服务中使用 cl.exe 编译 C++ 代码并生成可执行文件
- 如何调试编译 c++ 代码的 bazel?
- 为什么在使用转换构造函数编译代码时需要 const 复制构造函数?
- 编译 C++ 代码后尺寸较大
- 使用用 C++ 和 DDS 编写的 CMAKE 编译代码
- 编译代码时如何不制作二进制文件?
- 如何使用所有其他文件信息来编译代码,例如HAAR级联训练的权重的XML文件