diff --git a/centipede/BUILD b/centipede/BUILD index d173db671..50664b478 100644 --- a/centipede/BUILD +++ b/centipede/BUILD @@ -924,7 +924,6 @@ RUNNER_SOURCES_NO_MAIN = [ "runner_interceptors.cc", "runner_interface.h", "runner_sancov.cc", - "runner_sanitizer.cc", "shared_memory_blob_sequence.cc", "shared_memory_blob_sequence.h", ] diff --git a/centipede/runner.cc b/centipede/runner.cc index 8bffdd972..ecb18785a 100644 --- a/centipede/runner.cc +++ b/centipede/runner.cc @@ -908,9 +908,10 @@ extern void ForkServerCallMeVeryEarly(); // * linker sees them and decides to drop runner_sancov.o. extern void RunnerSancov(); [[maybe_unused]] auto fake_reference_for_runner_sancov = &RunnerSancov; -// Same for runner_sanitizer.cc. -extern void RunnerSanitizer(); -[[maybe_unused]] auto fake_reference_for_runner_sanitizer = &RunnerSanitizer; +// Same for runner_interceptor.cc. +extern void RunnerInterceptor(); +[[maybe_unused]] auto fake_reference_for_runner_interceptor = + &RunnerInterceptor; GlobalRunnerState::GlobalRunnerState() { // TODO(kcc): move some code from CentipedeRunnerMain() here so that it works diff --git a/centipede/runner_interceptors.cc b/centipede/runner_interceptors.cc index 7f94fbeb1..62776b8d9 100644 --- a/centipede/runner_interceptors.cc +++ b/centipede/runner_interceptors.cc @@ -13,13 +13,7 @@ // limitations under the License. // Function interceptors for Centipede. -// Interceptors are disabled under ASAN/TSAN/MSAN because those sanitizers -// have their own conflicting interceptors. -// The typical usage of sanitizers with Centipede is via the --extra_binaries -// flag, where the sanitized binary does not produce coverage output and thus -// doesn't need (most of?) interceptors. -#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) && \ - !defined(MEMORY_SANITIZER) + #include // for dlsym() #include @@ -77,19 +71,49 @@ int NormalizeCmpResult(int result) { } // namespace -// Initialize original function pointers at the module startup. This may still -// be too late, since the functions may be used before this module is -// initialized. So, the interceptor may not assume that X_orig != nullptr for -// function X. -static auto memcmp_orig = - FuncAddr("memcmp"); -static auto strcmp_orig = - FuncAddr("strcmp"); - -// TODO(kcc): as we implement more functions like memcmp_fallback and -// length_of_common_prefix, move them into a separate module and unittest. +namespace centipede { +void RunnerInterceptor() {} // to be referenced in runner.cc +} // namespace centipede -// Fallback for the case memcmp_orig is null. +// A sanitizer-compatible way to intercept functions that are potentially +// intercepted by sanitizers, in which case the symbol __interceptor_X would be +// defined for intercepted function X. So we always forward an intercepted call +// to the sanitizer interceptor if it exists, and fall back to the next +// definition following dlsym. +// +// We define the X_orig pointers that are statically initialized to GetOrig_X() +// with the aforementioned logic to fill the pointers early, but they might +// still be too late. So the Centipede interceptors might need to handle the +// nullptr case and/or use REAL(X), which calls GetOrig_X() when needed. Also +// see compiler-rt/lib/interception/interception.h in the llvm-project source +// code. +// +// Note that since LLVM 17 it allows three interceptions (from the original +// binary, an external tool, and a sanitizer) to co-exist under a new scheme, +// while it is still compatible with the old way used here. +#define SANITIZER_INTERCEPTOR_NAME(orig_func_name) \ + __interceptor_##orig_func_name +#define DECLARE_CENTIPEDE_ORIG_FUNC(ret_type, orig_func_name, args) \ + extern "C" __attribute__((weak)) \ + ret_type(SANITIZER_INTERCEPTOR_NAME(orig_func_name)) args; \ + static decltype(&SANITIZER_INTERCEPTOR_NAME( \ + orig_func_name)) GetOrig_##orig_func_name() { \ + if (auto p = &SANITIZER_INTERCEPTOR_NAME(orig_func_name)) return p; \ + return FuncAddr( \ + #orig_func_name); \ + } \ + static ret_type(*orig_func_name##_orig) args = GetOrig_##orig_func_name() +#define REAL(orig_func_name) \ + (orig_func_name##_orig ? orig_func_name##_orig : GetOrig_##orig_func_name()) + +DECLARE_CENTIPEDE_ORIG_FUNC(int, memcmp, + (const void *s1, const void *s2, size_t n)); +DECLARE_CENTIPEDE_ORIG_FUNC(int, strcmp, (const char *s1, const char *s2)); +DECLARE_CENTIPEDE_ORIG_FUNC(int, pthread_create, + (pthread_t * thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg)); + +// Fallback for the case *cmp_orig is null. // Will be executed several times at process startup, if at all. static int memcmp_fallback(const void *s1, const void *s2, size_t n) { const auto *p1 = static_cast(s1); @@ -131,12 +155,8 @@ extern "C" int strcmp(const char *s1, const char *s2) { // Calls real pthread_create, but wraps the start_routine() in MyThreadStart. extern "C" int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { - static auto pthread_create_orig = - FuncAddr("pthread_create"); // Wrap the arguments. Will be deleted in MyThreadStart. auto *wrapped_args = new ThreadCreateArgs{start_routine, arg}; // Run the actual pthread_create. - return pthread_create_orig(thread, attr, MyThreadStart, wrapped_args); + return REAL(pthread_create)(thread, attr, MyThreadStart, wrapped_args); } -#endif // not ASAN/TSAN/MSAN diff --git a/centipede/runner_sanitizer.cc b/centipede/runner_sanitizer.cc deleted file mode 100644 index db38fb472..000000000 --- a/centipede/runner_sanitizer.cc +++ /dev/null @@ -1,50 +0,0 @@ -// 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. - -// Instrumentation callbacks for sanitizers. See -// compiler-rt/include/sanitizer/common_interface_defs.h in the LLVM -// repo. - -#include -#include - -#include "./centipede/runner.h" - -#define NO_SANITIZE __attribute__((no_sanitize("all"))) - -namespace centipede { -void RunnerSanitizer() {} // to be referenced in runner.cc -} // namespace centipede - -NO_SANITIZE -extern "C" void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1, - const void *s2, size_t n, - int result) { - if (s1 == nullptr || s2 == nullptr) return; - centipede::tls.TraceMemCmp(reinterpret_cast(caller_pc), - reinterpret_cast(s1), - reinterpret_cast(s2), n, - result == 0); -} -NO_SANITIZE -extern "C" void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1, - const char *s2, int result) { - if (s1 == nullptr || s2 == nullptr) return; - size_t len = 0; - while (s1[len] && s2[len]) ++len; - centipede::tls.TraceMemCmp(reinterpret_cast(caller_pc), - reinterpret_cast(s1), - reinterpret_cast(s2), len, - result == 0); -}