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 | 646c3c3beaf71fc64453d766dff22024dd5e0409 (patch) | |
tree | 06e50202a960ad683b1884ce830ef5d0a2c24dd0 /lib/Checker/DereferenceChecker.cpp | |
parent | 455553b7e5d5233acf48967874c43b4a5d7e24d1 (diff) |
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
Diffstat (limited to 'lib/Checker/DereferenceChecker.cpp')
-rw-r--r-- | lib/Checker/DereferenceChecker.cpp | 66 |
1 files changed, 47 insertions, 19 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<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: { |