[cfe-commits] r98796 - in /cfe/trunk: lib/Checker/CallAndMessageChecker.cpp test/Analysis/uninit-vals-ps-region.c
Ted Kremenek
kremenek at apple.com
Wed Mar 17 19:17:27 PDT 2010
Author: kremenek
Date: Wed Mar 17 21:17:27 2010
New Revision: 98796
URL: http://llvm.org/viewvc/llvm-project?rev=98796&view=rev
Log:
Detect pass-by-value arguments that are structs that contain
uninitialized data.
Modified:
cfe/trunk/lib/Checker/CallAndMessageChecker.cpp
cfe/trunk/test/Analysis/uninit-vals-ps-region.c
Modified: cfe/trunk/lib/Checker/CallAndMessageChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallAndMessageChecker.cpp?rev=98796&r1=98795&r2=98796&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CallAndMessageChecker.cpp (original)
+++ cfe/trunk/lib/Checker/CallAndMessageChecker.cpp Wed Mar 17 21:17:27 2010
@@ -24,7 +24,7 @@
class CallAndMessageChecker
: public CheckerVisitor<CallAndMessageChecker> {
BugType *BT_call_null;
- BugType *BT_call_undef;
+ BugType *BT_call_undef;
BugType *BT_call_arg;
BugType *BT_msg_undef;
BugType *BT_msg_arg;
@@ -47,9 +47,15 @@
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
ExplodedNode *N);
-
+
void HandleNilReceiver(CheckerContext &C, const GRState *state,
- const ObjCMessageExpr *ME);
+ const ObjCMessageExpr *ME);
+
+ void LazyInit_BT_call_arg() {
+ if (!BT_call_arg)
+ BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
+ " is undefined");
+ }
};
} // end anonymous namespace
@@ -62,19 +68,19 @@
ExplodedNode *N = C.GenerateSink();
if (!N)
return;
-
+
EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N));
C.EmitReport(R);
}
-void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
+void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE){
-
+
const Expr *Callee = CE->getCallee()->IgnoreParens();
SVal L = C.getState()->getSVal(Callee);
-
+
if (L.isUndef()) {
if (!BT_call_undef)
BT_call_undef =
@@ -82,21 +88,21 @@
EmitBadCall(BT_call_undef, C, CE);
return;
}
-
+
if (isa<loc::ConcreteInt>(L)) {
if (!BT_call_null)
BT_call_null =
new BuiltinBug("Called function pointer is null (null dereference)");
EmitBadCall(BT_call_null, C, CE);
- }
-
+ }
+
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
I != E; ++I) {
- if (C.getState()->getSVal(*I).isUndef()) {
+ const SVal &V = C.getState()->getSVal(*I);
+ if (V.isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
- if (!BT_call_arg)
- BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
- " is undefined");
+ LazyInit_BT_call_arg();
+
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
BT_call_arg->getName(), N);
@@ -106,6 +112,89 @@
return;
}
}
+ if (const nonloc::LazyCompoundVal *LV =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+ const LazyCompoundValData *D = LV->getCVData();
+
+ class FindUninitializedField {
+ public:
+ llvm::SmallVector<const FieldDecl *, 10> FieldChain;
+ private:
+ ASTContext &C;
+ StoreManager &StoreMgr;
+ MemRegionManager &MrMgr;
+ Store store;
+ public:
+ FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
+ MemRegionManager &mrMgr, Store s)
+ : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
+
+ bool Find(const TypedRegion *R) {
+ QualType T = R->getValueType(C);
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition();
+ assert(RD && "Referred record has no definition");
+ for (RecordDecl::field_iterator I =
+ RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
+ const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
+ FieldChain.push_back(*I);
+ T = (*I)->getType();
+ if (T->getAsStructureType()) {
+ if (Find(FR))
+ return true;
+ }
+ else {
+ const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
+ if (V.isUndef())
+ return true;
+ }
+ FieldChain.pop_back();
+ }
+ }
+
+ return false;
+ }
+ };
+
+ FindUninitializedField F(C.getASTContext(),
+ C.getState()->getStateManager().getStoreManager(),
+ C.getValueManager().getRegionManager(),
+ D->getStore());
+
+ if (F.Find(D->getRegion())) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ LazyInit_BT_call_arg();
+ llvm::SmallString<512> Str;
+ llvm::raw_svector_ostream os(Str);
+ os << "Passed-by-value struct argument contains uninitialized data";
+
+ if (F.FieldChain.size() == 1)
+ os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() << "')";
+ else {
+ os << " (e.g., via the field chain: '";
+ bool first = true;
+ for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
+ DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
+ if (first)
+ first = false;
+ else
+ os << '.';
+ os << (*DI)->getNameAsString();
+ }
+ os << "')";
+ }
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT_call_arg, os.str(), N);
+ R->addRange((*I)->getSourceRange());
+
+ // FIXME: enhance track back for uninitialized value for arbitrary
+ // memregions
+ C.EmitReport(R);
+ }
+ }
+ }
}
}
@@ -138,7 +227,7 @@
if (!BT_msg_arg)
BT_msg_arg =
new BuiltinBug("Pass-by-value argument in message expression"
- " is undefined");
+ " is undefined");
// Generate a report for this bug.
EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
BT_msg_arg->getName(), N);
@@ -160,24 +249,24 @@
void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
const ObjCMessageExpr *ME,
ExplodedNode *N) {
-
+
if (!BT_msg_ret)
BT_msg_ret =
new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value");
-
+
llvm::SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
<< "' is nil and returns a value of type '"
<< ME->getType().getAsString() << "' that will be garbage";
-
+
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
const Expr *receiver = ME->getReceiver();
report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
receiver);
- C.EmitReport(report);
+ C.EmitReport(report);
}
static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
@@ -188,11 +277,11 @@
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const GRState *state,
const ObjCMessageExpr *ME) {
-
+
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
QualType RetTy = ME->getType();
-
+
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
@@ -216,7 +305,7 @@
if (CanRetTy != Ctx.VoidTy &&
C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
// Compute: sizeof(void *) and sizeof(return type)
- const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (voidPtrSize < returnTypeSize &&
@@ -247,6 +336,6 @@
C.GenerateNode(state->BindExpr(ME, V));
return;
}
-
+
C.addTransition(state);
}
Modified: cfe/trunk/test/Analysis/uninit-vals-ps-region.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/uninit-vals-ps-region.c?rev=98796&r1=98795&r2=98796&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.c Wed Mar 17 21:17:27 2010
@@ -45,3 +45,9 @@
test_unit_aux2(v2.x + v1.y); // no-warning
}
+extern void test_uninit_struct_arg_aux(struct TestUninit arg);
+void test_uninit_struct_arg() {
+ struct TestUninit x;
+ test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
+}
+
More information about the cfe-commits
mailing list