// 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);
}
如果使用clang 5.0.0 +优化执行此代码,可能会导致崩溃。
我预期的三元运算符 boolValue ? "true" : "false" 看起来很安全,我假设:"不管 boolValue 中有什么垃圾值都没关系,因为它最终会评估为 true 或 false。"
我已经设置了一个Compiler Explorer example,显示了反汇编中的问题,这是完整的示例。注意:为了重现问题,我发现能够工作的组合是使用带有 -O2 优化的Clang 5.0.0。
#include <iostream>
#include <cstring>
// Simple struct, with an empty constructor that doesn't initialize anything
struct FStruct {
bool uninitializedBool;
__attribute__ ((noinline)) // Note: the constructor must be declared noinline to trigger the problem
FStruct() {};
};
char destBuffer[16];
// Small utility function that allocates and returns a string "true" or "false" depending on the value of the parameter
void Serialize(bool boolValue) {
// Determine which string to print depending if 'boolValue' is evaluated as true or false
const char* whichString = boolValue ? "true" : "false";
// Compute the length of the string we selected
size_t len = strlen(whichString);
memcpy(destBuffer, whichString, len);
}
int main()
{
// Locally construct an instance of our struct here on the stack. The bool member uninitializedBool is uninitialized.
FStruct structInstance;
// Output "true" or "false" to stdout
Serialize(structInstance.uninitializedBool);
return 0;
}
问题出在优化器上:它足够聪明,能够推断出字符串“true”和“false”的长度只相差1。因此,它并没有真正计算长度,而是使用布尔值本身的值,理论上应该是0或1,并且运行如下:
const size_t len = strlen(whichString); // original code
const size_t len = 5 - boolValue; // clang clever optimization
虽然这样做“聪明”,但我的问题是:C++标准是否允许编译器假设bool只能具有内部数字表示为'0'或'1'并以这种方式使用它?还是这是一种实现定义的情况,在这种情况下,实现假定所有的bool都只包含0或1,任何其他值都属于未定义行为领域?
static_cast<bool>())。但这并不是关于编译器选择的bool内部表示的要求。 - Euro Micelli