Skip to content
This repository was archived by the owner on Mar 22, 2023. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,11 @@ It's simply possible to print this content by running C++ code like this (from a
auto spans = span_runtimes_from_stream(stream);
std::cout << spans << std::endl;
```

## Debugging segfaults and other signals

Pmemstream test framework has support for handling signals and turning them into exceptions so that
applications do not crash. It is useful for Rapidcheck tests (it makes shrinking possible) and for ctest.

To turn this feature on, set env variable PMEMSTREAM_HANDLE_SIGNAL_FOR_DEBUG=1 and add test_register_sighandlers()
where the exceptions should be thrown (e.g. at the beginning of lambda passed to rc::check())
24 changes: 1 addition & 23 deletions tests/common/test_backtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,32 +155,10 @@ void test_dump_backtrace(void)
/*
* test_sighandler -- fatal signal handler
*/
void test_sighandler(int sig)
void test_backtrace_sighandler(int sig)
{
#ifndef PMEMSTREAM_USE_TSAN
printf("\nSignal: %s, backtrace:\n", strsignal(sig));
test_dump_backtrace();
printf("\n");
exit(128 + sig);
#endif
}

/*
* test_register_sighandlers -- register signal handlers for various fatal
* signals
*/
void test_register_sighandlers(void)
{
#ifndef PMEMSTREAM_USE_TSAN
signal(SIGSEGV, test_sighandler);
signal(SIGABRT, test_sighandler);
signal(SIGILL, test_sighandler);
signal(SIGFPE, test_sighandler);
signal(SIGINT, test_sighandler);
#ifndef _WIN32
signal(SIGALRM, test_sighandler);
signal(SIGQUIT, test_sighandler);
signal(SIGBUS, test_sighandler);
#endif
#endif
}
3 changes: 1 addition & 2 deletions tests/common/test_backtrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ extern "C" {
#endif

void test_dump_backtrace(void);
void test_sighandler(int sig);
void test_register_sighandlers(void);
void test_backtrace_sighandler(int sig);

#ifdef __cplusplus
}
Expand Down
31 changes: 31 additions & 0 deletions tests/common/test_sighandlers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: BSD-3-Clause
/* Copyright 2022, Intel Corporation */

#ifndef LIBPMEMSTREAM_TEST_SIGHANDLERS_H
#define LIBPMEMSTREAM_TEST_SIGHANDLERS_H

#include <signal.h>

#include "test_backtrace.h"

/*
* test_register_sighandlers -- register signal handlers for various fatal
* signals
*/
static inline void test_register_sighandlers(void (*sighandler)(int))
{
#ifndef PMEMSTREAM_USE_TSAN
signal(SIGSEGV, sighandler);
signal(SIGABRT, sighandler);
signal(SIGILL, sighandler);
signal(SIGFPE, sighandler);
signal(SIGINT, sighandler);
#ifndef _WIN32
signal(SIGALRM, sighandler);
signal(SIGQUIT, sighandler);
signal(SIGBUS, sighandler);
#endif
#endif
}

#endif // LIBPMEMSTREAM_TEST_SIGHANDLERS_H
51 changes: 51 additions & 0 deletions tests/common/test_sighandlers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: BSD-3-Clause
/* Copyright 2022, Intel Corporation */

#ifndef LIBPMEMSTREAM_TEST_SIGHANDLERS_HPP
#define LIBPMEMSTREAM_TEST_SIGHANDLERS_HPP

#include <csetjmp>
#include <cstring>
#include <stdexcept>
#include <string>

#include "test_sighandlers.h"

static inline sigjmp_buf &sigjmp_tls_buf()
{
static thread_local sigjmp_buf sigjmp;
return sigjmp;
}

static inline void test_handle_signal_for_debug(int sig)
{
if (sig == SIGKILL) {
test_backtrace_sighandler(sig);
} else {
siglongjmp(sigjmp_tls_buf(), sig);
}
}

static inline int test_register_signal_handler_for_debug()
{
int sig = sigsetjmp(sigjmp_tls_buf(), 0);
if (sig != 0) {
test_register_sighandlers(test_backtrace_sighandler);
throw std::runtime_error("Signal: " + std::string(strsignal(sig)) + " received!");
} else {
test_register_sighandlers(test_handle_signal_for_debug);
return 0;
}
}

static inline int test_register_sighandlers()
{
if (getenv("PMEMSTREAM_HANDLE_SIGNAL_FOR_DEBUG")) {
return test_register_signal_handler_for_debug();
} else {
test_register_sighandlers(test_backtrace_sighandler);
return 0;
}
}

#endif // LIBPMEMSTREAM_TEST_SIGHANDLERS_HPP
3 changes: 3 additions & 0 deletions tests/common/thread_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <thread>
#include <vector>

#include "test_sighandlers.hpp"

static inline std::string get_msg_from_exception_ptr(std::exception_ptr ptr)
{
try {
Expand Down Expand Up @@ -61,6 +63,7 @@ void parallel_exec(size_t threads_number, Function f)
threads.emplace_back(
[&](size_t id) {
try {
test_register_sighandlers();
f(id);
} catch (...) {
exception_ptrs[id] = std::current_exception();
Expand Down
13 changes: 12 additions & 1 deletion tests/common/thread_helpers_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ static constexpr size_t concurrency = 128;
int main()
{
struct test_config_type test_config;

return run_test(test_config, [] {
std::atomic<size_t> counter;
counter = 0;
Expand All @@ -36,5 +35,17 @@ int main()
syncthreads();
UT_ASSERTeq(counter.load(), concurrency * 2);
});

setenv("PMEMSTREAM_HANDLE_SIGNAL_FOR_DEBUG", "1", 1);
try {
parallel_exec(2, [&](size_t id) {
auto ptr = (char *)nullptr;
std::cout << *ptr;
UT_ASSERT_UNREACHABLE;
});
} catch (std::runtime_error &e) {
} catch (...) {
UT_ASSERT_UNREACHABLE;
}
});
}
4 changes: 2 additions & 2 deletions tests/common/unittest.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#define LIBPMEMSTREAM_UNITTEST_H

#include "libpmemstream.h"
#include "test_backtrace.h"
#include "test_sighandlers.h"

#include <errno.h>
#include <fcntl.h>
Expand Down Expand Up @@ -50,7 +50,7 @@ extern "C" {
#endif

/* XXX: refactor to use __start (https://stackoverflow.com/questions/15919356/c-program-start) */
#define START() test_register_sighandlers()
#define START() test_register_sighandlers(test_backtrace_sighandler)

/* XXX: provide function to get the actual metadata overhead */
#define STREAM_METADATA_SIZE (16UL * 1024)
Expand Down
1 change: 1 addition & 0 deletions tests/common/unittest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <type_traits>

#include "env_setter.hpp"
#include "test_sighandlers.hpp"
#include "valgrind_internal.h"

/* Execute only this many runs of rc_check tests under valgrind. It must be bigger than one because
Expand Down