optimizations options (e.g. -O0, -O1, -O2) to diversify testing.
* Build a test driver using the same options as the library.
The test driver is a C/C++ file containing interesting calls to the library
- inside a single function ``extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);``
+ inside a single function ``extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);``.
+ Currently, the only expected return value is 0, others are reserved for future.
* Link the Fuzzer, the library and the driver together into an executable
using the same sanitizer options as for the library.
* Collect the initial corpus of inputs for the
A simple function that does something interesting if it receives the input "HI!"::
cat << EOF >> test_fuzzer.cc
- extern "C" void LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) {
+ extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size) {
if (size > 0 && data[0] == 'H')
if (size > 1 && data[1] == 'I')
if (size > 2 && data[2] == '!')
__builtin_trap();
+ return 0;
}
EOF
# Get lib/Fuzzer. Assuming that you already have fresh clang in PATH.
cat << EOF > pcre_fuzzer.cc
#include <string.h>
#include "pcre2posix.h"
- extern "C" void LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
- if (size < 1) return;
+ extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
+ if (size < 1) return 0;
char *str = new char[size+1];
memcpy(str, data, size);
str[size] = 0;
regfree(&preg);
}
delete [] str;
+ return 0;
}
EOF
clang++ -g -fsanitize=address $COV_FLAGS -c -std=c++11 -I inst/include/ pcre_fuzzer.cc
assert (SSL_CTX_use_PrivateKey_file(sctx, "server.key", SSL_FILETYPE_PEM));
return 0;
}
- extern "C" void LLVMFuzzerTestOneInput(unsigned char *Data, size_t Size) {
+ extern "C" int LLVMFuzzerTestOneInput(unsigned char *Data, size_t Size) {
static int unused = Init();
SSL *server = SSL_new(sctx);
BIO *sinbio = BIO_new(BIO_s_mem());
BIO_write(sinbio, Data, Size);
SSL_do_handshake(server);
SSL_free(server);
+ return 0;
}
EOF
# Build the fuzzer.
namespace fuzzer {
-typedef void (*UserCallback)(const uint8_t *Data, size_t Size);
+typedef void (*DeprecatedUserCallback)(const uint8_t *Data, size_t Size);
+/// Returns an int 0. Values other than zero are reserved for future.
+typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
/** Simple C-like interface with a single user-supplied callback.
Usage:
#\code
#include "FuzzerInterface.h"
-void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
DoStuffWithData(Data, Size);
+ return 0;
}
// Implement your own main() or use the one from FuzzerMain.cpp.
#\endcode
*/
int FuzzerDriver(int argc, char **argv, UserCallback Callback);
+int FuzzerDriver(int argc, char **argv, DeprecatedUserCallback Callback);
class FuzzerRandomBase {
public:
public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
// Must define the target function.
- void TargetFunction(...) { ... }
+ int TargetFunction(...) { ...; return 0; }
// Optionally define the mutator.
size_t Mutate(...) { ... }
// Optionally define the CrossOver method.
UserSuppliedFuzzer(); // Deprecated, don't use.
UserSuppliedFuzzer(FuzzerRandomBase *Rand);
/// Executes the target function on 'Size' bytes of 'Data'.
- virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
+ virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0;
/// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
/// returns the new size of the data, which should be positive.
virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
public:
SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback)
: UserSuppliedFuzzer(Rand), Callback(Callback) {}
- virtual void TargetFunction(const uint8_t *Data, size_t Size) {
- return Callback(Data, Size);
+
+ SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, DeprecatedUserCallback Callback)
+ : UserSuppliedFuzzer(Rand), DeprecatedCallback(Callback) {}
+
+ virtual int TargetFunction(const uint8_t *Data, size_t Size) override {
+ if (Callback) return Callback(Data, Size);
+ DeprecatedCallback(Data, Size);
+ return 0;
}
private:
- UserCallback Callback;
+ DeprecatedUserCallback DeprecatedCallback = nullptr;
+ UserCallback Callback = nullptr;
};
}; // namespace fuzzer
}
void Fuzzer::ExecuteCallback(const Unit &U) {
+ int Res = 0;
if (Options.Tokens.empty()) {
- USF.TargetFunction(U.data(), U.size());
+ Res = USF.TargetFunction(U.data(), U.size());
} else {
auto T = SubstituteTokens(U);
- USF.TargetFunction(T.data(), T.size());
+ Res = USF.TargetFunction(T.data(), T.size());
}
+ assert(Res == 0);
}
size_t Fuzzer::RunOneMaximizeTotalCoverage(const Unit &U) {
#include "FuzzerInternal.h"
// This function should be defined by the user.
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
int main(int argc, char **argv) {
return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput);
// executed many times.
#include <iostream>
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int Num = 0;
for (size_t i = 0; i < Size; i++)
if (Data[i] == 'A' + i)
std::cerr << "BINGO!\n";
exit(1);
}
+ return 0;
}
exit(1);
}
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// looking for "thread_local unsigned A;"
- if (Size < 24) return;
+ if (Size < 24) return 0;
if (0 == memcmp(&Data[0], "thread_local", 12))
if (Data[12] == ' ')
if (0 == memcmp(&Data[13], "unsigned", 8))
if (Data[22] == 'A')
if (Data[23] == ';')
Found();
+ return 0;
}
#include <cstddef>
#include <iostream>
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int bits = 0;
if (Size > 0 && Data[0] == 'F') bits |= 1;
if (Size > 1 && Data[1] == 'U') bits |= 2;
std::cerr << "BINGO!\n";
exit(1);
}
+ return 0;
}
#include <cstddef>
#include <iostream>
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int bits = 0;
if (Size > 0 && Data[0] == 'F') bits |= 1;
if (Size > 1 && Data[1] == 'U') bits |= 2;
std::cerr << "BINGO!\n";
exit(1);
}
+ return 0;
}
static volatile int One = 1;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size > 0 && Data[0] == 'H') {
Sink = 1;
if (Size > 1 && Data[1] == 'i') {
}
}
}
+ return 0;
}
#include <cstdio>
#include <cstdlib>
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// TODO: check other sizes.
if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) {
if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) {
}
}
}
+ return 0;
}
static volatile int Sink;
static volatile int *Null = 0;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size > 0 && Data[0] == 'H') {
Sink = 1;
if (Size > 1 && Data[1] == 'i') {
}
}
}
+ return 0;
}
#include <cstring>
#include <cstdio>
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- if (Size < 14) return;
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ if (Size < 14) return 0;
uint64_t x = 0;
int64_t y = 0;
int z = 0;
Size, x, y, z, a);
exit(1);
}
+ return 0;
}
static volatile int Zero = 0;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
const char *Expected = "ElvisPresley";
- if (Size < strlen(Expected)) return;
+ if (Size < strlen(Expected)) return 0;
size_t Match = 0;
for (size_t i = 0; Expected[i]; i++)
if (Expected[i] + Zero == Data[i])
std::cout << "BINGO; Found the target, exiting\n";
exit(1);
}
+ return 0;
}
return Hash;
}
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size < 14)
- return;
+ return 0;
uint32_t Hash = simple_hash(&Data[0], Size - 4);
uint32_t Want = reinterpret_cast<const uint32_t *>(&Data[Size - 4])[0];
if (Hash != Want)
- return;
+ return 0;
fprintf(stderr, "BINGO; simple_hash defeated: %x == %x\n", (unsigned int)Hash,
(unsigned int)Want);
exit(1);
+ return 0;
}
static volatile int Sink;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size > 0 && Data[0] == 'H') {
Sink = 1;
if (Size > 1 && Data[1] == 'i') {
}
}
}
+ return 0;
}
return res == 0;
}
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Eq(Data, Size, "AAA") &&
Size >= 3 && Eq(Data + 3, Size - 3, "BBBB") &&
Size >= 7 && Eq(Data + 7, Size - 7, "CCCCCC") &&
fprintf(stderr, "BINGO\n");
exit(1);
}
+ return 0;
}
static volatile int sink;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// TODO: check other sizes.
char *S = (char*)Data;
if (Size >= 8 && strncmp(S, "123", 8))
}
}
}
+ return 0;
}
return false;
}
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size >= 4 && Switch<int>(Data, Size) &&
Size >= 12 && Switch<uint64_t>(Data + 4, Size - 4) &&
Size >= 14 && ShortSwitch(Data + 12, 2)
fprintf(stderr, "BINGO; Found the target, exiting\n");
exit(1);
}
+ return 0;
}
static volatile int Sink;
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size > 0 && Data[0] == 'H') {
Sink = 1;
if (Size > 1 && Data[1] == 'i') {
}
}
}
+ return 0;
}
public:
MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
: fuzzer::UserSuppliedFuzzer(Rand) {}
- void TargetFunction(const uint8_t *Data, size_t Size) {
- if (Size <= 10) return;
- if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
+ int TargetFunction(const uint8_t *Data, size_t Size) {
+ if (Size <= 10) return 0;
+ if (memcmp(Data, &kMagic, sizeof(kMagic))) return 0;
// It's hard to get here w/o advanced fuzzing techniques (e.g. cmp tracing).
// So, we simply 'fix' the data in the custom mutator.
if (Data[8] == 'H') {
}
}
}
+ return 0;
}
// Custom mutator.
virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
} // end of anonymous namespace
-extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// Allocate space for locals before setjmp so that memory can be collected
// if parse exits prematurely (via longjmp).
if (setjmp(JmpBuf))
// If reached, we have returned with non-zero status, so exit.
- return;
+ return 0;
// TODO(kschimpf) Write a main to do this initialization.
if (!InstalledHandler) {
M = parseAssembly(MemBuf->getMemBufferRef(), Err, Context);
if (!M.get())
- return;
+ return 0;
verifyModule(*M.get());
+ return 0;
}
cl::desc("Options to pass to the fuzzer"), cl::ZeroOrMore,
cl::PositionalEatsArgs);
-void DisassembleOneInput(const uint8_t *Data, size_t Size) {
+int DisassembleOneInput(const uint8_t *Data, size_t Size) {
char AssemblyText[AssemblyTextBufSize];
std::vector<uint8_t> DataCopy(Data, Data + Size);
break;
} while (Consumed != 0);
LLVMDisasmDispose(Ctx);
+ return 0;
}
int main(int argc, char **argv) {