Add automatic libFuzzer linking + fuzz test

This commit is contained in:
Johan Engelen 2017-07-20 22:06:46 +02:00
parent 4f5bd4a9bc
commit 800dc5a97f
3 changed files with 139 additions and 0 deletions

View file

@ -45,6 +45,8 @@ public:
private:
virtual void addSanitizers();
virtual void addASanLinkFlags();
virtual void addFuzzLinkFlags();
virtual void addCppStdlibLinkFlags();
virtual void addUserSwitches();
void addDefaultLibs();
@ -260,11 +262,61 @@ void ArgsBuilder::addASanLinkFlags() {
}
}
// Adds all required link flags for -fsanitize=fuzzer when libFuzzer library is
// found.
void ArgsBuilder::addFuzzLinkFlags() {
std::string searchPaths[] = {
exe_path::prependLibDir("libFuzzer.a"),
exe_path::prependLibDir("libLLVMFuzzer.a"),
};
for (const auto &filepath : searchPaths) {
if (llvm::sys::fs::exists(filepath)) {
args.push_back(filepath);
// libFuzzer requires the C++ std library, but only add the link flags
// when libFuzzer was found.
addCppStdlibLinkFlags();
return;
}
}
}
void ArgsBuilder::addCppStdlibLinkFlags() {
switch (global.params.targetTriple->getOS()) {
case llvm::Triple::Linux:
if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android) {
args.push_back("-lc++");
} else {
args.push_back("-lstdc++");
}
break;
case llvm::Triple::Solaris:
case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
case llvm::Triple::DragonFly:
args.push_back("-lstdc++");
break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::FreeBSD:
args.push_back("-lc++");
break;
default:
// Don't know: do nothing so the user can step in
break;
}
}
void ArgsBuilder::addSanitizers() {
if (opts::isSanitizerEnabled(opts::AddressSanitizer)) {
addASanLinkFlags();
}
if (opts::isSanitizerEnabled(opts::FuzzSanitizer)) {
addFuzzLinkFlags();
}
// TODO: instead of this, we should link with our own sanitizer libraries
// because LDC's LLVM version could be different from the system clang.
if (opts::isSanitizerEnabled(opts::MemorySanitizer)) {

View file

@ -0,0 +1,49 @@
// Test Fuzz+ASan functionality
// REQUIRES: Fuzzer, ASan
// See https://github.com/ldc-developers/ldc/issues/2222 for -disable-fp-elim
// RUN: %ldc -g -fsanitize=address,fuzzer -disable-fp-elim %s -of=%t%exe
// RUN: not %t%exe 2>&1 | FileCheck %s
bool FuzzMe(ubyte* data, size_t dataSize)
{
return dataSize >= 6 &&
data[0] == 'F' &&
data[1] == 'U' &&
data[2] == 'Z' &&
data[3] == 'F' &&
data[4] == 'U' &&
data[5] == 'Z' &&
// CHECK: stack-buffer-overflow
// CHECK-NEXT: READ of size 1
// CHECK-NEXT: #0 {{.*}} in {{.*fuzz_asan6FuzzMe.*}} {{.*}}fuzz_asan.d:
// FIXME, debug line info is wrong (Github issue #2090). Once fixed, add [[@LINE+1]]
data[6] == 'Z'; // :<
}
extern (C) int LLVMFuzzerTestOneInput(const(ubyte*) data, size_t size)
{
// D runtime must be initialized, but only once.
static bool init = false;
if (!init)
{
import core.runtime : rt_init;
rt_init();
init = true;
}
ubyte[6] stackdata;
if (data)
{
for (auto i = 0; (i < size) && (i < stackdata.length); ++i)
stackdata[i] = data[i];
}
// CHECK-NEXT: #1 {{.*}} in LLVMFuzzerTestOneInput {{.*}}fuzz_asan.d:[[@LINE+1]]
FuzzMe(&stackdata[0], size);
return 0;
}
// The test unit should start with "FUZFUZ"
// CHECK: FUZFUZ

View file

@ -0,0 +1,38 @@
// Test basic fuzz test crash
// REQUIRES: Fuzzer
// RUN: %ldc -g -fsanitize=fuzzer %s -of=%t%exe
// RUN: not %t%exe 2>&1 | FileCheck %s
// CHECK: ERROR: libFuzzer: deadly signal
void FuzzMe(const(ubyte*) data, size_t size)
{
if ((size >= 6) && data[0] == 'F' && data[1] == 'U' && data[2] == 'Z'
&& data[3] == 'L' && data[4] == 'D' && data[5] == 'C')
{
assert(false);
}
}
extern (C) int LLVMFuzzerTestOneInput(const(ubyte*) data, size_t size)
{
// D runtime must be initialized, but only once.
static bool init = false;
if (!init)
{
import core.runtime : rt_init;
rt_init();
init = true;
}
auto a = new int; // Test that GC works
FuzzMe(data, size);
return 0;
}
// The test unit should start with "FUZLDC"
// CHECK: FUZLDC