forked from OSchip/llvm-project
[libFuzzer] Make -fsanitize=memory,fuzzer work.
This patch allows libFuzzer to fuzz applications instrumented with MSan without recompiling libFuzzer with MSan instrumentation. Fixes https://github.com/google/sanitizers/issues/958. Differential Revision: https://reviews.llvm.org/D48891 llvm-svn: 336619
This commit is contained in:
parent
6cd35e8194
commit
a34c65e845
|
@ -537,6 +537,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
|||
EF = new ExternalFunctions();
|
||||
if (EF->LLVMFuzzerInitialize)
|
||||
EF->LLVMFuzzerInitialize(argc, argv);
|
||||
if (EF->__msan_scoped_disable_interceptor_checks)
|
||||
EF->__msan_scoped_disable_interceptor_checks();
|
||||
const Vector<std::string> Args(*argv, *argv + *argc);
|
||||
assert(!Args.empty());
|
||||
ProgName = new std::string(Args[0]);
|
||||
|
|
|
@ -46,3 +46,6 @@ EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
|
|||
EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
|
||||
EXT_FUNC(__sanitizer_dump_coverage, void, (const uintptr_t *, uintptr_t),
|
||||
false);
|
||||
EXT_FUNC(__msan_scoped_disable_interceptor_checks, void, (), false);
|
||||
EXT_FUNC(__msan_scoped_enable_interceptor_checks, void, (), false);
|
||||
EXT_FUNC(__msan_unpoison, void, (const volatile void *, size_t size), false);
|
||||
|
|
|
@ -152,6 +152,28 @@ private:
|
|||
static thread_local bool IsMyThread;
|
||||
};
|
||||
|
||||
struct ScopedEnableMsanInterceptorChecks {
|
||||
ScopedEnableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_enable_interceptor_checks)
|
||||
EF->__msan_scoped_enable_interceptor_checks();
|
||||
}
|
||||
~ScopedEnableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_disable_interceptor_checks)
|
||||
EF->__msan_scoped_disable_interceptor_checks();
|
||||
}
|
||||
};
|
||||
|
||||
struct ScopedDisableMsanInterceptorChecks {
|
||||
ScopedDisableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_disable_interceptor_checks)
|
||||
EF->__msan_scoped_disable_interceptor_checks();
|
||||
}
|
||||
~ScopedDisableMsanInterceptorChecks() {
|
||||
if (EF->__msan_scoped_enable_interceptor_checks)
|
||||
EF->__msan_scoped_enable_interceptor_checks();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_INTERNAL_H
|
||||
|
|
|
@ -179,6 +179,7 @@ void Fuzzer::StaticDeathCallback() {
|
|||
void Fuzzer::DumpCurrentUnit(const char *Prefix) {
|
||||
if (!CurrentUnitData)
|
||||
return; // Happens when running individual inputs.
|
||||
ScopedDisableMsanInterceptorChecks S;
|
||||
MD.PrintMutationSequence();
|
||||
Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
|
||||
size_t UnitSize = CurrentUnitSize;
|
||||
|
@ -516,19 +517,24 @@ void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
|
|||
// so that we reliably find buffer overflows in it.
|
||||
uint8_t *DataCopy = new uint8_t[Size];
|
||||
memcpy(DataCopy, Data, Size);
|
||||
if (EF->__msan_unpoison)
|
||||
EF->__msan_unpoison(DataCopy, Size);
|
||||
if (CurrentUnitData && CurrentUnitData != Data)
|
||||
memcpy(CurrentUnitData, Data, Size);
|
||||
CurrentUnitSize = Size;
|
||||
AllocTracer.Start(Options.TraceMalloc);
|
||||
UnitStartTime = system_clock::now();
|
||||
TPC.ResetMaps();
|
||||
RunningCB = true;
|
||||
int Res = CB(DataCopy, Size);
|
||||
RunningCB = false;
|
||||
UnitStopTime = system_clock::now();
|
||||
(void)Res;
|
||||
assert(Res == 0);
|
||||
HasMoreMallocsThanFrees = AllocTracer.Stop();
|
||||
{
|
||||
ScopedEnableMsanInterceptorChecks S;
|
||||
AllocTracer.Start(Options.TraceMalloc);
|
||||
UnitStartTime = system_clock::now();
|
||||
TPC.ResetMaps();
|
||||
RunningCB = true;
|
||||
int Res = CB(DataCopy, Size);
|
||||
RunningCB = false;
|
||||
UnitStopTime = system_clock::now();
|
||||
(void)Res;
|
||||
assert(Res == 0);
|
||||
HasMoreMallocsThanFrees = AllocTracer.Stop();
|
||||
}
|
||||
if (!LooseMemeq(DataCopy, Data, Size))
|
||||
CrashOnOverwrittenData();
|
||||
CurrentUnitSize = 0;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
volatile size_t Sink;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size < 4) return 0;
|
||||
if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') {
|
||||
char uninit[7];
|
||||
Sink = strlen(uninit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
struct Simple {
|
||||
int x_;
|
||||
Simple() {
|
||||
x_ = 5;
|
||||
}
|
||||
~Simple() {
|
||||
x_ += 1;
|
||||
}
|
||||
};
|
||||
|
||||
Simple *volatile SimpleSink;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size < 4) return 0;
|
||||
if (Data[0] == 'F' && Data[1] == 'U' && Data[2] == 'Z' && Data[3] == 'Z') {
|
||||
{
|
||||
Simple S;
|
||||
SimpleSink = &S;
|
||||
}
|
||||
if (SimpleSink->x_) fprintf(stderr, "Failed to catch use-after-dtor\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ config.substitutions.append(('%build_dir', config.cmake_binary_dir))
|
|||
libfuzzer_src_root = os.path.join(config.compiler_rt_src_root, "lib", "fuzzer")
|
||||
config.substitutions.append(('%libfuzzer_src', libfuzzer_src_root))
|
||||
|
||||
def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True):
|
||||
def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=False):
|
||||
compiler_cmd = config.clang
|
||||
extra_cmd = config.target_flags
|
||||
if config.clang and config.stdlib == 'libc++':
|
||||
|
@ -63,7 +63,10 @@ def generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True):
|
|||
link_cmd = '-lstdc++'
|
||||
|
||||
std_cmd = '--driver-mode=g++ -std=c++11' if is_cpp else ''
|
||||
sanitizers = ['address']
|
||||
if msan_enabled:
|
||||
sanitizers = ['memory']
|
||||
else:
|
||||
sanitizers = ['address']
|
||||
if fuzzer_enabled:
|
||||
sanitizers.append('fuzzer')
|
||||
sanitizers_cmd = ('-fsanitize=%s' % ','.join(sanitizers))
|
||||
|
@ -93,6 +96,10 @@ config.substitutions.append(('%no_fuzzer_c_compiler',
|
|||
generate_compiler_cmd(is_cpp=False, fuzzer_enabled=False)
|
||||
))
|
||||
|
||||
config.substitutions.append(('%msan_compiler',
|
||||
generate_compiler_cmd(is_cpp=True, fuzzer_enabled=True, msan_enabled=True)
|
||||
))
|
||||
|
||||
if config.host_os == 'Darwin':
|
||||
if config.target_arch in ["x86_64", "x86_64h"]:
|
||||
config.parallelism_group = "darwin-64bit-sanitizer"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
RUN: %msan_compiler %S/SimpleTest.cpp -o %t
|
||||
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
|
||||
|
||||
RUN: %msan_compiler %S/SimpleCmpTest.cpp -o %t
|
||||
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
|
||||
|
||||
RUN: %msan_compiler %S/MemcmpTest.cpp -o %t
|
||||
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
|
||||
|
||||
RUN: %msan_compiler %S/StrcmpTest.cpp -o %t
|
||||
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=NO-REPORT
|
||||
|
||||
NO-REPORT-NOT: MemorySanitizer
|
||||
NO-REPORT: BINGO
|
||||
|
||||
|
||||
RUN: %msan_compiler %S/UseAfterDtor.cpp -o %t
|
||||
RUN: MSAN_OPTIONS=poison_in_dtor=1 not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT
|
||||
|
||||
RUN: %msan_compiler %S/UninitializedStrlen.cpp -o %t
|
||||
RUN: not %run %t -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=REPORT
|
||||
|
||||
REPORT: MemorySanitizer: use-of-uninitialized-value
|
Loading…
Reference in New Issue