123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- //===-- IRMutator.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
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/FuzzMutate/IRMutator.h"
- #include "llvm/ADT/Optional.h"
- #include "llvm/Analysis/TargetLibraryInfo.h"
- #include "llvm/FuzzMutate/Operations.h"
- #include "llvm/FuzzMutate/Random.h"
- #include "llvm/FuzzMutate/RandomIRBuilder.h"
- #include "llvm/IR/BasicBlock.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/InstIterator.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/Module.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Transforms/Scalar/DCE.h"
- using namespace llvm;
- static void createEmptyFunction(Module &M) {
- // TODO: Some arguments and a return value would probably be more interesting.
- LLVMContext &Context = M.getContext();
- Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Context), {},
- /*isVarArg=*/false),
- GlobalValue::ExternalLinkage, "f", &M);
- BasicBlock *BB = BasicBlock::Create(Context, "BB", F);
- ReturnInst::Create(Context, BB);
- }
- void IRMutationStrategy::mutate(Module &M, RandomIRBuilder &IB) {
- if (M.empty())
- createEmptyFunction(M);
- auto RS = makeSampler<Function *>(IB.Rand);
- for (Function &F : M)
- if (!F.isDeclaration())
- RS.sample(&F, /*Weight=*/1);
- mutate(*RS.getSelection(), IB);
- }
- void IRMutationStrategy::mutate(Function &F, RandomIRBuilder &IB) {
- mutate(*makeSampler(IB.Rand, make_pointer_range(F)).getSelection(), IB);
- }
- void IRMutationStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
- mutate(*makeSampler(IB.Rand, make_pointer_range(BB)).getSelection(), IB);
- }
- void IRMutator::mutateModule(Module &M, int Seed, size_t CurSize,
- size_t MaxSize) {
- std::vector<Type *> Types;
- for (const auto &Getter : AllowedTypes)
- Types.push_back(Getter(M.getContext()));
- RandomIRBuilder IB(Seed, Types);
- auto RS = makeSampler<IRMutationStrategy *>(IB.Rand);
- for (const auto &Strategy : Strategies)
- RS.sample(Strategy.get(),
- Strategy->getWeight(CurSize, MaxSize, RS.totalWeight()));
- auto Strategy = RS.getSelection();
- Strategy->mutate(M, IB);
- }
- static void eliminateDeadCode(Function &F) {
- FunctionPassManager FPM;
- FPM.addPass(DCEPass());
- FunctionAnalysisManager FAM;
- FAM.registerPass([&] { return TargetLibraryAnalysis(); });
- FAM.registerPass([&] { return PassInstrumentationAnalysis(); });
- FPM.run(F, FAM);
- }
- void InjectorIRStrategy::mutate(Function &F, RandomIRBuilder &IB) {
- IRMutationStrategy::mutate(F, IB);
- eliminateDeadCode(F);
- }
- std::vector<fuzzerop::OpDescriptor> InjectorIRStrategy::getDefaultOps() {
- std::vector<fuzzerop::OpDescriptor> Ops;
- describeFuzzerIntOps(Ops);
- describeFuzzerFloatOps(Ops);
- describeFuzzerControlFlowOps(Ops);
- describeFuzzerPointerOps(Ops);
- describeFuzzerAggregateOps(Ops);
- describeFuzzerVectorOps(Ops);
- return Ops;
- }
- Optional<fuzzerop::OpDescriptor>
- InjectorIRStrategy::chooseOperation(Value *Src, RandomIRBuilder &IB) {
- auto OpMatchesPred = [&Src](fuzzerop::OpDescriptor &Op) {
- return Op.SourcePreds[0].matches({}, Src);
- };
- auto RS = makeSampler(IB.Rand, make_filter_range(Operations, OpMatchesPred));
- if (RS.isEmpty())
- return None;
- return *RS;
- }
- void InjectorIRStrategy::mutate(BasicBlock &BB, RandomIRBuilder &IB) {
- SmallVector<Instruction *, 32> Insts;
- for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
- Insts.push_back(&*I);
- if (Insts.size() < 1)
- return;
- // Choose an insertion point for our new instruction.
- size_t IP = uniform<size_t>(IB.Rand, 0, Insts.size() - 1);
- auto InstsBefore = makeArrayRef(Insts).slice(0, IP);
- auto InstsAfter = makeArrayRef(Insts).slice(IP);
- // Choose a source, which will be used to constrain the operation selection.
- SmallVector<Value *, 2> Srcs;
- Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore));
- // Choose an operation that's constrained to be valid for the type of the
- // source, collect any other sources it needs, and then build it.
- auto OpDesc = chooseOperation(Srcs[0], IB);
- // Bail if no operation was found
- if (!OpDesc)
- return;
- for (const auto &Pred : makeArrayRef(OpDesc->SourcePreds).slice(1))
- Srcs.push_back(IB.findOrCreateSource(BB, InstsBefore, Srcs, Pred));
- if (Value *Op = OpDesc->BuilderFunc(Srcs, Insts[IP])) {
- // Find a sink and wire up the results of the operation.
- IB.connectToSink(BB, InstsAfter, Op);
- }
- }
- uint64_t InstDeleterIRStrategy::getWeight(size_t CurrentSize, size_t MaxSize,
- uint64_t CurrentWeight) {
- // If we have less than 200 bytes, panic and try to always delete.
- if (CurrentSize > MaxSize - 200)
- return CurrentWeight ? CurrentWeight * 100 : 1;
- // Draw a line starting from when we only have 1k left and increasing linearly
- // to double the current weight.
- int64_t Line = (-2 * static_cast<int64_t>(CurrentWeight)) *
- (static_cast<int64_t>(MaxSize) -
- static_cast<int64_t>(CurrentSize) - 1000) /
- 1000;
- // Clamp negative weights to zero.
- if (Line < 0)
- return 0;
- return Line;
- }
- void InstDeleterIRStrategy::mutate(Function &F, RandomIRBuilder &IB) {
- auto RS = makeSampler<Instruction *>(IB.Rand);
- for (Instruction &Inst : instructions(F)) {
- // TODO: We can't handle these instructions.
- if (Inst.isTerminator() || Inst.isEHPad() ||
- Inst.isSwiftError() || isa<PHINode>(Inst))
- continue;
- RS.sample(&Inst, /*Weight=*/1);
- }
- if (RS.isEmpty())
- return;
- // Delete the instruction.
- mutate(*RS.getSelection(), IB);
- // Clean up any dead code that's left over after removing the instruction.
- eliminateDeadCode(F);
- }
- void InstDeleterIRStrategy::mutate(Instruction &Inst, RandomIRBuilder &IB) {
- assert(!Inst.isTerminator() && "Deleting terminators invalidates CFG");
- if (Inst.getType()->isVoidTy()) {
- // Instructions with void type (ie, store) have no uses to worry about. Just
- // erase it and move on.
- Inst.eraseFromParent();
- return;
- }
- // Otherwise we need to find some other value with the right type to keep the
- // users happy.
- auto Pred = fuzzerop::onlyType(Inst.getType());
- auto RS = makeSampler<Value *>(IB.Rand);
- SmallVector<Instruction *, 32> InstsBefore;
- BasicBlock *BB = Inst.getParent();
- for (auto I = BB->getFirstInsertionPt(), E = Inst.getIterator(); I != E;
- ++I) {
- if (Pred.matches({}, &*I))
- RS.sample(&*I, /*Weight=*/1);
- InstsBefore.push_back(&*I);
- }
- if (!RS)
- RS.sample(IB.newSource(*BB, InstsBefore, {}, Pred), /*Weight=*/1);
- Inst.replaceAllUsesWith(RS.getSelection());
- Inst.eraseFromParent();
- }
- void InstModificationIRStrategy::mutate(Instruction &Inst,
- RandomIRBuilder &IB) {
- SmallVector<std::function<void()>, 8> Modifications;
- CmpInst *CI = nullptr;
- GetElementPtrInst *GEP = nullptr;
- switch (Inst.getOpcode()) {
- default:
- break;
- case Instruction::Add:
- case Instruction::Mul:
- case Instruction::Sub:
- case Instruction::Shl:
- Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); }),
- Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); });
- Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(true); });
- Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(false); });
- break;
- case Instruction::ICmp:
- CI = cast<ICmpInst>(&Inst);
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_EQ); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_NE); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGT); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_UGE); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULT); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_ULE); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGT); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SGE); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLT); });
- Modifications.push_back([CI]() { CI->setPredicate(CmpInst::ICMP_SLE); });
- break;
- case Instruction::GetElementPtr:
- GEP = cast<GetElementPtrInst>(&Inst);
- Modifications.push_back([GEP]() { GEP->setIsInBounds(true); });
- Modifications.push_back([GEP]() { GEP->setIsInBounds(false); });
- break;
- }
- auto RS = makeSampler(IB.Rand, Modifications);
- if (RS)
- RS.getSelection()();
- }
|