From 646c3c3beaf71fc64453d766dff22024dd5e0409 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 26 Oct 2010 00:06:13 +0000 Subject: [PATCH] Tweak null dereference checker to give better diagnostics for null dereferences resulting from array accesses. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117334 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Checker/DereferenceChecker.cpp | 66 ++++++++++++++++++-------- test/Analysis/null-deref-ps.c | 6 +-- test/Analysis/plist-output-alternate.m | 10 ++-- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/lib/Checker/DereferenceChecker.cpp b/lib/Checker/DereferenceChecker.cpp index 50392b28cd..bb40a84cb0 100644 --- a/lib/Checker/DereferenceChecker.cpp +++ b/lib/Checker/DereferenceChecker.cpp @@ -36,6 +36,9 @@ public: ImplicitNullDerefNodes.data() + ImplicitNullDerefNodes.size()); } + void AddDerefSource(llvm::raw_ostream &os, + llvm::SmallVectorImpl &Ranges, + const Expr *Ex, bool loadedFrom = false); }; } // end anonymous namespace @@ -52,6 +55,33 @@ clang::GetImplicitNullDereferences(GRExprEngine &Eng) { return checker->getImplicitNodes(); } +void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, + llvm::SmallVectorImpl &Ranges, + const Expr *Ex, + bool loadedFrom) { + switch (Ex->getStmtClass()) { + default: + return; + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DR = cast(Ex); + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + os << " (" << (loadedFrom ? "loaded from" : "from") + << " variable '" << VD->getName() << "')"; + Ranges.push_back(DR->getSourceRange()); + } + return; + } + case Stmt::MemberExprClass: { + const MemberExpr *ME = cast(Ex); + os << " (" << (loadedFrom ? "loaded from" : "via") + << " field '" << ME->getMemberNameInfo() << "')"; + SourceLocation L = ME->getMemberLoc(); + Ranges.push_back(SourceRange(L, L)); + break; + } + } +} + void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { // Check for dereference of an undefined value. @@ -96,31 +126,29 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, llvm::SmallVector Ranges; switch (S->getStmtClass()) { + case Stmt::ArraySubscriptExprClass: { + llvm::raw_svector_ostream os(buf); + os << "Array access"; + const ArraySubscriptExpr *AE = cast(S); + AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts()); + os << " results in a null pointer dereference"; + break; + } case Stmt::UnaryOperatorClass: { + llvm::raw_svector_ostream os(buf); + os << "Dereference of null pointer"; const UnaryOperator *U = cast(S); - const Expr *SU = U->getSubExpr()->IgnoreParens(); - if (const DeclRefExpr *DR = dyn_cast(SU)) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) { - llvm::raw_svector_ostream os(buf); - os << "Dereference of null pointer (loaded from variable '" - << VD->getName() << "')"; - Ranges.push_back(DR->getSourceRange()); - } - } + AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast(S); - if (M->isArrow()) - if (DeclRefExpr *DR = - dyn_cast(M->getBase()->IgnoreParenCasts())) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) { - llvm::raw_svector_ostream os(buf); - os << "Field access results in a dereference of a null pointer " - "(loaded from variable '" << VD->getName() << "')"; - Ranges.push_back(M->getBase()->getSourceRange()); - } - } + if (M->isArrow()) { + llvm::raw_svector_ostream os(buf); + os << "Access to field '" << M->getMemberNameInfo() + << "' results in a dereference of a null pointer"; + AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true); + } break; } case Stmt::ObjCIvarRefExprClass: { diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c index 58f5d30c09..1e3f2db34b 100644 --- a/test/Analysis/null-deref-ps.c +++ b/test/Analysis/null-deref-ps.c @@ -26,7 +26,7 @@ int f2(struct foo_struct* p) { if (p) p->x = 1; - return p->x++; // expected-warning{{Field access results in a dereference of a null pointer (loaded from variable 'p')}} + return p->x++; // expected-warning{{Access to field 'x' results in a dereference of a null pointer (loaded from variable 'p')}} } int f3(char* x) { @@ -36,7 +36,7 @@ int f3(char* x) { if (x) return x[i - 1]; - return x[i+1]; // expected-warning{{Dereference of null pointer}} + return x[i+1]; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} } int f3_b(char* x) { @@ -46,7 +46,7 @@ int f3_b(char* x) { if (x) return x[i - 1]; - return x[i+1]++; // expected-warning{{Dereference of null pointer}} + return x[i+1]++; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} } int f4(int *p) { diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m index d063348a11..12697b4c6c 100644 --- a/test/Analysis/plist-output-alternate.m +++ b/test/Analysis/plist-output-alternate.m @@ -743,23 +743,23 @@ void rdar8331641(int x) { // CHECK: // CHECK: // CHECK: line37 -// CHECK: col3 +// CHECK: col7 // CHECK: file0 // CHECK: // CHECK: // CHECK: line37 -// CHECK: col8 +// CHECK: col7 // CHECK: file0 // CHECK: // CHECK: // CHECK: // CHECK: extended_message -// CHECK: Dereference of null pointer +// CHECK: Dereference of null pointer (loaded from field 'p') // CHECK: message -// CHECK: Dereference of null pointer +// CHECK: Dereference of null pointer (loaded from field 'p') // CHECK: // CHECK: -// CHECK: descriptionDereference of null pointer +// CHECK: descriptionDereference of null pointer (loaded from field 'p') // CHECK: categoryLogic error // CHECK: typeDereference of null pointer // CHECK: location -- 2.40.0