Skip to content

Commit

Permalink
[MemoryBuiltins] Allow truncation in visitAllocaInst()
Browse files Browse the repository at this point in the history
Summary:
Solves PR33689.

If the pointer size is less than the size of the type used for the array
size in an alloca (the <ty> type below) then we could trigger the assert in
the PR. In that example we have pointer size i16 and <ty> is i32.

<result> = alloca [inalloca] <type> [, <ty> <NumElements>] [, align <alignment>]

Handle the situation by allowing truncation as well as zero extension in
ObjectSizeOffsetVisitor::visitAllocaInst().

Also, we now detect overflow in visitAllocaInst(), similar to how it was
already done in visitCallSite().

Reviewers: craig.topper, rnk, george.burgess.iv

Reviewed By: george.burgess.iv

Subscribers: davide, llvm-commits

Differential Revision: https://reviews.llvm.org/D35003

llvm-svn: 307754
  • Loading branch information
mikaelholmen committed Jul 12, 2017
1 parent e970c2b commit ad7e718
Showing 2 changed files with 27 additions and 17 deletions.
3 changes: 3 additions & 0 deletions llvm/include/llvm/Analysis/MemoryBuiltins.h
Original file line number Diff line number Diff line change
@@ -224,6 +224,9 @@ class ObjectSizeOffsetVisitor
SizeOffsetType visitSelectInst(SelectInst &I);
SizeOffsetType visitUndefValue(UndefValue&);
SizeOffsetType visitInstruction(Instruction &I);

private:
bool CheckedZextOrTrunc(APInt &I);
};

typedef std::pair<Value*, Value*> SizeOffsetEvalType;
41 changes: 24 additions & 17 deletions llvm/lib/Analysis/MemoryBuiltins.cpp
Original file line number Diff line number Diff line change
@@ -505,6 +505,22 @@ SizeOffsetType ObjectSizeOffsetVisitor::compute(Value *V) {
return unknown();
}

/// When we're compiling N-bit code, and the user uses parameters that are
/// greater than N bits (e.g. uint64_t on a 32-bit build), we can run into
/// trouble with APInt size issues. This function handles resizing + overflow
/// checks for us. Check and zext or trunc \p I depending on IntTyBits and
/// I's value.
bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) {
// More bits than we can handle. Checking the bit width isn't necessary, but
// it's faster than checking active bits, and should give `false` in the
// vast majority of cases.
if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)
return false;
if (I.getBitWidth() != IntTyBits)
I = I.zextOrTrunc(IntTyBits);
return true;
}

SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) {
if (!I.getAllocatedType()->isSized())
return unknown();
@@ -515,8 +531,14 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) {

Value *ArraySize = I.getArraySize();
if (const ConstantInt *C = dyn_cast<ConstantInt>(ArraySize)) {
Size *= C->getValue().zextOrSelf(IntTyBits);
return std::make_pair(align(Size, I.getAlignment()), Zero);
APInt NumElems = C->getValue();
if (!CheckedZextOrTrunc(NumElems))
return unknown();

bool Overflow;
Size = Size.umul_ov(NumElems, Overflow);
return Overflow ? unknown() : std::make_pair(align(Size, I.getAlignment()),
Zero);
}
return unknown();
}
@@ -561,21 +583,6 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitCallSite(CallSite CS) {
if (!Arg)
return unknown();

// When we're compiling N-bit code, and the user uses parameters that are
// greater than N bits (e.g. uint64_t on a 32-bit build), we can run into
// trouble with APInt size issues. This function handles resizing + overflow
// checks for us.
auto CheckedZextOrTrunc = [&](APInt &I) {
// More bits than we can handle. Checking the bit width isn't necessary, but
// it's faster than checking active bits, and should give `false` in the
// vast majority of cases.
if (I.getBitWidth() > IntTyBits && I.getActiveBits() > IntTyBits)
return false;
if (I.getBitWidth() != IntTyBits)
I = I.zextOrTrunc(IntTyBits);
return true;
};

APInt Size = Arg->getValue();
if (!CheckedZextOrTrunc(Size))
return unknown();

0 comments on commit ad7e718

Please sign in to comment.