- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近在升级到 gcc 7.2 后遇到了一个奇怪的 C++ 崩溃,这可以使用以下简单的完整 c++11 程序来演示:
#include <cassert>
#include <cstdio>
struct MyObject
{
static MyObject & null_obj()
{ return *static_cast<MyObject*> (nullptr); }
operator bool()
{
return value != 0;
}
int value = 0;
};
int foo(MyObject & obj = MyObject::null_obj())
{
if (&obj != &MyObject::null_obj() && obj)
return 1;
return 0;
}
int main(int argc, char * argv[])
{
int result;
if (argc == 1)
{
result = foo();
}
else
{
MyObject obj;
obj.value = 1;
result = foo(obj);
}
printf("%d", result);
}
程序可以使用:g++ -std=c++11 -O2
当不带参数执行时 - 程序采用顶部分支并在使用 gcc6.1 或更高版本构建时崩溃。使用 gcc 5.5 构建时不会崩溃。
添加虚拟参数时 - 程序采用第二个分支并且不会按预期崩溃。在没有编译器优化的情况下构建时,该程序在任何情况下都不会崩溃。
崩溃似乎是在评估 foo() 中的条件时发生的。根据短路评估规则,当表达式的第一部分为假时,不应执行此代码路径中的第二个条件。
当使用较新的编译器时,例如 gcc 6.1 或更高版本,为 foo 生成的汇编程序如下所示:
foo(MyObject&):
mov edx, DWORD PTR [rdi]
xor eax, eax
test edx, edx
setne al
ret
崩溃的罪魁祸首是函数顶部的 mov 指令。gcc 5.5 的汇编程序看起来有点不同:
foo(MyObject&):
test rdi, rdi
je .L3
mov edx, DWORD PTR [rdi]
xor eax, eax
test edx, edx
setne al
ret
.L3:
xor eax, eax
ret
函数顶部的检查会跳过无效读取(如预期的那样)
有人可能会争辩说,以这种方式使用空引用是一种相当狡猾的做法,我很想同意,即使我不知道确切原因。然而,我在使用 boost::throws() 的 boost::error_code 类中遇到了相同的习语:docs , source .
我知道短路评估不适用于重载 || 的类型和 && 运算符,但这里显然不是这种情况。
这是UB吗? (用户错误)、编译器错误或其他原因?
更新:
我最初对 boost::error_code 的引用是针对版本 1.65.1。此实现首先引入到 boost 版本 1.40 中。从那以后,我发现在最新版本的 boost 中,该功能被修改大概是为了避免 UB,但奇怪的是它被允许这么长时间不受挑战。新函数使用非零整数常量:
namespace detail
{
// Misuse of the error_code object is turned into a noisy failure by
// poisoning the reference. This particular implementation doesn't
// produce warnings or errors from popular compilers, is very efficient
// (as determined by inspecting generated code), and does not suffer
// from order of initialization problems. In practice, it also seems
// cause user function error handling implementation errors to be detected
// very early in the development cycle.
inline system::error_code* throws()
{
// See github.com/boostorg/system/pull/12 by visigoth for why the return
// is poisoned with (1) rather than (0). A test, test_throws_usage(), has
// been added to error_code_test.cpp, and as visigoth mentioned it fails
// on clang for release builds with a return of 0 but works fine with (1).
return reinterpret_cast<system::error_code*>(1);
}
}
inline system::error_code& throws() { return *detail::throws(); }
最佳答案
这是未定义的行为:
{ return *static_cast<MyObject*> (nullptr); }
您不能将 nullptr
转换为引用。它还打破了任何有引用资料的人的所有假设。
注意:未定义的行为意味着任何事情都可能发生(包括崩溃或不崩溃)。
关于c++ - 中毒的空引用和短路表达式评估错误或 UB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49020065/
在回答中 Is it valid to create closure (lambda) objects using `std::bit_cast` in C++20? 表明程序可能具有未定义的行为“取
C++ 20 draft [concept.default.init] 没有精确定义 default_initializable template concept default_initializa
我担心这又是一个关于解释 ISO/IEC 14882(C++ 标准)的问题,但是: 正在从程序中调用 main,例如我从 main 递归调用 main() 至少不是实现定义的行为? (更新:我的意思是
想象一下: uint64_t x = *(uint64_t *)((unsigned char[8]){'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}); 我有 rea
考虑以下代码: int main() { typedef struct { int first; float second; } type; type whole = { 1, 2.0
这个问题已经有答案了: (Why) is using an uninitialized variable undefined behavior? (7 个回答) 已关闭 6 年前。 SO 上各种受人尊
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我最近在这样的代码中遇到了一个错误 class C { public: // foo return value depends on C's state // AND each cal
我最近在升级到 gcc 7.2 后遇到了一个奇怪的 C++ 崩溃,这可以使用以下简单的完整 c++11 程序来演示: #include #include struct MyObject {
所以,我一直在阅读 the C++ standard并来到 [defns.undefined](我正在阅读的 C++17 草案中的 3.27。请注意,虽然我在这里引用 C++17,但我在 other
这不是 Rvalue reference to lvalue reference 的拷贝 由于我是针对 C++17 提出这个问题的:由于悬空引用,以下是否仍会调用未定义的行为(当然,如果使用了引用)?
这个问题在这里已经有了答案: Arithmetic right shift gives bogus result? (2 个答案) 关闭 7 年前。 我想检查一些大的计算内存需求(存储在 unsig
坦率地说,这样的代码是否有效(除了缺乏必要的错误检查,为简单起见此处省略)? 通过互联网发送数据的代码: uint16_t i = htons(500); sendto(sockfd, &i, siz
我知道 C 和 C++ 以及不同的语言,但以下内容适用于两者。 TL/DR 我知道 i = i++; 是 UB,因为 i 在表达式中被修改了两次,而 C 和 C++ 禁止它。 引用资料: C99 6.
是否有可能满足以下条件的代码在每次运行相同输入时产生不同的输出? 虽然代码是单线程的它确实链接到一个线程安全的运行时库。 没有明确调用 rand() 或 time() 或它们的 friend 。 有一
这个问题在这里已经有了答案: is there issue will stringstream.str().c_str()? [duplicate] (3 个答案) 关闭 6 年前。 考虑以下代码,
根据 C++ 标准,如果对象本身不是 const,则可以从指针中丢弃 const 并写入对象。这样: const Type* object = new Type(); const_cast( ob
下面的代码会调用 UB 吗? int main(){ volatile int i = 0; volatile int* p = &i; int j = ++i * *p; } 最佳答案
这个问题在这里已经有了答案: will casting around sockaddr_storage and sockaddr_in break strict aliasing (2 个答案) 关
假设我们有来自 C++98 的遗留代码: bool expensiveCheck(); struct Foo; bool someFunc() { Foo *ptr = 0; if(
我是一名优秀的程序员,十分优秀!