diff options
| author | Duncan Sands <baldrick@free.fr> | 2012-09-26 07:45:36 +0000 |
|---|---|---|
| committer | Duncan Sands <baldrick@free.fr> | 2012-09-26 07:45:36 +0000 |
| commit | a221eea7db747c950fef8b1b08e159065f842f1e (patch) | |
| tree | 0928a758fde5ebc372804087424e14cc85c2360d /llvm | |
| parent | d18eab51715cc5c00fe1a70f82628662ed99b591 (diff) | |
| download | bcm5719-llvm-a221eea7db747c950fef8b1b08e159065f842f1e.tar.gz bcm5719-llvm-a221eea7db747c950fef8b1b08e159065f842f1e.zip | |
Teach the 'lint' sanity checking pass to detect simple buffer overflows.
llvm-svn: 164671
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Analysis/Lint.cpp | 58 | ||||
| -rw-r--r-- | llvm/test/Other/lint.ll | 12 |
2 files changed, 51 insertions, 19 deletions
diff --git a/llvm/lib/Analysis/Lint.cpp b/llvm/lib/Analysis/Lint.cpp index 6e765a7fdea..9258aeee550 100644 --- a/llvm/lib/Analysis/Lint.cpp +++ b/llvm/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/llvm/test/Other/lint.ll b/llvm/test/Other/lint.ll index f6787e973ed..d3ab98872d7 100644 --- a/llvm/test/Other/lint.ll +++ b/llvm/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: |

