[llvm-commits] [llvm] r102733 - in /llvm/trunk: lib/Analysis/Lint.cpp test/Other/lint.ll
Dan Gohman
gohman at apple.com
Fri Apr 30 12:05:00 PDT 2010
Author: djg
Date: Fri Apr 30 14:05:00 2010
New Revision: 102733
URL: http://llvm.org/viewvc/llvm-project?rev=102733&view=rev
Log:
Add lint checks for invalid uses of memory.
Modified:
llvm/trunk/lib/Analysis/Lint.cpp
llvm/trunk/test/Other/lint.ll
Modified: llvm/trunk/lib/Analysis/Lint.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Lint.cpp?rev=102733&r1=102732&r2=102733&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/Lint.cpp (original)
+++ llvm/trunk/lib/Analysis/Lint.cpp Fri Apr 30 14:05:00 2010
@@ -51,6 +51,13 @@
using namespace llvm;
namespace {
+ namespace MemRef {
+ static unsigned Read = 1;
+ static unsigned Write = 2;
+ static unsigned Callee = 4;
+ static unsigned Branchee = 8;
+ }
+
class Lint : public FunctionPass, public InstVisitor<Lint> {
friend class InstVisitor<Lint>;
@@ -58,7 +65,7 @@
void visitCallSite(CallSite CS);
void visitMemoryReference(Instruction &I, Value *Ptr, unsigned Align,
- const Type *Ty);
+ const Type *Ty, unsigned Flags);
void visitCallInst(CallInst &I);
void visitInvokeInst(InvokeInst &I);
@@ -187,7 +194,7 @@
Value *Callee = CS.getCalledValue();
// TODO: Check function alignment?
- visitMemoryReference(I, Callee, 0, 0);
+ visitMemoryReference(I, Callee, 0, 0, MemRef::Callee);
if (Function *F = dyn_cast<Function>(Callee->stripPointerCasts())) {
Assert1(CS.getCallingConv() == F->getCallingConv(),
@@ -222,8 +229,10 @@
case Intrinsic::memcpy: {
MemCpyInst *MCI = cast<MemCpyInst>(&I);
- visitMemoryReference(I, MCI->getSource(), MCI->getAlignment(), 0);
- visitMemoryReference(I, MCI->getDest(), MCI->getAlignment(), 0);
+ visitMemoryReference(I, MCI->getSource(), MCI->getAlignment(), 0,
+ MemRef::Write);
+ visitMemoryReference(I, MCI->getDest(), MCI->getAlignment(), 0,
+ MemRef::Read);
// Check that the memcpy arguments don't overlap. The AliasAnalysis API
// isn't expressive enough for what we really want to do. Known partial
@@ -240,13 +249,16 @@
}
case Intrinsic::memmove: {
MemMoveInst *MMI = cast<MemMoveInst>(&I);
- visitMemoryReference(I, MMI->getSource(), MMI->getAlignment(), 0);
- visitMemoryReference(I, MMI->getDest(), MMI->getAlignment(), 0);
+ visitMemoryReference(I, MMI->getSource(), MMI->getAlignment(), 0,
+ MemRef::Write);
+ visitMemoryReference(I, MMI->getDest(), MMI->getAlignment(), 0,
+ MemRef::Read);
break;
}
case Intrinsic::memset: {
MemSetInst *MSI = cast<MemSetInst>(&I);
- visitMemoryReference(I, MSI->getDest(), MSI->getAlignment(), 0);
+ visitMemoryReference(I, MSI->getDest(), MSI->getAlignment(), 0,
+ MemRef::Write);
break;
}
@@ -255,18 +267,21 @@
"Undefined behavior: va_start called in a non-varargs function",
&I);
- visitMemoryReference(I, CS.getArgument(0), 0, 0);
+ visitMemoryReference(I, CS.getArgument(0), 0, 0,
+ MemRef::Read | MemRef::Write);
break;
case Intrinsic::vacopy:
- visitMemoryReference(I, CS.getArgument(0), 0, 0);
- visitMemoryReference(I, CS.getArgument(1), 0, 0);
+ visitMemoryReference(I, CS.getArgument(0), 0, 0, MemRef::Write);
+ visitMemoryReference(I, CS.getArgument(1), 0, 0, MemRef::Read);
break;
case Intrinsic::vaend:
- visitMemoryReference(I, CS.getArgument(0), 0, 0);
+ visitMemoryReference(I, CS.getArgument(0), 0, 0,
+ MemRef::Read | MemRef::Write);
break;
case Intrinsic::stackrestore:
- visitMemoryReference(I, CS.getArgument(0), 0, 0);
+ visitMemoryReference(I, CS.getArgument(0), 0, 0,
+ MemRef::Read);
break;
}
}
@@ -287,16 +302,39 @@
}
// TODO: Add a length argument and check that the reference is in bounds
-// TODO: Add read/write/execute flags and check for writing to read-only
-// memory or jumping to suspicious writeable memory
void Lint::visitMemoryReference(Instruction &I,
- Value *Ptr, unsigned Align, const Type *Ty) {
+ Value *Ptr, unsigned Align, const Type *Ty,
+ unsigned Flags) {
Value *UnderlyingObject = Ptr->getUnderlyingObject();
Assert1(!isa<ConstantPointerNull>(UnderlyingObject),
"Undefined behavior: Null pointer dereference", &I);
Assert1(!isa<UndefValue>(UnderlyingObject),
"Undefined behavior: Undef pointer dereference", &I);
+ if (Flags & MemRef::Write) {
+ if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(UnderlyingObject))
+ Assert1(!GV->isConstant(),
+ "Undefined behavior: Write to read-only memory", &I);
+ Assert1(!isa<Function>(UnderlyingObject) &&
+ !isa<BlockAddress>(UnderlyingObject),
+ "Undefined behavior: Write to text section", &I);
+ }
+ if (Flags & MemRef::Read) {
+ Assert1(!isa<Function>(UnderlyingObject),
+ "Unusual: Load from function body", &I);
+ Assert1(!isa<BlockAddress>(UnderlyingObject),
+ "Undefined behavior: Load from block address", &I);
+ }
+ if (Flags & MemRef::Callee) {
+ Assert1(!isa<BlockAddress>(UnderlyingObject),
+ "Undefined behavior: Call to block address", &I);
+ }
+ if (Flags & MemRef::Branchee) {
+ Assert1(!isa<Constant>(UnderlyingObject) ||
+ isa<BlockAddress>(UnderlyingObject),
+ "Undefined behavior: Branch to non-blockaddress", &I);
+ }
+
if (TD) {
if (Align == 0 && Ty) Align = TD->getABITypeAlignment(Ty);
@@ -312,12 +350,13 @@
}
void Lint::visitLoadInst(LoadInst &I) {
- visitMemoryReference(I, I.getPointerOperand(), I.getAlignment(), I.getType());
+ visitMemoryReference(I, I.getPointerOperand(), I.getAlignment(), I.getType(),
+ MemRef::Read);
}
void Lint::visitStoreInst(StoreInst &I) {
visitMemoryReference(I, I.getPointerOperand(), I.getAlignment(),
- I.getOperand(0)->getType());
+ I.getOperand(0)->getType(), MemRef::Write);
}
void Lint::visitXor(BinaryOperator &I) {
@@ -392,11 +431,12 @@
}
void Lint::visitVAArgInst(VAArgInst &I) {
- visitMemoryReference(I, I.getOperand(0), 0, 0);
+ visitMemoryReference(I, I.getOperand(0), 0, 0,
+ MemRef::Read | MemRef::Write);
}
void Lint::visitIndirectBrInst(IndirectBrInst &I) {
- visitMemoryReference(I, I.getAddress(), 0, 0);
+ visitMemoryReference(I, I.getAddress(), 0, 0, MemRef::Branchee);
}
void Lint::visitExtractElementInst(ExtractElementInst &I) {
Modified: llvm/trunk/test/Other/lint.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/lint.ll?rev=102733&r1=102732&r2=102733&view=diff
==============================================================================
--- llvm/trunk/test/Other/lint.ll (original)
+++ llvm/trunk/test/Other/lint.ll Fri Apr 30 14:05:00 2010
@@ -3,6 +3,8 @@
declare fastcc void @bar()
+ at CG = constant i32 7
+
define i32 @foo() noreturn {
; CHECK: Caller and callee calling convention differ
call void @bar()
@@ -39,6 +41,16 @@
%xx = xor i32 undef, undef
; CHECK: sub(undef, undef)
%xs = sub i32 undef, undef
+
+; CHECK: Write to read-only memory
+ store i32 8, i32* @CG
+; CHECK: Write to text section
+ store i32 8, i32* bitcast (i32()* @foo to i32*)
+; CHECK: Load from block address
+ %lb = load i32* bitcast (i8* blockaddress(@foo, %next) to i32*)
+; CHECK: Call to block address
+ call void()* bitcast (i8* blockaddress(@foo, %next) to void()*)()
+
br label %next
next:
@@ -64,3 +76,9 @@
call void @llvm.va_start(i8* %p)
ret void
}
+
+define void @use_indbr() {
+ indirectbr i8* bitcast (i32()* @foo to i8*), [label %block]
+block:
+ unreachable
+}
More information about the llvm-commits
mailing list