diff options
Diffstat (limited to 'llvm/lib/Fuzzer')
-rw-r--r-- | llvm/lib/Fuzzer/FuzzerInternal.h | 6 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/FuzzerMutate.cpp | 36 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/FuzzerUnittest.cpp | 74 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/RepeatedBytesTest.cpp | 29 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/StrcmpTest.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/fuzzer-traces.test | 5 | ||||
-rw-r--r-- | llvm/lib/Fuzzer/test/repeated-bytes.test | 2 |
8 files changed, 139 insertions, 20 deletions
diff --git a/llvm/lib/Fuzzer/FuzzerInternal.h b/llvm/lib/Fuzzer/FuzzerInternal.h index 5f0574ae..61f4866 100644 --- a/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/llvm/lib/Fuzzer/FuzzerInternal.h @@ -255,10 +255,12 @@ public: size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by shuffling bytes. size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); - /// Mutates data by erasing a byte. - size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by erasing bytes. + size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by inserting a byte. size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting several repeated bytes. + size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by chanding one byte. size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by chanding one bit. diff --git a/llvm/lib/Fuzzer/FuzzerMutate.cpp b/llvm/lib/Fuzzer/FuzzerMutate.cpp index 65e1650..05ea39d 100644 --- a/llvm/lib/Fuzzer/FuzzerMutate.cpp +++ b/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -24,8 +24,10 @@ MutationDispatcher::MutationDispatcher(Random &Rand, DefaultMutators.insert( DefaultMutators.begin(), { - {&MutationDispatcher::Mutate_EraseByte, "EraseByte"}, + {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_InsertRepeatedBytes, + "InsertRepeatedBytes"}, {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, @@ -103,14 +105,17 @@ size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, return Size; } -size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size, - size_t MaxSize) { +size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, + size_t MaxSize) { assert(Size); if (Size == 1) return 0; - size_t Idx = Rand(Size); - // Erase Data[Idx]. - memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1); - return Size - 1; + size_t N = Rand(Size / 2) + 1; + assert(N < Size); + size_t Idx = Rand(Size - N + 1); + // Erase Data[Idx:Idx+N]. + memmove(Data + Idx, Data + Idx + N, Size - Idx - N); + // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); + return Size - N; } size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, @@ -123,6 +128,23 @@ size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, return Size + 1; } +size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, + size_t Size, + size_t MaxSize) { + const size_t kMinBytesToInsert = 3; + if (Size + kMinBytesToInsert >= MaxSize) return 0; + size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); + size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; + assert(Size + N <= MaxSize && N); + size_t Idx = Rand(Size + 1); + // Insert new values at Data[Idx]. + memmove(Data + Idx + N, Data + Idx, Size - Idx); + uint8_t Byte = RandCh(Rand); + for (size_t i = 0; i < N; i++) + Data[Idx + i] = Byte; + return Size + N; +} + size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize) { size_t Idx = Rand(Size); diff --git a/llvm/lib/Fuzzer/test/CMakeLists.txt b/llvm/lib/Fuzzer/test/CMakeLists.txt index cbc983e..2164086 100644 --- a/llvm/lib/Fuzzer/test/CMakeLists.txt +++ b/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -81,6 +81,7 @@ set(Tests OneHugeAllocTest OutOfMemoryTest RepeatedMemcmp + RepeatedBytesTest SimpleCmpTest SimpleDictionaryTest SimpleFnAdapterTest diff --git a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp index 3fd87e5..bcbd116 100644 --- a/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -88,7 +88,7 @@ TEST(Fuzzer, Hash) { typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, size_t MaxSize); -void TestEraseByte(Mutator M, int NumIter) { +void TestEraseBytes(Mutator M, int NumIter) { std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); fuzzer::EF = t.get(); uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -99,6 +99,16 @@ void TestEraseByte(Mutator M, int NumIter) { 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}; + + uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; + uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77}; + + uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77}; + uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44}; + uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77}; + + Random Rand(0); MutationDispatcher MD(Rand, {}); int FoundMask = 0; @@ -113,15 +123,23 @@ void TestEraseByte(Mutator M, int NumIter) { if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5; if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6; if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7; + + if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8; + if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9; + if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10; + + if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11; + if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12; + if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13; } - EXPECT_EQ(FoundMask, 255); + EXPECT_EQ(FoundMask, (1 << 14) - 1); } -TEST(FuzzerMutate, EraseByte1) { - TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100); +TEST(FuzzerMutate, EraseBytes1) { + TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200); } -TEST(FuzzerMutate, EraseByte2) { - TestEraseByte(&MutationDispatcher::Mutate, 1000); +TEST(FuzzerMutate, EraseBytes2) { + TestEraseBytes(&MutationDispatcher::Mutate, 2000); } void TestInsertByte(Mutator M, int NumIter) { @@ -160,6 +178,50 @@ TEST(FuzzerMutate, InsertByte2) { TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); } +void TestInsertRepeatedBytes(Mutator M, int NumIter) { + std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); + fuzzer::EF = t.get(); + Random Rand(0); + MutationDispatcher MD(Rand, {}); + int FoundMask = 0; + uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'}; + uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33}; + uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33}; + uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33}; + uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33}; + + uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'}; + uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33}; + uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33}; + uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33}; + uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33}; + + for (int i = 0; i < NumIter; i++) { + uint8_t T[8] = {0x00, 0x11, 0x22, 0x33}; + size_t NewSize = (MD.*M)(T, 4, 8); + if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0; + if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1; + if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2; + if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3; + if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4; + + if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; + if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; + if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; + if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8; + if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9; + + } + EXPECT_EQ(FoundMask, (1 << 10) - 1); +} + +TEST(FuzzerMutate, InsertRepeatedBytes1) { + TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000); +} +TEST(FuzzerMutate, InsertRepeatedBytes2) { + TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 200000); +} + void TestChangeByte(Mutator M, int NumIter) { std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); fuzzer::EF = t.get(); diff --git a/llvm/lib/Fuzzer/test/RepeatedBytesTest.cpp b/llvm/lib/Fuzzer/test/RepeatedBytesTest.cpp new file mode 100644 index 0000000..2fa6c78 --- /dev/null +++ b/llvm/lib/Fuzzer/test/RepeatedBytesTest.cpp @@ -0,0 +1,29 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Simple test for a fuzzer. The fuzzer must find repeated bytes. +#include <assert.h> +#include <cstdint> +#include <cstdlib> +#include <cstddef> +#include <iostream> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + // Looking for AAAAAAAAAAAAAAAAAAAAAA or some such. + size_t CurA = 0, MaxA = 0; + for (size_t i = 0; i < Size; i++) { + // Make sure there are no conditionals in the loop so that + // coverage can't help the fuzzer. + int EQ = Data[i] == 'A'; + CurA = EQ * (CurA + 1); + int GT = CurA > MaxA; + MaxA = GT * CurA + (!GT) * MaxA; + } + if (MaxA >= 20) { + std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n"; + exit(0); + } + return 0; +} + diff --git a/llvm/lib/Fuzzer/test/StrcmpTest.cpp b/llvm/lib/Fuzzer/test/StrcmpTest.cpp index 5a13299..cd91dda 100644 --- a/llvm/lib/Fuzzer/test/StrcmpTest.cpp +++ b/llvm/lib/Fuzzer/test/StrcmpTest.cpp @@ -20,9 +20,9 @@ bool Eq(const uint8_t *Data, size_t Size, const char *Str) { } 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") && + if (Eq(Data, Size, "ABC") && + Size >= 3 && Eq(Data + 3, Size - 3, "QWER") && + Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") && Size >= 14 && Data[13] == 42 ) { fprintf(stderr, "BINGO\n"); diff --git a/llvm/lib/Fuzzer/test/fuzzer-traces.test b/llvm/lib/Fuzzer/test/fuzzer-traces.test index 2d77295..13f82ca 100644 --- a/llvm/lib/Fuzzer/test/fuzzer-traces.test +++ b/llvm/lib/Fuzzer/test/fuzzer-traces.test @@ -1,9 +1,10 @@ CHECK: BINGO Done1000000: Done 1000000 runs in +Done2000000: Done 2000000 runs in RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=10000001 2>&1 | FileCheck %s RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=6 -runs=1000002 2>&1 | FileCheck %s RUN: LLVMFuzzer-SwitchTest -seed=7 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 -RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=8 -runs=1000000 -max_len=16 2>&1 | FileCheck %s -RUN: LLVMFuzzer-SimpleHashTest -seed=9 -runs=1000000 -max_len=16 2>&1 | FileCheck %s --check-prefix=Done1000000 +RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=8 -runs=2000000 -max_len=16 2>&1 | FileCheck %s +RUN: LLVMFuzzer-SimpleHashTest -seed=9 -runs=2000000 -max_len=16 2>&1 | FileCheck %s --check-prefix=Done2000000 diff --git a/llvm/lib/Fuzzer/test/repeated-bytes.test b/llvm/lib/Fuzzer/test/repeated-bytes.test new file mode 100644 index 0000000..edcba83 --- /dev/null +++ b/llvm/lib/Fuzzer/test/repeated-bytes.test @@ -0,0 +1,2 @@ +CHECK: BINGO +RUN: LLVMFuzzer-RepeatedBytesTest -runs=10000 2>&1 | FileCheck %s |