blob: 20a4fc14a936ee44021b9381ae574570d649152d [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include <sanitizer/common_interface_defs.h>
#include <sanitizer/lsan_interface.h>
#include "src/lib/fxl/macros.h"
#include "src/sys/fuzzing/common/sancov.h"
#include "src/sys/fuzzing/common/testing/module.h"
namespace fuzzing {
// The |FakeSanitizerRuntime| provides implementations of weak symbols usually provided by sanitizer
// runtime if no such runtime is present.
class FakeSanitizerRuntime final {
public:
FakeSanitizerRuntime() {
__sanitizer_cov_8bit_counters_init(module_.counters(), module_.counters_end());
__sanitizer_cov_pcs_init(module_.pcs(), module_.pcs_end());
}
~FakeSanitizerRuntime() = default;
uint8_t &operator[](size_t index) { return module_[index]; }
using MallocHook = void (*)(const volatile void *, size_t);
void set_malloc_hook(MallocHook malloc_hook) { malloc_hook_ = malloc_hook; }
using DeathCallback = void (*)();
void set_death_callback(DeathCallback death_callback) { death_callback_ = death_callback; }
void set_leak(bool leak) { leak_ = leak; }
int DoRecoverableLeakCheck() { return leak_ ? 1 : 0; }
int AcquireCrashState() { return !crash_state_acquired_.exchange(true); }
void OnMalloc(size_t len) {
FX_CHECK(malloc_hook_) << "__sanitizer_install_malloc_and_free_hooks was not called.";
malloc_hook_(this, len);
}
void OnDeath() {
FX_CHECK(death_callback_) << "__sanitizer_set_death_callback was not called.";
death_callback_();
exit(1);
}
private:
FakeModule module_;
MallocHook malloc_hook_ = nullptr;
DeathCallback death_callback_ = nullptr;
bool leak_ = false;
std::atomic<bool> crash_state_acquired_ = false;
FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(FakeSanitizerRuntime);
};
// The fake sanitizer runtime needs to run code before |main| and the |InstrumentedProcess|
// constructor, so like the latter it takes an exception to usual rule requiring globally scoped
// objects to be trivially constructible. To mitigate the static initializtion order fiasco, it
// needs to be constructed as late as possible, but still ahead of |InstrumentedProcess|.
[[gnu::init_priority(0xfffe)]] FakeSanitizerRuntime gFakeSanitizerRuntime;
void SetCoverage(size_t index, uint8_t value) { gFakeSanitizerRuntime[index] = value; }
void Malloc(size_t size) { gFakeSanitizerRuntime.OnMalloc(size); }
void LeakMemory() { gFakeSanitizerRuntime.set_leak(true); }
void Die() { gFakeSanitizerRuntime.OnDeath(); }
} // namespace fuzzing
extern "C" {
int __sanitizer_acquire_crash_state() { return fuzzing::gFakeSanitizerRuntime.AcquireCrashState(); }
void __sanitizer_print_memory_profile(size_t, size_t) {}
void __sanitizer_set_death_callback(void (*death_callback)(void)) {
fuzzing::gFakeSanitizerRuntime.set_death_callback(death_callback);
}
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const volatile void *, size_t),
void (*free_hook)(const volatile void *)) {
fuzzing::gFakeSanitizerRuntime.set_malloc_hook(malloc_hook);
return 1;
}
void __sanitizer_purge_allocator() {}
void __lsan_enable() {}
void __lsan_disable() {}
int __lsan_do_recoverable_leak_check() {
return fuzzing::gFakeSanitizerRuntime.DoRecoverableLeakCheck();
}
} // extern "C"