From: Jordan Rose Date: Mon, 1 Oct 2012 19:07:22 +0000 (+0000) Subject: [analyzer] Allow ObjC ivar lvalues where the base is nil. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=92375adafbca9ee5dc2840a6252000154a6e71df;p=platform%2Fupstream%2Fllvm.git [analyzer] Allow ObjC ivar lvalues where the base is nil. By analogy with C structs, this seems to be legal, if probably discouraged. It's only if the ivar is read from or written to that there's a problem. Running a program that gets the "address" of an instance variable does in fact return the offset when the base "object" is nil. This isn't a full revert because r164442 includes some diagnostic tweaks as well; those have been kept. This partially reverts r164442 / 08965091770c9b276c238bac2f716eaa4da2dca4. llvm-svn: 164960 --- diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index ee315a4..51dda19 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -25,21 +25,11 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); SVal baseVal = state->getSVal(Ex->getBase(), LCtx); - - // First check that the base object is valid. - ExplodedNodeSet DstLoc; - evalLocation(DstLoc, Ex, Ex, Pred, state, baseVal, - /*Tag=*/0, /*isLoad=*/true); - - // Bind the lvalue to the expression. SVal location = state->getLValue(Ex->getDecl(), baseVal); ExplodedNodeSet dstIvar; - StmtNodeBuilder Bldr(DstLoc, dstIvar, *currBldrCtx); - for (ExplodedNodeSet::iterator I = DstLoc.begin(), E = DstLoc.end(); - I != E; ++I) { - Bldr.generateNode(Ex, (*I), (*I)->getState()->BindExpr(Ex, LCtx, location)); - } + StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location)); // Perform the post-condition check of the ObjCIvarRefExpr and store // the created nodes in 'Dst'. diff --git a/clang/test/Analysis/ivars.m b/clang/test/Analysis/ivars.m index 5ba3877..c717da6 100644 --- a/clang/test/Analysis/ivars.m +++ b/clang/test/Analysis/ivars.m @@ -135,6 +135,6 @@ struct S makeS(); int testNull(Root *obj) { if (obj) return 0; - int *x = &obj->uniqueID; // expected-warning{{Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj')}} - return *x; + int *x = &obj->uniqueID; + return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} } diff --git a/clang/test/Analysis/null-deref-path-notes.m b/clang/test/Analysis/null-deref-path-notes.m index 003c2fb..92e6857 100644 --- a/clang/test/Analysis/null-deref-path-notes.m +++ b/clang/test/Analysis/null-deref-path-notes.m @@ -12,12 +12,10 @@ int testNull(Root *obj) { if (obj) return 0; // expected-note@-1 {{Assuming 'obj' is nil}} - // expected-note@-2 {{Assuming pointer value is null}} - // expected-note@-3 {{Taking false branch}} - // FIXME: We don't need the second note. + // expected-note@-2 {{Taking false branch}} - int *x = &obj->uniqueID; // expected-warning{{Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj')}} expected-note{{Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj')}} - return *x; + int *x = &obj->uniqueID; // expected-note{{Variable 'x' initialized to a null pointer value}} + return *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}} expected-note{{Dereference of null pointer (loaded from variable 'x')}} } @@ -109,33 +107,67 @@ int testNull(Root *obj) { // CHECK-NEXT: Assuming 'obj' is nil // CHECK-NEXT: // CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line13 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line13 -// CHECK-NEXT: col7 +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: ranges // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 -// CHECK-NEXT: col7 +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 -// CHECK-NEXT: col9 +// CHECK-NEXT: line17 +// CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: depth0 // CHECK-NEXT: extended_message -// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: Variable 'x' initialized to a null pointer value // CHECK-NEXT: message -// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: Variable 'x' initialized to a null pointer value // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: kindcontrol @@ -145,26 +177,26 @@ int testNull(Root *obj) { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 -// CHECK-NEXT: col7 +// CHECK-NEXT: line17 +// CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 -// CHECK-NEXT: col9 +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 +// CHECK-NEXT: line18 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col5 +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -179,26 +211,26 @@ int testNull(Root *obj) { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 +// CHECK-NEXT: line18 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col5 +// CHECK-NEXT: line18 +// CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col13 +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col15 +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -209,42 +241,42 @@ int testNull(Root *obj) { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col13 +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: ranges // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col13 +// CHECK-NEXT: line18 +// CHECK-NEXT: col11 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col15 +// CHECK-NEXT: line18 +// CHECK-NEXT: col11 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: depth0 // CHECK-NEXT: extended_message -// CHECK-NEXT: Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj') +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') // CHECK-NEXT: message -// CHECK-NEXT: Access to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj') +// CHECK-NEXT: Dereference of null pointer (loaded from variable 'x') // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: descriptionAccess to instance variable 'uniqueID' results in a dereference of a null pointer (loaded from variable 'obj') +// CHECK-NEXT: descriptionDereference of null pointer (loaded from variable 'x') // CHECK-NEXT: categoryLogic error // CHECK-NEXT: typeDereference of null pointer // CHECK-NEXT: issue_context_kindfunction // CHECK-NEXT: issue_contexttestNull -// CHECK-NEXT: issue_hash7 +// CHECK-NEXT: issue_hash6 // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line19 -// CHECK-NEXT: col13 +// CHECK-NEXT: line18 +// CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -255,7 +287,7 @@ int testNull(Root *obj) { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line29 +// CHECK-NEXT: line27 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -263,12 +295,12 @@ int testNull(Root *obj) { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line29 +// CHECK-NEXT: line27 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line29 +// CHECK-NEXT: line27 // CHECK-NEXT: col33 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -288,12 +320,12 @@ int testNull(Root *obj) { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line29 +// CHECK-NEXT: line27 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line29 +// CHECK-NEXT: line27 // CHECK-NEXT: col6 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -301,12 +333,12 @@ int testNull(Root *obj) { // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col4 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -322,12 +354,12 @@ int testNull(Root *obj) { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col4 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -335,12 +367,12 @@ int testNull(Root *obj) { // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -352,7 +384,7 @@ int testNull(Root *obj) { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -360,12 +392,12 @@ int testNull(Root *obj) { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -381,7 +413,7 @@ int testNull(Root *obj) { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -389,12 +421,12 @@ int testNull(Root *obj) { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -414,12 +446,12 @@ int testNull(Root *obj) { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col7 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line30 +// CHECK-NEXT: line28 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -427,12 +459,12 @@ int testNull(Root *obj) { // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line36 +// CHECK-NEXT: line34 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line36 +// CHECK-NEXT: line34 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -444,7 +476,7 @@ int testNull(Root *obj) { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line36 +// CHECK-NEXT: line34 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -452,13 +484,13 @@ int testNull(Root *obj) { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line36 +// CHECK-NEXT: line34 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line36 -// CHECK-NEXT: col10 +// CHECK-NEXT: line34 +// CHECK-NEXT: col18 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -478,7 +510,7 @@ int testNull(Root *obj) { // CHECK-NEXT: issue_hash8 // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line36 +// CHECK-NEXT: line34 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: