[cfe-commits] r98800 - in /cfe/trunk: lib/Checker/CallAndMessageChecker.cpp test/Analysis/uninit-vals-ps-region.c test/Analysis/uninit-vals-ps-region.m
Ted Kremenek
kremenek at apple.com
Wed Mar 17 20:22:29 PDT 2010
Author: kremenek
Date: Wed Mar 17 22:22:29 2010
New Revision: 98800
URL: http://llvm.org/viewvc/llvm-project?rev=98800&view=rev
Log:
Refactor argument checking in CallAndMessageChecker to be the same
for both CallExprs and ObjCMessageExprs.
Added:
cfe/trunk/test/Analysis/uninit-vals-ps-region.m
- copied, changed from r98799, cfe/trunk/test/Analysis/uninit-vals-ps-region.c
Removed:
cfe/trunk/test/Analysis/uninit-vals-ps-region.c
Modified:
cfe/trunk/lib/Checker/CallAndMessageChecker.cpp
Modified: cfe/trunk/lib/Checker/CallAndMessageChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/CallAndMessageChecker.cpp?rev=98800&r1=98799&r2=98800&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/CallAndMessageChecker.cpp (original)
+++ cfe/trunk/lib/Checker/CallAndMessageChecker.cpp Wed Mar 17 22:22:29 2010
@@ -44,6 +44,9 @@
bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
private:
+ bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
+ const char *BT_desc, BugType *&BT);
+
void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
ExplodedNode *N);
@@ -51,10 +54,9 @@
void HandleNilReceiver(CheckerContext &C, const GRState *state,
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");
+ void LazyInit_BT(const char *desc, BugType *&BT) {
+ if (!BT)
+ BT = new BuiltinBug(desc);
}
};
} // end anonymous namespace
@@ -75,6 +77,114 @@
C.EmitReport(R);
}
+bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
+ const Expr *Ex,
+ const char *BT_desc,
+ BugType *&BT) {
+
+ const SVal &V = C.getState()->getSVal(Ex);
+
+ if (V.isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ LazyInit_BT(BT_desc, BT);
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addRange(Ex->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ C.EmitReport(R);
+ }
+ return true;
+ }
+
+ if (const nonloc::LazyCompoundVal *LV =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ 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;
+ }
+ };
+
+ const LazyCompoundValData *D = LV->getCVData();
+ 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(BT_desc, BT);
+ 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, os.str(), N);
+ R->addRange(Ex->getSourceRange());
+
+ // FIXME: enhance track back for uninitialized value for arbitrary
+ // memregions
+ C.EmitReport(R);
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE){
@@ -97,105 +207,11 @@
}
for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
- const SVal &V = C.getState()->getSVal(*I);
- if (V.isUndef()) {
- if (ExplodedNode *N = C.GenerateSink()) {
- LazyInit_BT_call_arg();
-
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
- BT_call_arg->getName(), N);
- R->addRange((*I)->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
- C.EmitReport(R);
- 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);
- }
- }
- }
- }
+ I != E; ++I)
+ if (PreVisitProcessArg(C, *I,
+ "Pass-by-value argument in function call is"
+ " undefined", BT_call_arg))
+ return;
}
void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
@@ -221,23 +237,11 @@
// Check for any arguments that are uninitialized/undefined.
for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
- E = ME->arg_end(); I != E; ++I) {
- if (state->getSVal(*I).isUndef()) {
- if (ExplodedNode *N = C.GenerateSink()) {
- if (!BT_msg_arg)
- BT_msg_arg =
- new BuiltinBug("Pass-by-value argument in message expression"
- " is undefined");
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
- BT_msg_arg->getName(), N);
- R->addRange((*I)->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
- C.EmitReport(R);
+ E = ME->arg_end(); I != E; ++I)
+ if (PreVisitProcessArg(C, *I,
+ "Pass-by-value argument in message expression "
+ "is undefined", BT_msg_arg))
return;
- }
- }
- }
}
bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
Removed: 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=98799&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.c (removed)
@@ -1,53 +0,0 @@
-// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-store=region -verify %s
-
-struct s {
- int data;
-};
-
-struct s global;
-
-void g(int);
-
-void f4() {
- int a;
- if (global.data == 0)
- a = 3;
- if (global.data == 0) // When the true branch is feasible 'a = 3'.
- g(a); // no-warning
-}
-
-
-// Test uninitialized value due to part of the structure being uninitialized.
-struct TestUninit { int x; int y; };
-struct TestUninit test_uninit_aux();
-void test_unit_aux2(int);
-void test_uninit_pos() {
- struct TestUninit v1 = { 0, 0 };
- struct TestUninit v2 = test_uninit_aux();
- int z;
- v1.y = z; // expected-warning{{Assigned value is garbage or undefined}}
- test_unit_aux2(v2.x + v1.y);
-}
-void test_uninit_pos_2() {
- struct TestUninit v1 = { 0, 0 };
- struct TestUninit v2;
- test_unit_aux2(v2.x + v1.y); // expected-warning{{The left operand of '+' is a garbage value}}
-}
-void test_uninit_pos_3() {
- struct TestUninit v1 = { 0, 0 };
- struct TestUninit v2;
- test_unit_aux2(v1.y + v2.x); // expected-warning{{The right operand of '+' is a garbage value}}
-}
-
-void test_uninit_neg() {
- struct TestUninit v1 = { 0, 0 };
- struct TestUninit v2 = test_uninit_aux();
- 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')}}
-}
-
Copied: cfe/trunk/test/Analysis/uninit-vals-ps-region.m (from r98799, cfe/trunk/test/Analysis/uninit-vals-ps-region.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/uninit-vals-ps-region.m?p2=cfe/trunk/test/Analysis/uninit-vals-ps-region.m&p1=cfe/trunk/test/Analysis/uninit-vals-ps-region.c&r1=98799&r2=98800&rev=98800&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/uninit-vals-ps-region.c (original)
+++ cfe/trunk/test/Analysis/uninit-vals-ps-region.m Wed Mar 17 22:22:29 2010
@@ -51,3 +51,12 @@
test_uninit_struct_arg_aux(x); // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
}
+ at interface Foo
+- (void) passVal:(struct TestUninit)arg;
+ at end
+void testFoo(Foo *o) {
+ struct TestUninit x;
+ [o passVal:x]; // expected-warning{{Passed-by-value struct argument contains uninitialized data (e.g., field: 'x')}}
+}
+
+
More information about the cfe-commits
mailing list