Skip to content

Commit

Permalink
#Centipede Improve thread termination detection to handle pthread_exit.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 574999308
  • Loading branch information
xinhaoyuan authored and copybara-github committed Nov 2, 2023
1 parent 2d7ebf0 commit 5e24a2b
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 4 deletions.
1 change: 1 addition & 0 deletions centipede/puzzles/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ package(default_visibility = ["@com_google_fuzztest//centipede/puzzles:__subpack
"autodictionary_stress",
"paths",
"thread_uint32_cmp_1",
"pthread_exit_uint32_cmp_1",
]]
52 changes: 52 additions & 0 deletions centipede/puzzles/pthread_exit_uint32_cmp_1.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2023 The Centipede Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Centipede puzzle: one 4-byte cmp, in a separate thread using pthread
// interface. We should be able to solve it w/o cmp features *or* w/o auto
// dictionary.
//
// RUN: Run && SolutionIs Fuzz
// RUN: Run --use_auto_dictionary=0 && SolutionIs Fuzz
// RUN: Run --use_cmp_features=0 && SolutionIs Fuzz

#include <pthread.h>

#include <cstdint>
#include <cstdlib>
#include <cstring>

// non-const, to avoid compiler optimization.
static char expected_data[] = "Fuzz";

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
pthread_t pt;
struct ThreadArg {
const uint8_t *data;
size_t size;
} arg = {.data = data, .size = size};
auto pt_entry = +[](const ThreadArg *thread_arg) {
uint32_t value, expected_value;
if (thread_arg->size == sizeof(value)) {
memcpy(&value, thread_arg->data, sizeof(value));
memcpy(&expected_value, expected_data, sizeof(expected_value));
if (value == expected_value) abort();
pthread_exit(nullptr);
}
};
if (pthread_create(&pt, nullptr,
reinterpret_cast<void *(*)(void *)>(pt_entry), &arg) != 0)
return 1;
if (pthread_join(pt, nullptr) != 0) return 1;
return 0;
}
12 changes: 12 additions & 0 deletions centipede/runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ size_t LengthOfCommonPrefix(const void *s1, const void *s2, size_t n) {
return n;
}

class ThreadTerminationDetector {
public:
// A dummy method to trigger the construction and make sure that the
// destructor will be called on the thread termination.
__attribute__((optnone)) void EnsureAlive() {}

~ThreadTerminationDetector() { tls.OnThreadStop(); }
};

thread_local ThreadTerminationDetector termination_detector;

} // namespace

// Use of the fixed init priority allows to call CentipedeRunnerMain
Expand Down Expand Up @@ -126,6 +137,7 @@ void ThreadLocalRunnerState::TraceMemCmp(uintptr_t caller_pc, const uint8_t *s1,
}

void ThreadLocalRunnerState::OnThreadStart() {
termination_detector.EnsureAlive();
tls.lowest_sp = tls.top_frame_sp =
reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
tls.call_stack.Reset(state.run_time_flags.callstack_level);
Expand Down
6 changes: 3 additions & 3 deletions centipede/runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ struct ThreadLocalRunnerState {
// Guarded by state.tls_list_mu.
ThreadLocalRunnerState *next, *prev;

// The pthread_create() interceptor calls OnThreadStart()/OnThreadStop()
// before/after the thread callback.
// The main thread calls OnThreadStart().
// The pthread_create() interceptor calls OnThreadStart() before the thread
// callback. The main thread also calls OnThreadStart(). OnThreadStop() will
// be called when thread termination is detected internally - see runner.cc.
void OnThreadStart();
void OnThreadStop();

Expand Down
1 change: 0 additions & 1 deletion centipede/runner_interceptors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ void *MyThreadStart(void *arg) {
auto *args = static_cast<ThreadCreateArgs *>(arg);
tls.OnThreadStart();
void *retval = args->start_routine(args->arg);
tls.OnThreadStop();
delete args; // allocated in the pthread_create wrapper.
return retval;
}
Expand Down

0 comments on commit 5e24a2b

Please sign in to comment.