From 610f79cbab4d752349b5c81a94682a6a82b102e7 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Fri, 5 Apr 2013 00:59:33 +0000 Subject: [PATCH] [analyzer] Show path diagnostic for C++ initializers Also had to modify the PostInitializer ProgramLocation to contain the field region. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178826 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/ProgramPoint.h | 15 +- .../Core/BugReporterVisitors.cpp | 10 + lib/StaticAnalyzer/Core/ExprEngine.cpp | 6 +- lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 3 + test/Analysis/inlining/path-notes.cpp | 400 +++++++++++++++++- 5 files changed, 418 insertions(+), 16 deletions(-) diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 72422d8d15..333329d8c3 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -471,14 +471,25 @@ private: class PostInitializer : public ProgramPoint { public: - PostInitializer(const CXXCtorInitializer *I, + /// \brief Construct a PostInitializer point that represents a location after + /// CXXCtorInitializer expression evaluation. + /// + /// \param I The initializer. + /// \param Loc The location of the field being initialized. + PostInitializer(const CXXCtorInitializer *I, + const void *Loc, const LocationContext *L) - : ProgramPoint(I, PostInitializerKind, L) {} + : ProgramPoint(I, Loc, PostInitializerKind, L) {} const CXXCtorInitializer *getInitializer() const { return static_cast(getData1()); } + /// \brief Returns the location of the field. + const void *getLocationValue() const { + return getData2(); + } + private: friend class ProgramPoint; PostInitializer() {} diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index c3bbc3baf6..f600362da9 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -435,6 +435,16 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } } + // If this is a post initializer expression, initializing the region, we + // should track the initializer expression. + if (Optional PIP = Pred->getLocationAs()) { + const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue(); + if (FieldReg && FieldReg == R) { + StoreSite = Pred; + InitE = PIP->getInitializer()->getInit(); + } + } + // Otherwise, see if this is the store site: // (1) Succ has this binding and Pred does not, i.e. this is // where the binding first occurred. diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 5746bfb724..ab4dbd7525 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -438,8 +438,8 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, ProgramStateRef State = Pred->getState(); SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); - PostInitializer PP(BMI, stackFrame); ExplodedNodeSet Tmp(Pred); + SVal FieldLoc; // Evaluate the initializer, if necessary if (BMI->isAnyMemberInitializer()) { @@ -448,7 +448,6 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, const Expr *Init = BMI->getInit()->IgnoreImplicit(); if (!isa(Init)) { const ValueDecl *Field; - SVal FieldLoc; if (BMI->isIndirectMemberInitializer()) { Field = BMI->getIndirectMember(); FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); @@ -483,6 +482,8 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, assert(Tmp.size() == 1 && "have not generated any new nodes yet"); assert(*Tmp.begin() == Pred && "have not generated any new nodes yet"); Tmp.clear(); + + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } } else { @@ -492,6 +493,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // Construct PostInitializer nodes whether the state changed or not, // so that the diagnostics don't get confused. + PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); ExplodedNodeSet Dst; NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 686540b60e..7c0fb14a5c 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -588,6 +588,9 @@ PathDiagnosticLocation S = SP->getStmt(); if (P.getAs()) return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); + } else if (Optional PIP = P.getAs()) { + return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), + SMng); } else if (Optional PIE = P.getAs()) { return PathDiagnosticLocation(PIE->getLocation(), SMng); } else if (Optional CE = P.getAs()) { diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp index 6c63e1400c..895ee28e8b 100644 --- a/test/Analysis/inlining/path-notes.cpp +++ b/test/Analysis/inlining/path-notes.cpp @@ -184,7 +184,6 @@ namespace ReturnZeroNote { } } - int &returnNullReference() { int *x = 0; // expected-note@-1 {{'x' initialized to a null pointer value}} @@ -192,6 +191,20 @@ int &returnNullReference() { // expected-note@-1 {{Returning null reference}} } +struct FooWithInitializer { + int *ptr; + FooWithInitializer(int *p) : ptr(p) { // expected-note {{Null pointer value stored to 'f.ptr'}} + *ptr = 1; // expected-note {{Dereference of null pointer (loaded from field 'ptr')}} + // expected-warning@-1 {{Dereference of null pointer (loaded from field 'ptr')}} + } +}; + +void testPathNoteOnInitializer() { + int *p = 0; // expected-note {{'p' initialized to a null pointer value}} + + FooWithInitializer f(p); // expected-note {{Passing null pointer value via 1st parameter 'p'}} + // expected-note@-1 {{Calling constructor for 'FooWithInitializer'}} +} // CHECK: diagnostics // CHECK-NEXT: @@ -3230,7 +3243,7 @@ int &returnNullReference() { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line189 +// CHECK-NEXT: line188 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3238,12 +3251,12 @@ int &returnNullReference() { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line189 +// CHECK-NEXT: line188 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line189 +// CHECK-NEXT: line188 // CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3263,12 +3276,12 @@ int &returnNullReference() { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line189 +// CHECK-NEXT: line188 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line189 +// CHECK-NEXT: line188 // CHECK-NEXT: col5 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3276,12 +3289,12 @@ int &returnNullReference() { // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 // CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3293,7 +3306,7 @@ int &returnNullReference() { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3301,12 +3314,12 @@ int &returnNullReference() { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 // CHECK-NEXT: col11 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -3327,7 +3340,370 @@ int &returnNullReference() { // CHECK-NEXT: issue_hash3 // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line191 +// CHECK-NEXT: line190 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: 'p' initialized to a null pointer value +// CHECK-NEXT: message +// CHECK-NEXT: 'p' initialized to a null pointer value +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line203 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// 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: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Passing null pointer value via 1st parameter 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col23 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col21 +// 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: line205 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col21 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line205 +// CHECK-NEXT: col24 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling constructor for 'FooWithInitializer' +// CHECK-NEXT: message +// CHECK-NEXT: Calling constructor for 'FooWithInitializer' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testPathNoteOnInitializer' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testPathNoteOnInitializer' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col35 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col33 +// 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: line196 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to 'f.ptr' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to 'f.ptr' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col31 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line196 +// CHECK-NEXT: col33 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line197 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line197 +// CHECK-NEXT: col3 +// 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: line197 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line197 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line197 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'ptr') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'ptr') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from field 'ptr') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_hash1 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line197 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: -- 2.40.0