Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Avoid recursion when using sentry_reinstall_backend #548

Merged
merged 6 commits into from
Jun 18, 2021
Merged
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
4 changes: 4 additions & 0 deletions examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ main(int argc, char **argv)
}
}

if (has_arg(argc, argv, "reinstall")) {
sentry_reinstall_backend();
}

if (has_arg(argc, argv, "sleep")) {
sleep_s(10);
}
Expand Down
30 changes: 30 additions & 0 deletions src/backends/sentry_backend_crashpad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ extern "C" {
#ifdef SENTRY_PLATFORM_LINUX
# define SIGNAL_STACK_SIZE 65536
static stack_t g_signal_stack;

# include "util/posix/signals.h"

// This list was taken from crashpad's util/posix/signals.cc file
// and is used to know which signals we need to reset to default
// when shutting down the backend
constexpr int g_CrashSignals[] = {
SIGABRT,
SIGBUS,
SIGFPE,
SIGILL,
SIGQUIT,
SIGSEGV,
SIGSYS,
SIGTRAP,
# if defined(SIGEMT)
SIGEMT,
# endif // defined(SIGEMT)
SIGXCPU,
SIGXFSZ,
};
#endif

typedef struct {
Expand Down Expand Up @@ -281,6 +302,15 @@ sentry__crashpad_backend_startup(
static void
sentry__crashpad_backend_shutdown(sentry_backend_t *backend)
{
#ifdef SENTRY_PLATFORM_LINUX
// restore signal handlers to their default state
for (const auto signal : g_CrashSignals) {
if (crashpad::Signals::IsCrashSignal(signal)) {
crashpad::Signals::InstallDefaultHandler(signal);
}
}
#endif

crashpad_state_t *data = (crashpad_state_t *)backend->data;
delete data->db;
data->db = nullptr;
Expand Down
1 change: 1 addition & 0 deletions src/backends/sentry_backend_inproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ shutdown_inproc_backend(sentry_backend_t *UNUSED(backend))
sigaltstack(&g_signal_stack, 0);
sentry_free(g_signal_stack.ss_sp);
g_signal_stack.ss_sp = NULL;
reset_signal_handlers();
}

#elif defined SENTRY_PLATFORM_WINDOWS
Expand Down
2 changes: 1 addition & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
black==19.10b0
pytest==5.4.1
pytest-httpserver==0.3.4
pytest-httpserver==1.0.0
20 changes: 20 additions & 0 deletions tests/test_integration_crashpad.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ def test_crashpad_capture(cmake, httpserver):
assert len(httpserver.log) == 2


def test_crashpad_reinstall(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"})

env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver))
httpserver.expect_oneshot_request("/api/123456/minidump/").respond_with_data("OK")

with httpserver.wait(timeout=10) as waiting:
child = run(tmp_path, "sentry_example", ["log", "reinstall", "crash"], env=env)
assert child.returncode # well, its a crash after all

assert waiting.result

run(tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env)

assert len(httpserver.log) == 1


def test_crashpad_crash(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"})

Expand Down Expand Up @@ -67,6 +84,9 @@ def test_crashpad_crash(cmake, httpserver):
assert_crashpad_upload(multipart)


@pytest.mark.skipif(
sys.platform == "linux", reason="linux clears the signal handlers on shutdown"
)
def test_crashpad_crash_after_shutdown(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "crashpad"})

Expand Down
37 changes: 37 additions & 0 deletions tests/test_integration_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ def test_inproc_crash_http(cmake, httpserver):
assert_crash(envelope)


def test_inproc_reinstall(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "inproc"})

env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver))
httpserver.expect_request(
"/api/123456/envelope/", headers={"x-sentry-auth": auth_header},
).respond_with_data("OK")

child = run(tmp_path, "sentry_example", ["log", "reinstall", "crash"], env=env,)
assert child.returncode # well, its a crash after all

run(
tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env,
)

assert len(httpserver.log) == 1


def test_inproc_dump_inflight(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "inproc"})

Expand Down Expand Up @@ -268,6 +286,25 @@ def test_breakpad_crash_http(cmake, httpserver):
assert_minidump(envelope)


@pytest.mark.skipif(not has_breakpad, reason="test needs breakpad backend")
def test_breakpad_reinstall(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "breakpad"})

env = dict(os.environ, SENTRY_DSN=make_dsn(httpserver))
httpserver.expect_request(
"/api/123456/envelope/", headers={"x-sentry-auth": auth_header},
).respond_with_data("OK")

child = run(tmp_path, "sentry_example", ["log", "reinstall", "crash"], env=env,)
assert child.returncode # well, its a crash after all

run(
tmp_path, "sentry_example", ["log", "no-setup"], check=True, env=env,
)

assert len(httpserver.log) == 1


@pytest.mark.skipif(not has_breakpad, reason="test needs breakpad backend")
def test_breakpad_dump_inflight(cmake, httpserver):
tmp_path = cmake(["sentry_example"], {"SENTRY_BACKEND": "breakpad"})
Expand Down