增强测试框架:有什么方法可以追溯SIGSEV?

时间:2018-11-10 13:07:20

标签: c++ linux gcc segmentation-fault boost-test

仅从Boost测试框架开始。使用Ubuntu + gcc(如果重要的话,可以在Windows上通过新事物运行)。当我运行测试时,得到以下信息:

unknown location(0): fatal error: in "PhraseListTest/everythingEqual8": signal: SIGSEGV, si_code: 0 (memory access violation at address: 0x00000080)
/mnt/c/projects/matching/matching-native/src/test/cpp/phrase_list_test.cpp(70): last checkpoint

*** 1 failure is detected in the test module "burningmime_matching_tests"

我将如何查找代码中发生的位置?消息指示测试中指向一行的唯一指示。有问题的行是:

BOOST_CHECK(matches(phraseList, bitset));

我相当确定问题出在matches()函数内部某处(可能有多个层次),但是...在哪里?


如果有人正在阅读此书,那么“重复”的答案都不起作用;显然,人们是在不考虑上下文的​​情况下关闭它的。

Boost测试框架用其自己的信号处理程序替换(并在执行每个测试之前执行)。这意味着在每个测试的开始,您都需要更换信号处理程序。我最终得到了这样的东西...

某些标头:

struct SignalToStacktraceScope
{
    SignalToStacktraceScope();
    ~SignalToStacktraceScope();
};

某些源文件:

#include <cstdio>
#include <csignal>
#include <iostream>
#include <boost/stacktrace.hpp>

    #if !NDEBUG && !BOOST_OS_WINDOWS
        typedef void (*FSignalHandler)(int signum);
        static void stacktraceHandler(int signum, const char* signame, FSignalHandler oldHandler)
        {
            fprintf(stderr, "\n\n===========================================\nReceived signal %s\n", signame);
            fflush(stderr); // flush before stack trace in case getting the stack trace itself produces another segfault
            std::cerr << boost::stacktrace::stacktrace();
            fprintf(stderr, "===========================================\n\n");
            fflush(stderr);

            // then raise the signal again to go back to the test framework
            signal(signum, oldHandler);
            raise(signum);
        }

        #define FOREACH_SIGNAL(F) \
            F(SIGSEGV) \
            F(SIGFPE) \
            F(SIGABRT) \
            F(SIGTERM)

        #define DEFINE_SIGNAL_WRAPPER(S) \
            static FSignalHandler oldHandler_##S = nullptr; \
            static void stacktraceHandler_##S(int signum) \
            { \
                stacktraceHandler(signum, #S, oldHandler_##S); \
            }
        FOREACH_SIGNAL(DEFINE_SIGNAL_WRAPPER)
        #undef DEFINE_SIGNAL_WRAPPER

        SignalToStacktraceScope::SignalToStacktraceScope()
        {
            #define HOOK_SIGNAL_WRAPPER(S) oldHandler_##S = signal(S, &stacktraceHandler_##S);
            FOREACH_SIGNAL(HOOK_SIGNAL_WRAPPER)
            #undef HOOK_SIGNAL_WRAPPER
        }

        SignalToStacktraceScope::~SignalToStacktraceScope()
        {
            #define UNHOOK_SIGNAL_WRAPPER(S) { signal(S, oldHandler_##S); oldHandler_##S = nullptr; }
            FOREACH_SIGNAL(UNHOOK_SIGNAL_WRAPPER)
            #undef UNHOOK_SIGNAL_WRAPPER
        }

        #undef FOREACH_SIGNAL
    #else
        SignalToStacktraceScope::SignalToStacktraceScope() { }
        SignalToStacktraceScope::~SignalToStacktraceScope() { }
    #endif

,然后在每个测试功能的顶部放置一个SignalToStacktraceScope(或包装BOOST_TEST_CASE宏以添加它)。在测试开始时执行一次操作将无济于事,因为Boost会不断替换它。

0 个答案:

没有答案