From 8d4c8061c9a8d4ca6bf30cd21368073b7d64e136 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 1 Aug 2015 01:42:51 +0000 Subject: [PATCH] [libFuzzer] start refactoring the Mutator and adding tests to it git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243817 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Fuzzer/FuzzerInternal.h | 2 ++ lib/Fuzzer/FuzzerMutate.cpp | 18 +++++++++------ lib/Fuzzer/FuzzerTraceState.cpp | 2 +- lib/Fuzzer/test/FuzzerUnittest.cpp | 36 +++++++++++++++++++++++++++++- lib/Fuzzer/test/fuzzer-dfsan.test | 14 +++++++----- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index fe7869871f0..274fdf077a7 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -33,6 +33,8 @@ void CopyFileToErr(const std::string &Path); std::string DirPlusFile(const std::string &DirPath, const std::string &FileName); +size_t Mutate_EraseByte(uint8_t *Data, size_t size, size_t MaxSize, + FuzzerRandomBase &Rand); size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, FuzzerRandomBase &Rand); diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index 66df98a66f5..eec6475f9b8 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -33,6 +33,16 @@ static char RandCh(FuzzerRandomBase &Rand) { return Special[Rand(sizeof(Special) - 1)]; } +size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand) { + assert(Size); + if (Size == 1) return Size; + size_t Idx = Rand(Size); + // Erase Data[Idx]. + memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1); + return Size - 1; +} + // Mutates Data in place, returns new size. size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, FuzzerRandomBase &Rand) { @@ -46,13 +56,7 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, assert(Size > 0); size_t Idx = Rand(Size); switch (Rand(3)) { - case 0: - if (Size > 1) { - // Erase Data[Idx]. - memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1); - Size = Size - 1; - } - [[clang::fallthrough]]; + case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break; case 1: if (Size < MaxSize) { // Insert new value at Data[Idx]. diff --git a/lib/Fuzzer/FuzzerTraceState.cpp b/lib/Fuzzer/FuzzerTraceState.cpp index f0537c00580..1c01e8aa77b 100644 --- a/lib/Fuzzer/FuzzerTraceState.cpp +++ b/lib/Fuzzer/FuzzerTraceState.cpp @@ -140,7 +140,7 @@ static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1, if (CmpSize == 1) return ComputeCmp(CmpType, Arg1, Arg2); // Other size, == if (CmpType == ICMP_EQ) return Arg1 == Arg2; - assert(0 && "unsupported cmp and type size combination"); + // assert(0 && "unsupported cmp and type size combination"); return true; } diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index ed52a55a507..a159e411404 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -2,6 +2,8 @@ #include "gtest/gtest.h" #include +using namespace fuzzer; + // For now, have LLVMFuzzerTestOneInput just to make it link. // Later we may want to make unittests that actually call LLVMFuzzerTestOneInput. extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { @@ -9,7 +11,6 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { } TEST(Fuzzer, CrossOver) { - using namespace fuzzer; FuzzerRandomLibc Rand(0); Unit A({0, 1, 2}), B({5, 6, 7}); Unit C; @@ -72,3 +73,36 @@ TEST(Fuzzer, Hash) { U.push_back('d'); EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U)); } + +typedef size_t (*Mutator)(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand); + +void TestEraseByte(Mutator M, int NumIter) { + uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77}; + uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77}; + uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77}; + uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; + FuzzerRandomLibc Rand(0); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + size_t NewSize = Mutate_EraseByte(T, sizeof(T), sizeof(T), Rand); + EXPECT_EQ(7UL, NewSize); + if (!memcmp(REM0, T, 7)) FoundMask |= 1 << 0; + if (!memcmp(REM1, T, 7)) FoundMask |= 1 << 1; + if (!memcmp(REM2, T, 7)) FoundMask |= 1 << 2; + if (!memcmp(REM3, T, 7)) FoundMask |= 1 << 3; + if (!memcmp(REM4, T, 7)) FoundMask |= 1 << 4; + if (!memcmp(REM5, T, 7)) FoundMask |= 1 << 5; + if (!memcmp(REM6, T, 7)) FoundMask |= 1 << 6; + if (!memcmp(REM7, T, 7)) FoundMask |= 1 << 7; + } + EXPECT_EQ(FoundMask, 255); +} + +TEST(FuzzerMutate, EraseByte1) { TestEraseByte(Mutate_EraseByte, 50); } +TEST(FuzzerMutate, EraseByte2) { TestEraseByte(Mutate, 100); } diff --git a/lib/Fuzzer/test/fuzzer-dfsan.test b/lib/Fuzzer/test/fuzzer-dfsan.test index c9d00f1d950..266cb51a594 100644 --- a/lib/Fuzzer/test/fuzzer-dfsan.test +++ b/lib/Fuzzer/test/fuzzer-dfsan.test @@ -1,15 +1,19 @@ -CHECK: BINGO +CHECK1: BINGO +CHECK2: BINGO +CHECK3: BINGO +CHECK4: BINGO + CHECK_DFSanCmpCallback: DFSanCmpCallback: PC CHECK_DFSanSwitchCallback: DFSanSwitchCallback: PC -RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK1 RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback -RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=1000 -timeout=5 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=1000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2 RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback -RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3 RUN: LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback -RUN: not LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=100000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK4 RUN: LLVMFuzzer-SwitchTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanSwitchCallback