From 86f1745be24c834175e7a8a51b12f9a0063d532e Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Thu, 18 Apr 2013 00:15:15 +0000 Subject: [PATCH] [analyzer] Tweak getDerefExpr more to track DeclRefExprs to references. In the committed example, we now see a note that tells us when the pointer was assumed to be null. This is the only case in which getDerefExpr returned null (failed to get the dereferenced expr) throughout our regression tests. (There were multiple occurrences of this one.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179736 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Core/BugReporterVisitors.cpp | 5 +- test/Analysis/inlining/path-notes.cpp | 227 ++++++++++++++++++ test/Analysis/reference.cpp | 2 +- 3 files changed, 232 insertions(+), 2 deletions(-) diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 9cf39d1e96..11fb1fcebd 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -41,7 +41,7 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) { } const Expr *bugreporter::getDerefExpr(const Stmt *S) { - // Pattern match for a few useful cases (do something smarter later): + // Pattern match for a few useful cases: // a[0], p->f, *p const Expr *E = dyn_cast(S); if (!E) @@ -73,6 +73,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { else if (const ArraySubscriptExpr *AE = dyn_cast(E)) { return AE->getBase(); } + else if (isDeclRefExprToReference(E)) { + return E; + } break; } diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp index b090b68fd6..96886afed8 100644 --- a/test/Analysis/inlining/path-notes.cpp +++ b/test/Analysis/inlining/path-notes.cpp @@ -244,6 +244,27 @@ void testGetDerefExprOnMemberExprWithADot() { // expected-note@-1 {{Dereference of undefined pointer value}} } + + +class A { +public: + void bar() const {} +}; +const A& testDeclRefExprToReferenceInGetDerefExpr(const A *ptr) { + const A& val = *ptr; //expected-note {{'val' initialized here}} + + // This is not valid C++; dynamic_cast with a reference type will throw an + // exception if the pointer does not match the expected type. However, our + // implementation of dynamic_cast will pass through a null pointer...or a + // "null reference"! So this branch is actually possible. + if (&val == 0) { //expected-note {{Assuming pointer value is null}} + // expected-note@-1 {{Taking true branch}} + val.bar(); // expected-warning {{Called C++ object pointer is null}} + // expected-note@-1 {{Called C++ object pointer is null}} + } + + return val; +} // CHECK: diagnostics // CHECK-NEXT: // CHECK-NEXT: @@ -4211,4 +4232,210 @@ void testGetDerefExprOnMemberExprWithADot() { // 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: line254 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line254 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line254 +// CHECK-NEXT: col14 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: 'val' initialized here +// CHECK-NEXT: message +// CHECK-NEXT: 'val' initialized here +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line254 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line254 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col4 +// 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: line260 +// CHECK-NEXT: col3 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col4 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col7 +// 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: line260 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col15 +// 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: message +// CHECK-NEXT: Assuming pointer value is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line260 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line262 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line262 +// CHECK-NEXT: col7 +// 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: line262 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: ranges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line262 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line262 +// CHECK-NEXT: col7 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: depth0 +// CHECK-NEXT: extended_message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: message +// CHECK-NEXT: Called C++ object pointer is null +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: descriptionCalled C++ object pointer is null +// CHECK-NEXT: categoryLogic error +// CHECK-NEXT: typeCalled C++ object pointer is null +// CHECK-NEXT: issue_context_kindfunction +// CHECK-NEXT: issue_contexttestDeclRefExprToReferenceInGetDerefExpr +// CHECK-NEXT: issue_hash9 +// CHECK-NEXT: location +// CHECK-NEXT: +// CHECK-NEXT: line262 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: // CHECK-NEXT: diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp index bcab80b04b..1dabe7bc1a 100644 --- a/test/Analysis/reference.cpp +++ b/test/Analysis/reference.cpp @@ -102,7 +102,7 @@ void testRetroactiveNullReference(int *x) { // "null reference". So the 'if' statement ought to be dead code. // However, Clang (and other compilers) don't actually check that a pointer // value is non-null in the implementation of references, so it is possible - // to produce a supposed "null reference" at runtime. The analyzer shoeuld + // to produce a supposed "null reference" at runtime. The analyzer should // still warn when it can prove such errors. int &y = *x; if (x != 0) -- 2.40.0