Skip to content

Commit 50921a2

Browse files
committed
[FuzzMutate] Fix a bug in connectToSink which might invalidate the whole module.
`connectToSink` uses a value by putting it in a future instruction. It will replace the operand of a future instruction with the current value. However, if current value is an `Instruction` and put into a switch case, the module is invalid. We fix that by only connecting to Br/Switch's condition, and don't touch other operands. Will have other strategies to mutate other Br/Switch operands to be patched once this patch is passed Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D138890
1 parent 21d9f72 commit 50921a2

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

llvm/lib/FuzzMutate/RandomIRBuilder.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Value *RandomIRBuilder::newSource(BasicBlock &BB, ArrayRef<Instruction *> Insts,
7272

7373
static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
7474
const Value *Replacement) {
75+
unsigned int OperandNo = Operand.getOperandNo();
7576
if (Operand->getType() != Replacement->getType())
7677
return false;
7778
switch (I->getOpcode()) {
@@ -80,13 +81,21 @@ static bool isCompatibleReplacement(const Instruction *I, const Use &Operand,
8081
case Instruction::ExtractValue:
8182
// TODO: We could potentially validate these, but for now just leave indices
8283
// alone.
83-
if (Operand.getOperandNo() >= 1)
84+
if (OperandNo >= 1)
8485
return false;
8586
break;
8687
case Instruction::InsertValue:
8788
case Instruction::InsertElement:
8889
case Instruction::ShuffleVector:
89-
if (Operand.getOperandNo() >= 2)
90+
if (OperandNo >= 2)
91+
return false;
92+
break;
93+
// For Br/Switch, we only try to modify the 1st Operand (condition).
94+
// Modify other operands, like switch case may accidently change case from
95+
// ConstantInt to a register, which is illegal.
96+
case Instruction::Switch:
97+
case Instruction::Br:
98+
if (OperandNo >= 1)
9099
return false;
91100
break;
92101
default:

llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/FuzzMutate/IRMutator.h"
1414
#include "llvm/FuzzMutate/OpDescriptor.h"
1515
#include "llvm/FuzzMutate/Operations.h"
16+
#include "llvm/FuzzMutate/Random.h"
1617
#include "llvm/IR/Constants.h"
1718
#include "llvm/IR/Instructions.h"
1819
#include "llvm/IR/LLVMContext.h"
@@ -292,4 +293,49 @@ TEST(RandomIRBuilderTest, SwiftError) {
292293
}
293294
}
294295

296+
TEST(RandomIRBuilderTest, dontConnectToSwitch) {
297+
// Check that we never put anything into switch's case branch
298+
// If we accidently put a variable, the module is invalid.
299+
LLVMContext Ctx;
300+
const char *SourceCode = "\n\
301+
define void @test(i1 %C1, i1 %C2, i32 %I, i32 %J) { \n\
302+
Entry: \n\
303+
%I.1 = add i32 %I, 42 \n\
304+
%J.1 = add i32 %J, 42 \n\
305+
%IJ = add i32 %I, %J \n\
306+
switch i32 %I, label %Default [ \n\
307+
i32 1, label %OnOne \n\
308+
] \n\
309+
Default: \n\
310+
%CIEqJ = icmp eq i32 %I.1, %J.1 \n\
311+
%CISltJ = icmp slt i32 %I.1, %J.1 \n\
312+
%CAnd = and i1 %C1, %C2 \n\
313+
br i1 %CIEqJ, label %Default, label %Exit \n\
314+
OnOne: \n\
315+
br i1 %C1, label %OnOne, label %Exit \n\
316+
Exit: \n\
317+
ret void \n\
318+
}";
319+
320+
std::vector<Type *> Types = {Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)};
321+
RandomIRBuilder IB(Seed, Types);
322+
for (int i = 0; i < 20; i++) {
323+
std::unique_ptr<Module> M = parseAssembly(SourceCode, Ctx);
324+
Function &F = *M->getFunction("test");
325+
auto RS = makeSampler(IB.Rand, make_pointer_range(F));
326+
BasicBlock *BB = RS.getSelection();
327+
SmallVector<Instruction *, 32> Insts;
328+
for (auto I = BB->getFirstInsertionPt(), E = BB->end(); I != E; ++I)
329+
Insts.push_back(&*I);
330+
if (Insts.size() < 2)
331+
continue;
332+
// Choose an instruction and connect to later operations.
333+
size_t IP = uniform<size_t>(IB.Rand, 1, Insts.size() - 1);
334+
Instruction *Inst = Insts[IP - 1];
335+
auto ConnectAfter = makeArrayRef(Insts).slice(IP);
336+
IB.connectToSink(*BB, ConnectAfter, Inst);
337+
ASSERT_FALSE(verifyModule(*M, &errs()));
338+
}
339+
}
340+
295341
} // namespace

0 commit comments

Comments
 (0)