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

#Centipede Support memory sanitizer and add new tests. #914

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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: 2 additions & 2 deletions centipede/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -1013,10 +1013,10 @@ RUNNER_SOURCES_NO_MAIN = [

RUNNER_SOURCES_WITH_MAIN = RUNNER_SOURCES_NO_MAIN + ["runner_main.cc"]

# Disable sancov and sanitizer instrumentation
# Disable sancov and sanitizer instrumentation, except for memory sanitizer, which would produce false positive if skipped here.
RUNNER_COPTS = [
"-fsanitize-coverage=0",
"-fno-sanitize=address,hwaddress,memory,thread,undefined",
"-fno-sanitize=address,hwaddress,thread,undefined",
]

RUNNER_LINKOPTS = [
Expand Down
16 changes: 16 additions & 0 deletions centipede/dso_example/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,19 @@ sh_test(
"@com_google_fuzztest//centipede:test_util_sh",
],
)

sh_test(
name = "dso_example_sanitizer_symbolize_test",
srcs = ["dso_example_sanitizer_symbolize_test.sh"],
data = [
":main",
],
tags = [
"external",
"manual",
"notap",
],
deps = [
"@com_google_fuzztest//centipede:test_util_sh",
],
)
44 changes: 44 additions & 0 deletions centipede/dso_example/dso_example_sanitizer_symbolize_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash

# 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.

# Tests the stack symbolization of the main binary when running with sanitizers.

set -eu

source "$(dirname "$0")/../test_util.sh"

CENTIPEDE_TEST_SRCDIR="$(centipede::get_centipede_test_srcdir)"

centipede::maybe_set_var_to_executable_path \
TARGET_BINARY "${CENTIPEDE_TEST_SRCDIR}/dso_example/main"

INPUT="${TEST_TMPDIR}/input"
LOG="${TEST_TMPDIR}/log"

echo -n 'FUZ' > "${INPUT}"
unset TEST_WARNINGS_OUTPUT_FILE
export ASAN_OPTIONS='handle_abort=2'
export MSAN_OPTIONS='handle_abort=2'
export TSAN_OPTIONS='handle_abort=2'
export CENTIPEDE_RUNNER_FLAGS=":use_cmp_features:"
"${TARGET_BINARY}" "${INPUT}" |& tee "${LOG}"

# Check that sanitizer reports the crash
centipede::assert_regex_in_file "ERROR: .*Sanitizer:" "${LOG}"
# Check that the intended stack location is symbolized and printed
centipede::assert_regex_in_file "#0 .* in FuzzMe" "${LOG}"

echo "PASS"
18 changes: 14 additions & 4 deletions centipede/runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ namespace {

// Returns the length of the common prefix of `s1` and `s2`, but not more
// than 63. I.e. the returned value is in [0, 64).
size_t LengthOfCommonPrefix(const void *s1, const void *s2, size_t n) {
//
// Needed to skip memory sanitizer to avoid false positives in error reporting.
__attribute__((no_sanitize("memory"))) size_t LengthOfCommonPrefix(
const void *s1, const void *s2, size_t n) {
const auto *p1 = static_cast<const uint8_t *>(s1);
const auto *p2 = static_cast<const uint8_t *>(s2);
static constexpr size_t kMaxLen = 63;
Expand All @@ -89,7 +92,14 @@ class ThreadTerminationDetector {
~ThreadTerminationDetector() { tls.OnThreadStop(); }
};

thread_local ThreadTerminationDetector termination_detector;
thread_local ThreadTerminationDetector thread_termination_detector;

class ProcessTerminationDetector {
public:
~ProcessTerminationDetector() { state.OnProcessExit(); }
};

static ProcessTerminationDetector process_termination_detector;

} // namespace

Expand Down Expand Up @@ -142,7 +152,7 @@ void ThreadLocalRunnerState::TraceMemCmp(uintptr_t caller_pc, const uint8_t *s1,
}

void ThreadLocalRunnerState::OnThreadStart() {
termination_detector.EnsureAlive();
thread_termination_detector.EnsureAlive();
tls.lowest_sp = tls.top_frame_sp =
reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
tls.stack_region_low = GetCurrentThreadStackRegionLow();
Expand Down Expand Up @@ -1000,7 +1010,7 @@ GlobalRunnerState::GlobalRunnerState() {
}
}

GlobalRunnerState::~GlobalRunnerState() {
void GlobalRunnerState::OnProcessExit() {
// The process is winding down, but CentipedeRunnerMain did not run.
// This means, the binary is standalone with its own main(), and we need to
// report the coverage now.
Expand Down
3 changes: 2 additions & 1 deletion centipede/runner.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ struct GlobalRunnerState {
Knobs knobs;

GlobalRunnerState();
~GlobalRunnerState();

void OnProcessExit();

// Runner reads flags from CentipedeGetRunnerFlags(). We don't use flags
// passed via argv so that argv flags can be passed directly to
Expand Down
3 changes: 2 additions & 1 deletion centipede/runner_fork_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ const char *GetOneEnv(const char *key) {
// without explicitly specified priority run after all constructors with
// explicitly specified priority, thus we still run before most
// "normal" constructors.
__attribute__((constructor(150))) void ForkServerCallMeVeryEarly() {
__attribute__((constructor(150), no_sanitize("memory"))) void
ForkServerCallMeVeryEarly() {
// Guard against calling twice.
static bool called_already = false;
if (called_already) return;
Expand Down
1 change: 1 addition & 0 deletions centipede/runner_sancov.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ __attribute__((noinline)) static void HandlePath(uintptr_t normalized_pc) {
// With __sanitizer_cov_trace_pc_guard this is an index of PC in the PC table.
// With __sanitizer_cov_trace_pc this is PC itself, normalized by subtracting
// the DSO's dynamic start address.
NO_SANITIZE
static inline void HandleOnePc(PCGuard pc_guard) {
if (!state.run_time_flags.use_pc_features) return;
state.pc_counter_set.SaturatedIncrement(pc_guard.pc_index);
Expand Down
12 changes: 0 additions & 12 deletions centipede/testing/build_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,6 @@ affect all its transitive dependencies as well.
# Change the flags from the default ones to sancov:
# https://clang.llvm.org/docs/SanitizerCoverage.html.
def _sancov_transition_impl(settings, attr):
features_to_strip = ["tsan", "msan"]
filtered_features = [
x
for x in settings["//command_line_option:features"]
if x not in features_to_strip
]

# some of the valid sancov flag combinations:
# trace-pc-guard,pc-table
# trace-pc-guard,pc-table,trace-cmp
Expand All @@ -50,24 +43,19 @@ def _sancov_transition_impl(settings, attr):
],
"//command_line_option:compilation_mode": "opt",
"//command_line_option:strip": "never", # preserve debug info.
"//command_line_option:features": filtered_features,
"//command_line_option:compiler": None,
"//command_line_option:dynamic_mode": "off",
}

sancov_transition = transition(
implementation = _sancov_transition_impl,
inputs = [
"//command_line_option:copt",
"//command_line_option:features",
],
outputs = [
"//command_line_option:collect_code_coverage",
"//command_line_option:copt",
"//command_line_option:compilation_mode",
"//command_line_option:strip",
"//command_line_option:features",
"//command_line_option:compiler",
"//command_line_option:dynamic_mode",
],
)
Expand Down