From: Kostya Serebryany Date: Thu, 3 Sep 2015 21:24:19 +0000 (+0000) Subject: [libFuzzer] refactor the mutation functions so that they are now methods of a class... X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=bf6bd487d5bd3f8066fa6e5076d7de3988b4be76 [libFuzzer] refactor the mutation functions so that they are now methods of a class. NFC git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246808 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Fuzzer/FuzzerCrossOver.cpp b/lib/Fuzzer/FuzzerCrossOver.cpp index 8b13698b5ae..5203deaf912 100644 --- a/lib/Fuzzer/FuzzerCrossOver.cpp +++ b/lib/Fuzzer/FuzzerCrossOver.cpp @@ -16,9 +16,9 @@ namespace fuzzer { // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. -size_t CrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) { +size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize) { assert(Size1 || Size2); MaxOutSize = Rand(MaxOutSize) + 1; size_t OutPos = 0; diff --git a/lib/Fuzzer/FuzzerInterface.cpp b/lib/Fuzzer/FuzzerInterface.cpp index 5df182ec595..231e757c8b2 100644 --- a/lib/Fuzzer/FuzzerInterface.cpp +++ b/lib/Fuzzer/FuzzerInterface.cpp @@ -20,9 +20,10 @@ void FuzzerRandomLibc::ResetSeed(int seed) { srand(seed); } size_t FuzzerRandomLibc::Rand() { return rand(); } UserSuppliedFuzzer::UserSuppliedFuzzer() - : OwnRand(true), Rand(new FuzzerRandomLibc(0)) {} + : OwnRand(true), Rand(new FuzzerRandomLibc(0)), MD(*Rand) {} -UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) : Rand(Rand) {} +UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) + : Rand(Rand), MD(*Rand) {} UserSuppliedFuzzer::~UserSuppliedFuzzer() { if (OwnRand) diff --git a/lib/Fuzzer/FuzzerInterface.h b/lib/Fuzzer/FuzzerInterface.h index c4582d61f1a..d3843a47d1c 100644 --- a/lib/Fuzzer/FuzzerInterface.h +++ b/lib/Fuzzer/FuzzerInterface.h @@ -62,33 +62,38 @@ class FuzzerRandomLibc : public FuzzerRandomBase { size_t Rand() override; }; +class MutationDispatcher { + public: + MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {} + /// 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 inserting a byte. + size_t Mutate_InsertByte(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. + size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Applies one of the above mutations. + /// Returns the new size of data which could be up to MaxSize. + size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Creates a cross-over of two pieces of Data, returns its size. + size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, + size_t Size2, uint8_t *Out, size_t MaxOutSize); -/// Mutates data by shuffling bytes. -size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); -/// Mutates data by erasing a byte. -size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); -/// Mutates data by inserting a byte. -size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); -/// Mutates data by chanding one byte. -size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); -/// Mutates data by chanding one bit. -size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); - -/// Applies one of the above mutations. -/// Returns the new size of data which could be up to MaxSize. -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); - -/// Creates a cross-over of two pieces of Data, returns its size. -size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, - size_t Size2, uint8_t *Out, size_t MaxOutSize, - FuzzerRandomBase &Rand); + private: + FuzzerRandomBase &Rand; +}; +// For backward compatibility only, deprecated. +static inline size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand) { + MutationDispatcher MD(Rand); + return MD.Mutate(Data, Size, MaxSize); +} /** An abstract class that allows to use user-supplied mutators with libFuzzer. @@ -122,15 +127,14 @@ class UserSuppliedFuzzer { /// 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) { - return ::fuzzer::Mutate(Data, Size, MaxSize, GetRand()); + return MD.Mutate(Data, Size, MaxSize); } /// Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out, /// returns the number of bytes written, which should be positive. virtual size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, size_t Size2, uint8_t *Out, size_t MaxOutSize) { - return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize, - GetRand()); + return MD.CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); } virtual ~UserSuppliedFuzzer(); @@ -139,6 +143,7 @@ class UserSuppliedFuzzer { private: bool OwnRand = false; FuzzerRandomBase *Rand; + MutationDispatcher MD; }; /// Runs the fuzzing with the UserSuppliedFuzzer. diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index c425ae0c1cd..82cee646c06 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -35,8 +35,8 @@ static char RandCh(FuzzerRandomBase &Rand) { return Special[Rand(sizeof(Special) - 1)]; } -size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, + size_t MaxSize) { assert(Size); size_t ShuffleAmount = Rand(std::min(Size, 8UL)) + 1; // [1,8] and <= Size. size_t ShuffleStart = Rand(Size - ShuffleAmount); @@ -46,8 +46,8 @@ size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize, return Size; } -size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size, + size_t MaxSize) { assert(Size); if (Size == 1) return Size; size_t Idx = Rand(Size); @@ -56,8 +56,8 @@ size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize, return Size - 1; } -size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, + size_t MaxSize) { if (Size == MaxSize) return Size; size_t Idx = Rand(Size + 1); // Insert new value at Data[Idx]. @@ -66,23 +66,22 @@ size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize, return Size + 1; } -size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, + size_t MaxSize) { size_t Idx = Rand(Size); Data[Idx] = RandCh(Rand); return Size; } -size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, + size_t MaxSize) { size_t Idx = Rand(Size); Data[Idx] = FlipRandomBit(Data[Idx], Rand); return Size; } // Mutates Data in place, returns new size. -size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand) { +size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { @@ -92,11 +91,11 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, } assert(Size > 0); switch (Rand(5)) { - case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break; - case 1: Size = Mutate_InsertByte(Data, Size, MaxSize, Rand); break; - case 2: Size = Mutate_ChangeByte(Data, Size, MaxSize, Rand); break; - case 3: Size = Mutate_ChangeBit(Data, Size, MaxSize, Rand); break; - case 4: Size = Mutate_ShuffleBytes(Data, Size, MaxSize, Rand); break; + case 0: Size = Mutate_EraseByte(Data, Size, MaxSize); break; + case 1: Size = Mutate_InsertByte(Data, Size, MaxSize); break; + case 2: Size = Mutate_ChangeByte(Data, Size, MaxSize); break; + case 3: Size = Mutate_ChangeBit(Data, Size, MaxSize); break; + case 4: Size = Mutate_ShuffleBytes(Data, Size, MaxSize); break; } assert(Size > 0); return Size; diff --git a/lib/Fuzzer/test/FuzzerUnittest.cpp b/lib/Fuzzer/test/FuzzerUnittest.cpp index a06e0ac4831..f070e4f5924 100644 --- a/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -12,6 +12,7 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { TEST(Fuzzer, CrossOver) { FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); Unit A({0, 1, 2}), B({5, 6, 7}); Unit C; Unit Expected[] = { @@ -54,8 +55,8 @@ TEST(Fuzzer, CrossOver) { std::set FoundUnits, ExpectedUnitsWitThisLength; for (int Iter = 0; Iter < 3000; Iter++) { C.resize(Len); - size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(), - C.data(), C.size(), Rand); + size_t NewSize = MD.CrossOver(A.data(), A.size(), B.data(), B.size(), + C.data(), C.size()); C.resize(NewSize); FoundUnits.insert(C); } @@ -74,8 +75,8 @@ TEST(Fuzzer, Hash) { EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U)); } -typedef size_t (*Mutator)(uint8_t *Data, size_t Size, size_t MaxSize, - FuzzerRandomBase &Rand); +typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, + size_t MaxSize); void TestEraseByte(Mutator M, int NumIter) { uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -87,10 +88,11 @@ void TestEraseByte(Mutator M, int NumIter) { 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); + MutationDispatcher MD(Rand); 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 = M(T, sizeof(T), sizeof(T), Rand); + size_t NewSize = (MD.*M)(T, sizeof(T), sizeof(T)); if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0; if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1; if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2; @@ -103,11 +105,12 @@ void TestEraseByte(Mutator M, int NumIter) { EXPECT_EQ(FoundMask, 255); } -TEST(FuzzerMutate, EraseByte1) { TestEraseByte(Mutate_EraseByte, 100); } -TEST(FuzzerMutate, EraseByte2) { TestEraseByte(Mutate, 1000); } +TEST(FuzzerMutate, EraseByte1) { TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100); } +TEST(FuzzerMutate, EraseByte2) { TestEraseByte(&MutationDispatcher::Mutate, 1000); } void TestInsertByte(Mutator M, int NumIter) { FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; @@ -119,7 +122,7 @@ void TestInsertByte(Mutator M, int NumIter) { uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8}; for (int i = 0; i < NumIter; i++) { uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = M(T, 7, 8, Rand); + size_t NewSize = (MD.*M)(T, 7, 8); if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0; if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1; if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2; @@ -132,11 +135,12 @@ void TestInsertByte(Mutator M, int NumIter) { EXPECT_EQ(FoundMask, 255); } -TEST(FuzzerMutate, InsertByte1) { TestInsertByte(Mutate_InsertByte, 1 << 15); } -TEST(FuzzerMutate, InsertByte2) { TestInsertByte(Mutate, 1 << 17); } +TEST(FuzzerMutate, InsertByte1) { TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15); } +TEST(FuzzerMutate, InsertByte2) { TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); } void TestChangeByte(Mutator M, int NumIter) { FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -148,7 +152,7 @@ void TestChangeByte(Mutator M, int NumIter) { uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; for (int i = 0; i < NumIter; i++) { uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = M(T, 8, 9, Rand); + size_t NewSize = (MD.*M)(T, 8, 9); if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; @@ -161,11 +165,12 @@ void TestChangeByte(Mutator M, int NumIter) { EXPECT_EQ(FoundMask, 255); } -TEST(FuzzerMutate, ChangeByte1) { TestChangeByte(Mutate_ChangeByte, 1 << 15); } -TEST(FuzzerMutate, ChangeByte2) { TestChangeByte(Mutate, 1 << 17); } +TEST(FuzzerMutate, ChangeByte1) { TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15); } +TEST(FuzzerMutate, ChangeByte2) { TestChangeByte(&MutationDispatcher::Mutate, 1 << 17); } void TestChangeBit(Mutator M, int NumIter) { FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -177,7 +182,7 @@ void TestChangeBit(Mutator M, int NumIter) { uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7}; for (int i = 0; i < NumIter; i++) { uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = M(T, 8, 9, Rand); + size_t NewSize = (MD.*M)(T, 8, 9); if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; @@ -190,11 +195,12 @@ void TestChangeBit(Mutator M, int NumIter) { EXPECT_EQ(FoundMask, 255); } -TEST(FuzzerMutate, ChangeBit1) { TestChangeBit(Mutate_ChangeBit, 1 << 16); } -TEST(FuzzerMutate, ChangeBit2) { TestChangeBit(Mutate, 1 << 18); } +TEST(FuzzerMutate, ChangeBit1) { TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16); } +TEST(FuzzerMutate, ChangeBit2) { TestChangeBit(&MutationDispatcher::Mutate, 1 << 18); } void TestShuffleBytes(Mutator M, int NumIter) { FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66}; uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66}; @@ -203,7 +209,7 @@ void TestShuffleBytes(Mutator M, int NumIter) { uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66}; for (int i = 0; i < NumIter; i++) { uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = M(T, 7, 7, Rand); + size_t NewSize = (MD.*M)(T, 7, 7); if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; @@ -213,8 +219,8 @@ void TestShuffleBytes(Mutator M, int NumIter) { EXPECT_EQ(FoundMask, 31); } -TEST(FuzzerMutate, ShuffleBytes1) { TestShuffleBytes(Mutate_ShuffleBytes, 1 << 15); } -TEST(FuzzerMutate, ShuffleBytes2) { TestShuffleBytes(Mutate, 1 << 16); } +TEST(FuzzerMutate, ShuffleBytes1) { TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 15); } +TEST(FuzzerMutate, ShuffleBytes2) { TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 16); } TEST(FuzzerDictionary, ParseOneDictionaryEntry) { Unit U;