diff options
author | serge-sans-paille <sguelton@mozilla.com> | 2024-11-18 07:39:04 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-18 07:39:04 +0000 |
commit | 1dcb3db0ac1255bf556bf6b62d03a113bd5191d8 (patch) | |
tree | 2dfc2d0c446e2797fd649b9bfa64ea1aa449b9be /llvm/lib/Analysis/MemoryBuiltins.cpp | |
parent | b4c0ef18226b7d1f82d71fc0171b99caec0d8d12 (diff) | |
download | llvm-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.cpp | 53 |
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(); |