// Mutates Data in place, returns new size. size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, const std::vector<Mutator> &Mutators) { assert(MaxSize > 0); if (Size == 0) { for (size_t i = 0; i < MaxSize; i++) Data[i] = RandCh(Rand); if (Options.OnlyASCII) ToASCII(Data, MaxSize); return MaxSize; } assert(Size > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 100; Iter++) { auto M = Mutators[Rand(Mutators.size())]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize && NewSize <= MaxSize) { if (Options.OnlyASCII) ToASCII(Data, NewSize); CurrentMutatorSequence.push_back(M); return NewSize; } } return std::min(Size, MaxSize); }
size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize) { if (Size > MaxSize) return 0; size_t Idx = Rand(Size); Data[Idx] = RandCh(Rand); return Size; }
size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize) { if (Size == MaxSize) return 0; size_t Idx = Rand(Size + 1); // Insert new value at Data[Idx]. memmove(Data + Idx + 1, Data + Idx, Size - Idx); Data[Idx] = RandCh(Rand); return Size + 1; }
size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize, FuzzerRandomBase &Rand) { if (Size == MaxSize) return Size; size_t Idx = Rand(Size + 1); // Insert new value at Data[Idx]. memmove(Data + Idx + 1, Data + Idx, Size - Idx); Data[Idx] = RandCh(Rand); return Size + 1; }
// Mutates Data in place, returns new size. size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, FuzzerRandomBase &Rand) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { for (size_t i = 0; i < MaxSize; i++) Data[i] = RandCh(Rand); return MaxSize; } assert(Size > 0); switch (Rand(4)) { 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; } assert(Size > 0); return Size; }
// Mutates Data in place, returns new size. size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { for (size_t i = 0; i < MaxSize; i++) Data[i] = RandCh(Rand); return MaxSize; } assert(Size > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 10; Iter++) { size_t MutatorIdx = Rand(MDImpl->Mutators.size()); auto M = MDImpl->Mutators[MutatorIdx]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize) { MDImpl->CurrentMutatorSequence.push_back(M); return NewSize; } } return Size; }
size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize, FuzzerRandomBase &Rand) { size_t Idx = Rand(Size); Data[Idx] = RandCh(Rand); return Size; }