aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuncan Sands <baldrick@free.fr>2012-09-26 07:45:36 +0000
committerDuncan Sands <baldrick@free.fr>2012-09-26 07:45:36 +0000
commitc7c42f71aad7d33892de73d6d6397e38814b0e97 (patch)
tree92e9bca7e906b0676ac4962fdd2e3d23929d9d53
parent02f790e53445b1ded08da61ae659496241afd1aa (diff)
downloadexternal_llvm-c7c42f71aad7d33892de73d6d6397e38814b0e97.zip
external_llvm-c7c42f71aad7d33892de73d6d6397e38814b0e97.tar.gz
external_llvm-c7c42f71aad7d33892de73d6d6397e38814b0e97.tar.bz2
Teach the 'lint' sanity checking pass to detect simple buffer overflows.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164671 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/Lint.cpp58
-rw-r--r--test/Other/lint.ll12
2 files changed, 51 insertions, 19 deletions
diff --git a/lib/Analysis/Lint.cpp b/lib/Analysis/Lint.cpp
index 6e765a7..9258aee 100644
--- a/lib/Analysis/Lint.cpp
+++ b/lib/Analysis/Lint.cpp
@@ -411,27 +411,47 @@ void Lint::visitMemoryReference(Instruction &I,
"Undefined behavior: Branch to non-blockaddress", &I);
}
+ // Check for buffer overflows and misalignment.
if (TD) {
- if (Align == 0 && Ty && Ty->isSized())
- Align = TD->getABITypeAlignment(Ty);
-
- if (Align != 0) {
- int64_t Offset = 0;
- if (Value *Base = GetPointerBaseWithConstantOffset(Ptr, Offset, *TD)) {
- unsigned BaseAlign = 0;
- if (AllocaInst *AI = dyn_cast<AllocaInst>(Base)) {
- BaseAlign = AI->getAlignment();
- if (BaseAlign == 0 && AI->getAllocatedType()->isSized())
- BaseAlign = TD->getABITypeAlignment(AI->getAllocatedType());
- } else if (GlobalValue *GV = dyn_cast<GlobalVariable>(Base)) {
- BaseAlign = GV->getAlignment();
- if (BaseAlign == 0 && GV->getType()->getElementType()->isSized())
- BaseAlign = TD->getABITypeAlignment(GV->getType()->getElementType());
- }
- Assert1((!BaseAlign || Align <= MinAlign(BaseAlign, Offset)),
- "Undefined behavior: Memory reference address is misaligned",
- &I);
+ // Only handles memory references that read/write something simple like an
+ // alloca instruction or a global variable.
+ int64_t Offset = 0;
+ if (Value *Base = GetPointerBaseWithConstantOffset(Ptr, Offset, *TD)) {
+ // OK, so the access is to a constant offset from Ptr. Check that Ptr is
+ // something we can handle and if so extract the size of this base object
+ // along with its alignment.
+ uint64_t BaseSize = AliasAnalysis::UnknownSize;
+ unsigned BaseAlign = 0;
+
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(Base)) {
+ Type *ATy = AI->getAllocatedType();
+ if (!AI->isArrayAllocation() && ATy->isSized())
+ BaseSize = TD->getTypeAllocSize(ATy);
+ BaseAlign = AI->getAlignment();
+ if (BaseAlign == 0 && ATy->isSized())
+ BaseAlign = TD->getABITypeAlignment(ATy);
+ } else if (GlobalValue *GV = dyn_cast<GlobalVariable>(Base)) {
+ Type *GTy = GV->getType()->getElementType();
+ if (GTy->isSized())
+ BaseSize = TD->getTypeAllocSize(GTy);
+ BaseAlign = GV->getAlignment();
+ if (BaseAlign == 0 && GTy->isSized())
+ BaseAlign = TD->getABITypeAlignment(GTy);
}
+
+ // Accesses from before the start or after the end of the object are not
+ // defined.
+ Assert1(Size == AliasAnalysis::UnknownSize ||
+ BaseSize == AliasAnalysis::UnknownSize ||
+ (Offset >= 0 && Offset + Size <= BaseSize),
+ "Undefined behavior: Buffer overflow", &I);
+
+ // Accesses that say that the memory is more aligned than it is are not
+ // defined.
+ if (Align == 0 && Ty && Ty->isSized())
+ Align = TD->getABITypeAlignment(Ty);
+ Assert1(!BaseAlign || Align <= MinAlign(BaseAlign, Offset),
+ "Undefined behavior: Memory reference address is misaligned", &I);
}
}
}
diff --git a/test/Other/lint.ll b/test/Other/lint.ll
index f6787e9..d3ab988 100644
--- a/test/Other/lint.ll
+++ b/test/Other/lint.ll
@@ -79,6 +79,18 @@ define i32 @foo() noreturn {
; CHECK: Write to read-only memory
call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast (i32* @CG to i8*), i8* bitcast (i32* @CG to i8*), i64 1, i32 1, i1 0)
+; CHECK: Undefined behavior: Buffer overflow
+ %wider = bitcast i8* %buf to i16*
+ store i16 0, i16* %wider
+; CHECK: Undefined behavior: Buffer overflow
+ %inner = getelementptr {i8, i8}* %buf2, i32 0, i32 1
+ %wider2 = bitcast i8* %inner to i16*
+ store i16 0, i16* %wider2
+; CHECK: Undefined behavior: Buffer overflow
+ %before = getelementptr i8* %buf, i32 -1
+ %wider3 = bitcast i8* %before to i16*
+ store i16 0, i16* %wider3
+
br label %next
next: