我知道C++ 中的"未定义行为"几乎可以让编译器做任何想做的事情.但是,我遇到了让我感到惊讶的崩溃,因为我认为代码足够安全.
在这种情况下,真正的问题仅发生在使用特定编译器的特定平台上,并且仅在启用了优化时才发生.
我尝试了几件事来重现问题并将其简化到最大程度.这是一个名为的函数的摘录Serialize,它将获取bool参数,并将字符串true或复制false到现有的目标缓冲区.
如果bool参数是未初始化的值,那么这个函数是否会在代码审查中,没有办法告诉它实际上可能会崩溃?
// Zero-filled global buffer of 16 characters
char destBuffer[16];
void Serialize(bool boolValue) {
// Determine which string to print based on boolValue
const char* whichString = boolValue ? "true" : "false";
// Compute the length of the string we selected
const size_t len = strlen(whichString);
// Copy string into destination buffer, which is zero-filled (thus already null-terminated)
memcpy(destBuffer, whichString, len);
}
Run Code Online (Sandbox Code Playgroud)
如果使用clang 5.0.0 +优化执行此代码,它将/可能崩溃.
boolValue ? "true" …
考虑这段代码:
#include <cstring>
template<typename T>
struct DefaultMsgImpl
{
DefaultMsgImpl() { memset(this, 0, sizeof(T)); }
};
struct Msg : DefaultMsgImpl<Msg>
{
int num;
};
int f()
{
Msg msg{.num = 66};
return msg.num;
}
Run Code Online (Sandbox Code Playgroud)
对于 GCC 13(及更早版本),f()返回 0,但对于所有其他编译器(MSVC、Clang、ICC、ICX...),f()返回 66。
上面的代码是有效的C++(在这种情况下,GCC 似乎对其进行了错误编译),还是未定义的行为(例如,因为 memset 在 的生命周期开始Msg之前接触了内存)?T如果是 UB,我希望得到引用 C++ 标准的答案。
演示: https: //godbolt.org/z/1qf9dv8cG
问题的启发来自处理大型数据二进制文件
链接到对象
程序(1)创建一个内存映射文件并向其中写入一些对象(C++标准定义),关闭文件并退出。
程序(2)将上述文件映射到内存中并尝试通过reinterpret_cast.
根据标准,这是否合法,因为对象表示没有更改并且对象仍然存在于文件中?
如果在两个进程之间尝试这样做,而不是使用文件,而是使用共享进程内存,这合法吗?
注意 - 这个问题与存储或共享本地虚拟地址无关,因为这显然是一件坏事。