4

我有一些测试可以测试 clang 的地址清理程序是否捕获特定错误。(我想确保我对它可以捕获的错误类型的理解是正确的,并且未来的版本会继续捕获我期望它们捕获的错误类型。)这意味着我有几个测试失败了OTHER_FAULT,这似乎是 clang 的运行时报告错误的固定方式。

我已经为这些测试设置了WILL_FAIL标志TRUE,但这似乎只是检查成功、无异常失败的返回值。如果进程因异常而终止,cmake 仍将其归类为失败。

我还尝试使用PASS_REGULAR_EXPRESSION来观察发生此错误时打印出的区别消息,但同样,如果测试以异常终止,cmake 似乎将测试归类为失败。

我能做些什么来解决这个问题吗?

(特定于clang的答案也是一种选择!-但我怀疑这将是我最后一次需要测试这样的东西,所以如果可能的话,我更愿意知道如何使用cmake进行测试)

4

2 回答 2

5

CTest 只为测试程序的结果提供基本的、常用的解释器。为了实现其他解释器,您可以编写简单的程序/脚本,它包装测试并根据需要解释其结果。例如 C 程序(用于 Linux):

test_that_crash.c

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

int main(int argc, char** argv)
{
    pid_t pid = fork();
    if(pid == -1)
    {
        // fork fails
        return 1;
    }
    else if(pid)
    {
        // Parent - wait child and interpret its result
        int status = 0;
        wait(&status);
        if(WIFSIGNALED(status)) return 0; // Signal-terminated means success
        else return 1;
    }
    else
    {
        // Child - execute wrapped command
        execvp(argv[1], argv + 1);
        exit(1);
    }
}

该程序可以在 CMake 中使用,如下所示:

CMakeLists.txt

# Compile our wrapper
add_executable(test_that_crash test_that_crash.c)
# Similar to add_test(name command), but test is assumed successfull only if it is crashed(signalled)
macro(add_test_crashed name command)
    # Use generic flow of add_test() command for automatically recognize our executable target
    add_test(NAME ${name} COMMAND test_that_crash ${command} ${ARGN})
endmacro(add_test_crashed)
# ...

# Add some test, which should crash
add_test_crashed(clang.crash.1 <clang-executable> <clang-args>)
于 2015-11-13T14:13:49.980 回答
0

还有一个特定于clang的解决方案:使用ASAN_OPTIONS环境变量配置其退出方式。(请参阅https://github.com/google/sanitizers/wiki/AddressSanitizerFlags。)为此,请将ASAN_OPTIONS环境变量设置为abort_on_error=0. 当地址清理程序检测到问题时,该进程将执行_exit(1)而不是(可能)abort(),因此看起来已经干净地终止了。然后,您可以使用 cmake 的WILL_FAIL机制来获取它。(目前还不清楚为什么 OS X 和 Linux 在这方面有所不同 - 但你去吧。)

作为奖励,测试失败的速度要快得多。

(通过 cmake 运行时可以缩短周转​​时间的另一个方便的选项是设置ASAN_SYMBOLIZER_PATH为空值,这会停止符号化堆栈跟踪的地址清理程序。符号化需要一点时间,但是在通过 cmake 运行时这样做没有意义,因为您可以'看不到输出。)

我没有手动执行此操作,而是编写了一个 Python 脚本,在 OS X 上适当地设置环境(在 Linux 上什么都不做),并调用测试。然后,我按照 Tsyvarev 的回答,使用宏添加每个 asan 测试。

macro(add_asan_test basename)
  add_executable(${basename} ${basename}.c)
  add_test(NAME test/${basename} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/wrap_clang_sanitizer_test.py -a $<TARGET_FILE:${basename}>)
  set_tests_properties(test/${basename} PROPERTIES WILL_FAIL TRUE)
endmacro()

这会尽快给出简单的通过/失败。我习惯于通过手动从 shell 运行有问题的测试并检查输出来调查故障,在这种情况下,我可以正常获取堆栈跟踪(并且退出的事实abort有点慢不是问题)。

(其他消毒剂也有类似的选择,但我没有调查过。)

于 2015-11-17T13:13:20.507 回答