From 9e2f5977a180ae927d05e844c65b8a7873be48a4 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Fri, 12 Apr 2013 18:40:21 +0000 Subject: [PATCH] [analyzer]Print field region even when the base region is not printable git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179395 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Core/PathSensitive/MemRegion.h | 8 +- lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 3 +- .../Core/BugReporterVisitors.cpp | 18 +- lib/StaticAnalyzer/Core/MemRegion.cpp | 34 ++- test/Analysis/inlining/path-notes.c | 263 ++++++++++++++++++ 5 files changed, 304 insertions(+), 22 deletions(-) diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index af2f365ead..7ae432e389 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -169,6 +169,8 @@ public: /// \brief Print the region for use in diagnostics. virtual void printPretty(raw_ostream &os) const; + virtual void printPrettyNoQuotes(raw_ostream &os) const; + Kind getKind() const { return kind; } template const RegionTy* getAs() const; @@ -875,7 +877,8 @@ public: } bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + + void printPrettyNoQuotes(raw_ostream &os) const; }; /// CXXThisRegion - Represents the region for the implicit 'this' parameter @@ -937,6 +940,7 @@ public: bool canPrintPretty() const; void printPretty(raw_ostream &os) const; + void printPrettyNoQuotes(raw_ostream &os) const; }; class ObjCIvarRegion : public DeclRegion { @@ -953,7 +957,7 @@ public: QualType getValueType() const; bool canPrintPretty() const; - void printPretty(raw_ostream &os) const; + void printPrettyNoQuotes(raw_ostream &os) const; void dumpToStream(raw_ostream &os) const; diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index b000bfae4b..e19e3f72c7 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1606,9 +1606,8 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, SmallString<200> buf; llvm::raw_svector_ostream os(buf); if (Region && Region->canPrintPretty()) { - os << "Potential leak of memory pointed to by '"; + os << "Potential leak of memory pointed to by "; Region->printPretty(os); - os << '\''; } else { os << "Potential memory leak"; } diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 9b5f6b2a8c..92159de168 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -307,9 +307,9 @@ public: if (LValue) { if (const MemRegion *MR = LValue->getAsRegion()) { if (MR->canPrintPretty()) { - Out << " (reference to '"; + Out << " (reference to "; MR->printPretty(Out); - Out << "')"; + Out << ")"; } } } else { @@ -545,13 +545,9 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, } if (action) { - if (!R) - return 0; - - os << '\''; R->printPretty(os); - os << "' "; - + os << " "; + if (V.getAs()) { bool b = false; if (R->isBoundable()) { @@ -606,10 +602,8 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, // Printed parameter indexes are 1-based, not 0-based. unsigned Idx = Param->getFunctionScopeIndex() + 1; - os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; - + os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter "; R->printPretty(os); - os << '\''; } } @@ -637,9 +631,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, else os << "Value assigned to "; - os << '\''; R->printPretty(os); - os << '\''; } // Construct a new PathDiagnosticPiece. diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index b3a1e65b19..e244d31afa 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -559,6 +559,15 @@ bool MemRegion::canPrintPretty() const { } void MemRegion::printPretty(raw_ostream &os) const { + assert(canPrintPretty() && "This region cannot be printed pretty."); + os << "'"; + printPrettyNoQuotes(os); + os << "'"; + return; +} + +void MemRegion::printPrettyNoQuotes(raw_ostream &os) const { + assert(canPrintPretty() && "This region cannot be printed pretty."); return; } @@ -566,7 +575,7 @@ bool VarRegion::canPrintPretty() const { return true; } -void VarRegion::printPretty(raw_ostream &os) const { +void VarRegion::printPrettyNoQuotes(raw_ostream &os) const { os << getDecl()->getName(); } @@ -574,17 +583,32 @@ bool ObjCIvarRegion::canPrintPretty() const { return true; } -void ObjCIvarRegion::printPretty(raw_ostream &os) const { +void ObjCIvarRegion::printPrettyNoQuotes(raw_ostream &os) const { os << getDecl()->getName(); } bool FieldRegion::canPrintPretty() const { - return superRegion->canPrintPretty(); + return true; +} + +void FieldRegion::printPrettyNoQuotes(raw_ostream &os) const { + if (superRegion->canPrintPretty()) { + superRegion->printPrettyNoQuotes(os); + os << "." << getDecl()->getName(); + } else { + os << "field " << "\'" << getDecl()->getName() << "'"; + } } void FieldRegion::printPretty(raw_ostream &os) const { - superRegion->printPretty(os); - os << "." << getDecl()->getName(); + if (superRegion->canPrintPretty()) { + os << "\'"; + printPrettyNoQuotes(os); + os << "'"; + } else { + printPrettyNoQuotes(os); + } + return; } //===----------------------------------------------------------------------===// diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c index 2272330689..15140bdf52 100644 --- a/test/Analysis/inlining/path-notes.c +++ b/test/Analysis/inlining/path-notes.c @@ -107,6 +107,20 @@ void testUseOfNullPointer() { // expected-note@-4 {{Calling 'usePointer'}} } +struct X { char *p; }; + +void setFieldToNull(struct X *x) { + x->p = 0; // expected-note {{Null pointer value stored to field 'p'}} +} + +int testSetFieldToNull(struct X *x) { + setFieldToNull(x); // expected-note {{Calling 'setFieldToNull'}} + // expected-note@-1{{Returning from 'setFieldToNull'}} + return *x->p; + // expected-warning@-1 {{Dereference of null pointer (loaded from field 'p')}} + // expected-note@-2 {{Dereference of null pointer (loaded from field 'p')}} +} + // CHECK: diagnostics // CHECK-NEXT: // CHECK-NEXT: @@ -2637,4 +2651,253 @@ void testUseOfNullPointer() { // 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: line117 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Calling 'setFieldToNull' +// CHECK-NEXT: message +// CHECK-NEXT: Calling 'setFieldToNull' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Entered call from 'testSetFieldToNull' +// CHECK-NEXT: message +// CHECK-NEXT: Entered call from 'testSetFieldToNull' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col1 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line112 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col2 +// 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: line113 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col2 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line113 +// CHECK-NEXT: col9 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth1 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Null pointer value stored to field 'p' +// CHECK-NEXT: message +// CHECK-NEXT: Null pointer value stored to field 'p' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindevent +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col19 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Returning from 'setFieldToNull' +// CHECK-NEXT: message +// CHECK-NEXT: Returning from 'setFieldToNull' +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line117 +// CHECK-NEXT: col16 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col8 +// 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: line119 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col10 +// 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: line119 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: message +// CHECK-NEXT: Dereference of null pointer (loaded from field 'p') +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionDereference of null pointer (loaded from field 'p') +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeDereference of null pointer +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestSetFieldToNull +// CHECK-NEXT: issue_hash3 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line119 +// CHECK-NEXT: col10 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: // CHECK-NEXT: -- 2.40.0