blob: c5a339c15e634ba919843666a6b4d822e3765a40 [file] [edit]
//===-- allocator_fuzzer.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#define SCUDO_FUZZ
#include "allocator_config.h"
#include "combined.h"
#include <fuzzer/FuzzedDataProvider.h>
#include <vector>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
using AllocatorT = scudo::Allocator<scudo::Config>;
static AllocatorT *Instance = []() {
auto *A = new AllocatorT();
A->init();
// The way we are using the allocator doesn't work properly with MTE
// enabled.
if (scudo::systemSupportsMemoryTagging())
A->disableMemoryTagging();
return A;
}();
FuzzedDataProvider FDP(Data, Size);
std::vector<void *> Allocations;
Instance->setOption(scudo::Option::ReleaseInterval, 1000);
constexpr size_t kMaxAllocatedBytes = 50 * 1024 * 1024;
size_t TotalAllocatedBytes = 0;
while (FDP.remaining_bytes() > 0) {
uint8_t Op = FDP.ConsumeIntegralInRange<uint8_t>(0, 4);
if ((Op == 0 || Op == 1) && TotalAllocatedBytes < kMaxAllocatedBytes) {
size_t ReqSize =
FDP.ConsumeIntegralInRange<size_t>(1, 1 << 20); // Up to 1MB
void *Ptr;
if (Op == 0) {
// Allocate no alignment
Ptr = Instance->allocate(ReqSize, scudo::Chunk::Origin::Malloc);
} else {
// Allocate with alignment
size_t Alignment =
1 << FDP.ConsumeIntegralInRange<size_t>(4, 12); // 16 to 4096
Ptr = Instance->allocate(ReqSize, scudo::Chunk::Origin::Memalign,
Alignment);
CHECK_EQ(0, reinterpret_cast<uintptr_t>(Ptr) & (Alignment - 1));
}
CHECK(Ptr != nullptr);
size_t Size = Instance->getUsableSize(Ptr);
TotalAllocatedBytes += Size;
Allocations.push_back(Ptr);
memset(Ptr, 0xff, Size);
} else if (Op == 2 && !Allocations.empty()) {
// Deallocate
size_t Index =
FDP.ConsumeIntegralInRange<size_t>(0, Allocations.size() - 1);
TotalAllocatedBytes -= Instance->getUsableSize(Allocations[Index]);
Instance->deallocate(Allocations[Index], scudo::Chunk::Origin::Malloc);
Allocations.erase(Allocations.begin() + Index);
} else if (Op == 3 && !Allocations.empty()) {
// Reallocate (Assumes reallocate of a memalign does not crash).
size_t Index =
FDP.ConsumeIntegralInRange<size_t>(0, Allocations.size() - 1);
size_t OldSize = Instance->getUsableSize(Allocations[Index]);
TotalAllocatedBytes -= OldSize;
size_t NewSize = FDP.ConsumeIntegralInRange<size_t>(1, 1 << 20);
void *NewPtr = Instance->reallocate(Allocations[Index], NewSize);
if (NewSize == 0) {
CHECK(NewPtr == nullptr);
Allocations.erase(Allocations.begin() + Index);
} else {
CHECK(NewPtr != nullptr);
size_t Size = Instance->getUsableSize(NewPtr);
memset(NewPtr, 0xff, Size);
Allocations[Index] = NewPtr;
TotalAllocatedBytes -= Size;
}
} else if (Op == 4) {
// ReleaseToOS
scudo::ReleaseToOS ReleaseType =
static_cast<scudo::ReleaseToOS>(FDP.ConsumeIntegralInRange<size_t>(
0, static_cast<size_t>(scudo::ReleaseToOS::Last)));
Instance->releaseToOS(ReleaseType);
}
}
// Cleanup remaining
for (void *Ptr : Allocations) {
Instance->deallocate(Ptr, scudo::Chunk::Origin::Malloc);
}
return 0;
}