mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-11 05:16:19 +03:00
Add automatic libFuzzer linking + fuzz test
This commit is contained in:
parent
4f5bd4a9bc
commit
800dc5a97f
3 changed files with 139 additions and 0 deletions
|
@ -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)) {
|
||||
|
|
49
tests/sanitizers/fuzz_asan.d
Normal file
49
tests/sanitizers/fuzz_asan.d
Normal 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
|
38
tests/sanitizers/fuzz_basic.d
Normal file
38
tests/sanitizers/fuzz_basic.d
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue