diff options
| author | Ted Kremenek <kremenek@apple.com> | 2010-10-26 00:06:13 +0000 |
|---|---|---|
| committer | Ted Kremenek <kremenek@apple.com> | 2010-10-26 00:06:13 +0000 |
| commit | 731310e13e8c29eed4cfcd5bc24bd6b2992e536f (patch) | |
| tree | 4e35ca81490d18b9d79cc1b2f929ba0ece3c7970 | |
| parent | e1961fe2891ed1dd08a6aee74e1a02b83653f9df (diff) | |
| download | bcm5719-llvm-731310e13e8c29eed4cfcd5bc24bd6b2992e536f.tar.gz bcm5719-llvm-731310e13e8c29eed4cfcd5bc24bd6b2992e536f.zip | |
Tweak null dereference checker to give better diagnostics for null dereferences resulting from array accesses.
llvm-svn: 117334
| -rw-r--r-- | clang/lib/Checker/DereferenceChecker.cpp | 66 | ||||
| -rw-r--r-- | clang/test/Analysis/null-deref-ps.c | 6 | ||||
| -rw-r--r-- | clang/test/Analysis/plist-output-alternate.m | 10 |
3 files changed, 55 insertions, 27 deletions
diff --git a/clang/lib/Checker/DereferenceChecker.cpp b/clang/lib/Checker/DereferenceChecker.cpp index 50392b28cd2..bb40a84cb00 100644 --- a/clang/lib/Checker/DereferenceChecker.cpp +++ b/clang/lib/Checker/DereferenceChecker.cpp @@ -36,6 +36,9 @@ public: ImplicitNullDerefNodes.data() + ImplicitNullDerefNodes.size()); } + void AddDerefSource(llvm::raw_ostream &os, + llvm::SmallVectorImpl<SourceRange> &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<SourceRange> &Ranges, + const Expr *Ex, + bool loadedFrom) { + switch (Ex->getStmtClass()) { + default: + return; + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); + if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { + os << " (" << (loadedFrom ? "loaded from" : "from") + << " variable '" << VD->getName() << "')"; + Ranges.push_back(DR->getSourceRange()); + } + return; + } + case Stmt::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(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<SourceRange, 2> Ranges; switch (S->getStmtClass()) { + case Stmt::ArraySubscriptExprClass: { + llvm::raw_svector_ostream os(buf); + os << "Array access"; + const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(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<UnaryOperator>(S); - const Expr *SU = U->getSubExpr()->IgnoreParens(); - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(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<MemberExpr>(S); - if (M->isArrow()) - if (DeclRefExpr *DR = - dyn_cast<DeclRefExpr>(M->getBase()->IgnoreParenCasts())) { - if (const VarDecl *VD = dyn_cast<VarDecl>(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/clang/test/Analysis/null-deref-ps.c b/clang/test/Analysis/null-deref-ps.c index 58f5d30c093..1e3f2db34b2 100644 --- a/clang/test/Analysis/null-deref-ps.c +++ b/clang/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/clang/test/Analysis/plist-output-alternate.m b/clang/test/Analysis/plist-output-alternate.m index d063348a116..12697b4c6c8 100644 --- a/clang/test/Analysis/plist-output-alternate.m +++ b/clang/test/Analysis/plist-output-alternate.m @@ -743,23 +743,23 @@ void rdar8331641(int x) { // CHECK: <array> // CHECK: <dict> // CHECK: <key>line</key><integer>37</integer> -// CHECK: <key>col</key><integer>3</integer> +// CHECK: <key>col</key><integer>7</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: <dict> // CHECK: <key>line</key><integer>37</integer> -// CHECK: <key>col</key><integer>8</integer> +// CHECK: <key>col</key><integer>7</integer> // CHECK: <key>file</key><integer>0</integer> // CHECK: </dict> // CHECK: </array> // CHECK: </array> // CHECK: <key>extended_message</key> -// CHECK: <string>Dereference of null pointer</string> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>message</key> -// CHECK: <string>Dereference of null pointer</string> +// CHECK: <string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: </dict> // CHECK: </array> -// CHECK: <key>description</key><string>Dereference of null pointer</string> +// CHECK: <key>description</key><string>Dereference of null pointer (loaded from field 'p')</string> // CHECK: <key>category</key><string>Logic error</string> // CHECK: <key>type</key><string>Dereference of null pointer</string> // CHECK: <key>location</key> |

