aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis/MemoryBuiltins.cpp
diff options
context:
space:
mode:
authorserge-sans-paille <sguelton@mozilla.com>2024-11-18 07:39:04 +0000
committerGitHub <noreply@github.com>2024-11-18 07:39:04 +0000
commit1dcb3db0ac1255bf556bf6b62d03a113bd5191d8 (patch)
tree2dfc2d0c446e2797fd649b9bfa64ea1aa449b9be /llvm/lib/Analysis/MemoryBuiltins.cpp
parentb4c0ef18226b7d1f82d71fc0171b99caec0d8d12 (diff)
downloadllvm-1dcb3db0ac1255bf556bf6b62d03a113bd5191d8.zip
llvm-1dcb3db0ac1255bf556bf6b62d03a113bd5191d8.tar.gz
llvm-1dcb3db0ac1255bf556bf6b62d03a113bd5191d8.tar.bz2
[llvm] Fix behavior of llvm.objectsize in presence of negative / large offset (#115504)
The internal structure used to carry intermediate computations hold signed values. If an object size happens to overflow signed values, we can get invalid result, so make sure this situation never happens. This is not very limitative as static allocation of such large values should scarcely happen.
Diffstat (limited to 'llvm/lib/Analysis/MemoryBuiltins.cpp')
-rw-r--r--llvm/lib/Analysis/MemoryBuiltins.cpp53
1 files changed, 45 insertions, 8 deletions
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index d9769c4..cd8594d 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -564,8 +564,13 @@ Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
static APInt getSizeWithOverflow(const SizeOffsetAPInt &Data) {
APInt Size = Data.Size;
APInt Offset = Data.Offset;
- if (Offset.isNegative() || Size.ult(Offset))
- return APInt(Size.getBitWidth(), 0);
+
+ assert(!Offset.isNegative() &&
+ "size for a pointer before the allocated object is ambiguous");
+
+ if (Size.ult(Offset))
+ return APInt::getZero(Size.getBitWidth());
+
return Size - Offset;
}
@@ -668,10 +673,14 @@ STATISTIC(ObjectVisitorArgument,
STATISTIC(ObjectVisitorLoad,
"Number of load instructions with unsolved size and offset");
+/// Align \p Size according to \p Alignment. If \p Size is greater than
+/// getSignedMaxValue(), set it as unknown as we can only represent signed value
+/// in OffsetSpan.
APInt ObjectSizeOffsetVisitor::align(APInt Size, MaybeAlign Alignment) {
if (Options.RoundToAlign && Alignment)
- return APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
- return Size;
+ Size = APInt(IntTyBits, alignTo(Size.getZExtValue(), *Alignment));
+
+ return Size.isNegative() ? APInt() : Size;
}
ObjectSizeOffsetVisitor::ObjectSizeOffsetVisitor(const DataLayout &DL,
@@ -733,8 +742,26 @@ OffsetSpan ObjectSizeOffsetVisitor::computeImpl(Value *V) {
ORT.After = APInt();
}
// If the computed bound is "unknown" we cannot add the stripped offset.
- return {(ORT.knownBefore() ? ORT.Before + Offset : ORT.Before),
- (ORT.knownAfter() ? ORT.After - Offset : ORT.After)};
+ if (ORT.knownBefore()) {
+ bool Overflow;
+ ORT.Before = ORT.Before.sadd_ov(Offset, Overflow);
+ if (Overflow)
+ ORT.Before = APInt();
+ }
+ if (ORT.knownAfter()) {
+ bool Overflow;
+ ORT.After = ORT.After.ssub_ov(Offset, Overflow);
+ if (Overflow)
+ ORT.After = APInt();
+ }
+
+ // We end up pointing on a location that's outside of the original object.
+ // This is UB, and we'd rather return an empty location then.
+ if (ORT.knownBefore() && ORT.Before.isNegative()) {
+ ORT.Before = APInt::getZero(ORT.Before.getBitWidth());
+ ORT.After = APInt::getZero(ORT.Before.getBitWidth());
+ }
+ return ORT;
}
OffsetSpan ObjectSizeOffsetVisitor::computeValue(Value *V) {
@@ -780,6 +807,7 @@ OffsetSpan ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) {
if (!isUIntN(IntTyBits, ElemSize.getKnownMinValue()))
return ObjectSizeOffsetVisitor::unknown();
APInt Size(IntTyBits, ElemSize.getKnownMinValue());
+
if (!I.isArrayAllocation())
return OffsetSpan(Zero, align(Size, I.getAlign()));
@@ -791,6 +819,7 @@ OffsetSpan ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) {
bool Overflow;
Size = Size.umul_ov(NumElems, Overflow);
+
return Overflow ? ObjectSizeOffsetVisitor::unknown()
: OffsetSpan(Zero, align(Size, I.getAlign()));
}
@@ -810,8 +839,12 @@ OffsetSpan ObjectSizeOffsetVisitor::visitArgument(Argument &A) {
}
OffsetSpan ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) {
- if (std::optional<APInt> Size = getAllocSize(&CB, TLI))
+ if (std::optional<APInt> Size = getAllocSize(&CB, TLI)) {
+ // Very large unsigned value cannot be represented as OffsetSpan.
+ if (Size->isNegative())
+ return ObjectSizeOffsetVisitor::unknown();
return OffsetSpan(Zero, *Size);
+ }
return ObjectSizeOffsetVisitor::unknown();
}
@@ -944,7 +977,11 @@ OffsetSpan ObjectSizeOffsetVisitor::findLoadOffsetRange(
if (!C)
return Unknown();
- return Known({APInt(C->getValue().getBitWidth(), 0), C->getValue()});
+ APInt CSize = C->getValue();
+ if (CSize.isNegative())
+ return Unknown();
+
+ return Known({APInt(CSize.getBitWidth(), 0), CSize});
}
return Unknown();