Skip to content

Commit

Permalink
Send SIGABRT from the watchdog thread to the thread executing the inp…
Browse files Browse the repository at this point in the history
…uts.

This improves error reporting, because the produced stack trace is more likely
to be related to the reason for exceeding a resource limit.

PiperOrigin-RevId: 723943930
  • Loading branch information
fniksic authored and copybara-github committed Feb 11, 2025
1 parent 58dda9b commit 2dbd532
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
27 changes: 25 additions & 2 deletions centipede/runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "./centipede/runner.h"

#include <pthread.h> // NOLINT: use pthread to avoid extra dependencies.
#include <signal.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
Expand All @@ -39,6 +40,7 @@
#include <ctime>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
Expand Down Expand Up @@ -256,7 +258,17 @@ static void CheckWatchdogLimits() {
" (%s); exiting\n",
resource.what, resource.value, resource.limit, resource.units);
WriteFailureDescription(resource.failure);
abort();
pthread_mutex_lock(&state.runner_main_thread_mu);
if (state.runner_main_thread.has_value()) {
fprintf(stderr, "Sending SIGABRT to the runner main thread.\n");
pthread_kill(*state.runner_main_thread, SIGABRT);
pthread_mutex_unlock(&state.runner_main_thread_mu);
return;
} else {
pthread_mutex_unlock(&state.runner_main_thread_mu);
fprintf(stderr, "Aborting the runner in the watchdog thread.\n");
std::abort();
}
}
}
}
Expand Down Expand Up @@ -293,7 +305,7 @@ __attribute__((noinline)) void CheckStackLimit(uintptr_t sp) {
tls.top_frame_sp - sp, stack_limit);
centipede::WriteFailureDescription(
centipede::kExecutionFailureStackLimitExceeded.data());
abort();
std::abort();
}
}

Expand Down Expand Up @@ -1109,6 +1121,17 @@ GlobalRunnerState::~GlobalRunnerState() {
//
// Note: argc/argv are used for only ReadOneInputExecuteItAndDumpCoverage().
int RunnerMain(int argc, char **argv, RunnerCallbacks &callbacks) {
{
LockGuard lock(state.runner_main_thread_mu);
state.runner_main_thread = pthread_self();
}
struct OnReturn {
~OnReturn() {
LockGuard lock(state.runner_main_thread_mu);
state.runner_main_thread = std::nullopt;
}
} on_return;

state.centipede_runner_main_executed = true;

fprintf(stderr, "Centipede fuzz target runner; argv[0]: %s flags: %s\n",
Expand Down
11 changes: 9 additions & 2 deletions centipede/runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <optional>

#include "absl/base/const_init.h"
#include "absl/base/nullability.h"
Expand Down Expand Up @@ -213,7 +214,7 @@ struct GlobalRunnerState {
return strndup(value_beg, end - value_beg);
}

pthread_mutex_t execution_result_override_mu;
pthread_mutex_t execution_result_override_mu = PTHREAD_MUTEX_INITIALIZER;
// If not nullptr, it points to a batch result with either zero or one
// execution. When an execution result present, it will be passed as the
// execution result of the current test input. The object is owned and cleaned
Expand All @@ -225,7 +226,8 @@ struct GlobalRunnerState {
ThreadLocalRunnerState *tls_list;
// Doubly linked list of detached TLSs.
ThreadLocalRunnerState *detached_tls_list;
pthread_mutex_t tls_list_mu; // Guards tls_list and detached_tls_list.
// Guards `tls_list` and `detached_tls_list`.
pthread_mutex_t tls_list_mu = PTHREAD_MUTEX_INITIALIZER;
// Iterates all TLS objects under tls_list_mu, except those with `ignore` set.
// Calls `callback()` on every TLS.
template <typename Callback>
Expand Down Expand Up @@ -324,6 +326,11 @@ struct GlobalRunnerState {
// CentipedeRunnerMain() sets this to true.
bool centipede_runner_main_executed = false;

// The thread that runs `RunnerMain()` and executes the inputs.
std::optional<pthread_t> runner_main_thread;
// Guards `runner_main_thread`.
pthread_mutex_t runner_main_thread_mu = PTHREAD_MUTEX_INITIALIZER;

// Timeout-related machinery.

// Starts the watchdog thread that terminates the runner if any of the
Expand Down

0 comments on commit 2dbd532

Please sign in to comment.