Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
中毒的空引用和短路表达式计算错误或UB? 我最近遇到了一个奇怪的C++崩溃,升级到GCC 7.2之后,可以用下面的简单的完整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); }_C++_Boost_Undefined Behavior - Fatal编程技术网

中毒的空引用和短路表达式计算错误或UB? 我最近遇到了一个奇怪的C++崩溃,升级到GCC 7.2之后,可以用下面的简单的完整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); }

中毒的空引用和短路表达式计算错误或UB? 我最近遇到了一个奇怪的C++崩溃,升级到GCC 7.2之后,可以用下面的简单的完整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); },c++,boost,undefined-behavior,C++,Boost,Undefined Behavior,崩溃的罪魁祸首是函数顶部的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 函数顶部的检查跳过无效读取(如预期) 有人可能会说,以这种方式使用空引用是一种相当狡猾的做法,我很想同意,尽管我不知道确切的

崩溃的罪魁祸首是函数顶部的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_代码类中遇到了相同的习惯用法

我知道短路评估不适用于过载| |和&&运算符的类型,但这里显然不是这种情况

这是UB吗?(用户错误)、编译器错误或其他什么

更新

我最初对boost::error_代码的引用是针对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(); }
名称空间详细信息
{
//错误代码对象的误用会由
//中毒引用。此特定实现不会
//从流行的编译器生成警告或错误,非常有效
//(通过检查生成的代码确定),并且不会受到影响
//从初始化问题的顺序来看。在实践中,似乎
//导致检测到用户函数错误处理实现错误
//在开发周期的早期。
内联系统::错误_代码*抛出()
{
//查看visigoth的github.com/boostorg/system/pull/12了解返回的原因
//被(1)而不是(0)毒害。测试test_throws_usage()具有
//已添加到error_code_test.cpp,正如visigoth所述,它失败了
//对于返回0的发布版本,在clang上运行,但在(1)下运行良好。
返回重新解释(1);
}
}
内联系统::错误_代码和throws(){return*详细信息::throws();}

短路不包括在内。您调用了
null\u obj()
,这是一个取消引用空指针的函数。因此,您的程序具有未定义的行为,句号

此规则不取决于您以后是否尝试从所述断开的值中读取某些数据


如果Boost做到了这一点,那么Boost就有一个bug。虽然Boost不太可能做到这一点。

短路不包括在内。您调用了
null\u obj()
,这是一个取消引用空指针的函数。因此,您的程序具有未定义的行为,句号

此规则不取决于您以后是否尝试从所述断开的值中读取某些数据


如果Boost做到了这一点,那么Boost就有一个bug。尽管Boost不太可能做到这一点。

这是未定义的行为:

    { return *static_cast<MyObject*>    (nullptr); }
{return*static_cast(nullptr);}
不允许将
nullptr
转换为引用。它还打破了任何有参考资料的人的所有假设


注意:未定义的行为意味着任何事情都可能发生(包括崩溃或不崩溃)。

这是未定义的行为:

    { return *static_cast<MyObject*>    (nullptr); }
{return*static_cast(nullptr);}
不允许将
nullptr
转换为引用。它还打破了任何有参考资料的人的所有假设


注意:未定义的行为意味着任何事情都可能发生(包括崩溃或未崩溃)。

取消引用空指针是未定义的行为。不能将引用设置为取消引用的null。我怀疑,经过优化后,较旧的编译器知道输入引用与null进行比较,因此生成
test rdi,rdi
指令,而较新的编译器知道比较是伪造的或完全优化了,因此它不会生成相同的
test
。尝试更改
null\u obj()
以返回对真实
MyObject
对象的引用,并查看编译器如何反应当然有效对象按预期工作。我基本上不明白boost是如何做到这一点的,他们使用完全相同的代码。信任您的编译器消息。@rtz boost源代码的哪一行?我看不出来。(没有NULL,nullptr类似于static_cast?)刚刚更新了到最新boost源代码/文档的断开链接引用NULL指针是未定义的行为。不能将引用设置为取消引用的null。我怀疑,经过优化后,较旧的编译器知道输入引用与null进行比较,因此生成
test rdi,rdi
指令,而较新的编译器知道比较是伪造的或完全优化了,因此它不会生成相同的
test
。尝试更改
null\u obj()
以返回对真实
MyObject
对象的引用,并查看编译器如何反应当然有效对象按预期工作。我基本上不明白boost是如何做到这一点的,他们使用完全相同的代码。信任您的编译器消息。@rtz boost源代码的哪一行?我看不出来。(没有NULL,nullptr类似static_cast?)刚刚更新了最新boost源代码/文档的断开链接如果您对boost代码有单独的问题,请继续提问(提供您声明的证据),但是boost取消引用NULL指针的可能性非常小。当然,bug确实潜入到任何项目中。可以说,取消对nullptr的引用不是UB。但毫无疑问,用这样一个操作的结果初始化一个引用是UB。@M.M:不,不能说解引用nullptr不是UB。该标准明确规定了这一点。而且,这样的一个操作符