当 UBSAN (-fsanitize=undefined) 发现未定义的行为时触发测试失败

Trigger a test failure when UBSAN (-fsanitize=undefined) finds undefined behaviour

提问人:Steve Lorimer 提问时间:5/12/2021 更新时间:12/2/2021 访问量:985

问:

我这里有一个小的单元测试,它有未定义的行为。

源代码:

#include <gtest/gtest.h>

TEST(test, test)
{
    int k = 0x7fffffff;
    k += 1; // cause integer overflow
}

GTEST_API_ int main(int argc, char** argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

我在我的CMakeLists.txt中启用UBSAN:

cmake_minimum_required (VERSION 3.12)
project(ub CXX)

find_package(GTest REQUIRED)

add_executable        (ub_test ub_test.cpp)
target_link_libraries (ub_test GTest::GTest)
target_compile_options(ub_test PRIVATE -fsanitize=undefined)
target_link_options   (ub_test PRIVATE -fsanitize=undefined)

UBSAN 正确识别未定义的行为:

/home/steve/src/ub/ub_test.cpp:6:7: runtime error: signed integer overflow:
2147483647 + 1 cannot be represented in type 'int'

但是,我的测试仍然通过。

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from test
[ RUN      ] test.test
/home/steve/src/ub/ub_test.cpp:6:7: runtime error: signed integer overflow:
2147483647 + 1 cannot be represented in type 'int'
[       OK ] test.test (0 ms)
[----------] 1 test from test (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

当 UBSAN 发现问题时,是否可以触发测试失败(抛出异常、退出 1 等)?

C++ 乌桑

评论

0赞 463035818_is_not_an_ai 5/12/2021
也许你可以重定向 stdout(或者是 stderr?)并断言这一点。

答:

5赞 mediocrevegetable1 5/12/2021 #1

根据文档

  • -fsanitize=...:打印详细的错误报告并继续执行(默认);

  • -fno-sanitize-recover=...:打印详细的错误报告并退出程序;

  • -fsanitize-trap=...:执行陷阱指令(不需要 UBSan 运行时支持)。

请注意,/ 选项不会启用相应的消毒剂,一般需要附有合适的标志。traprecover-fsanitize=

似乎当你使用完全相同的事情时,就会发生你所说的事情。它会注意到未定义的行为并报告它,但会继续执行。因此,附加一个应该退出程序。-fsanitize=-fno-sanitize-recover=all

评论

0赞 Steve Lorimer 5/12/2021
哈 - RTFM!谢谢!看起来获得此消息的正确方法是添加(即:除了-fno-sanitize-recover=all-fsantize=undefined)
1赞 mediocrevegetable1 5/12/2021
@SteveLorimer啊,我明白了,可能是由于“请注意,陷阱/恢复选项没有启用相应的消毒剂,通常需要附有合适的 -fsanitize= 标志。我将编辑我的帖子来解决这个问题。
4赞 Alexey Chernyshov 12/2/2021 #2

你可以试试环境变量。UBSAN_OPTIONS="halt_on_error=1"

UBSAN_OPTIONS="halt_on_error=1" cmake --build cmake-build-UBSAN --target test