如何使用cmake来测试预期因异常而失败的进程? (例如,因clang的地址消毒剂而导致的失败)

时间:2015-11-13 13:10:41

标签: cmake clang automated-tests address-sanitizer

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

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

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

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

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

2 个答案:

答案 0 :(得分:3)

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>)

答案 1 :(得分: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()

这样可以尽快完成简单的通过/失败。我习惯于通过手工运行有问题的测试并检查输出来调查失败,在这种情况下,我得到正常的堆栈跟踪(并且abort退出的事实是有点慢是一个问题)。

(其他消毒杀菌剂有类似的选择,但我还没有调查过它们。)