DereferenceChecker.cpp revision e172e8b9e7fc67d7d03589af7e92fe777afcf33a
15c22c8074404797f1313b1334757254fb5c6487aEli Friedman//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==// 25c22c8074404797f1313b1334757254fb5c6487aEli Friedman// 35c22c8074404797f1313b1334757254fb5c6487aEli Friedman// The LLVM Compiler Infrastructure 45c22c8074404797f1313b1334757254fb5c6487aEli Friedman// 55c22c8074404797f1313b1334757254fb5c6487aEli Friedman// This file is distributed under the University of Illinois Open Source 65c22c8074404797f1313b1334757254fb5c6487aEli Friedman// License. See LICENSE.TXT for details. 75c22c8074404797f1313b1334757254fb5c6487aEli Friedman// 85c22c8074404797f1313b1334757254fb5c6487aEli Friedman//===----------------------------------------------------------------------===// 95c22c8074404797f1313b1334757254fb5c6487aEli Friedman// 105c22c8074404797f1313b1334757254fb5c6487aEli Friedman// This defines NullDerefChecker, a builtin check in ExprEngine that performs 115c22c8074404797f1313b1334757254fb5c6487aEli Friedman// checks for null pointers at loads and stores. 125c22c8074404797f1313b1334757254fb5c6487aEli Friedman// 13509150f973ae650a57b79010a3ec36e60e40f41dEli Friedman//===----------------------------------------------------------------------===// 14509150f973ae650a57b79010a3ec36e60e40f41dEli Friedman 155c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "ClangSACheckers.h" 165c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/Checker.h" 175c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/CheckerManager.h" 185c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 195c22c8074404797f1313b1334757254fb5c6487aEli Friedman#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 205c22c8074404797f1313b1334757254fb5c6487aEli Friedman 215c22c8074404797f1313b1334757254fb5c6487aEli Friedmanusing namespace clang; 225c22c8074404797f1313b1334757254fb5c6487aEli Friedmanusing namespace ento; 2398ca4f2a325f72374a477f9deba7d09e8999c29bDan Gohman 2498ca4f2a325f72374a477f9deba7d09e8999c29bDan Gohmannamespace { 255c22c8074404797f1313b1334757254fb5c6487aEli Friedmanclass DereferenceChecker 265c22c8074404797f1313b1334757254fb5c6487aEli Friedman : public Checker< check::Location, 275c22c8074404797f1313b1334757254fb5c6487aEli Friedman EventDispatcher<ImplicitNullDerefEvent> > { 285c22c8074404797f1313b1334757254fb5c6487aEli Friedman mutable llvm::OwningPtr<BuiltinBug> BT_null; 295c22c8074404797f1313b1334757254fb5c6487aEli Friedman mutable llvm::OwningPtr<BuiltinBug> BT_undef; 305c22c8074404797f1313b1334757254fb5c6487aEli Friedman 315c22c8074404797f1313b1334757254fb5c6487aEli Friedmanpublic: 325c22c8074404797f1313b1334757254fb5c6487aEli Friedman void checkLocation(SVal location, bool isLoad, CheckerContext &C) const; 335c22c8074404797f1313b1334757254fb5c6487aEli Friedman 345c22c8074404797f1313b1334757254fb5c6487aEli Friedman static void AddDerefSource(raw_ostream &os, 355c22c8074404797f1313b1334757254fb5c6487aEli Friedman SmallVectorImpl<SourceRange> &Ranges, 365c22c8074404797f1313b1334757254fb5c6487aEli Friedman const Expr *Ex, bool loadedFrom = false); 37d858e90f039f5fcdc2fa93035e911a5a9505cc50Dan Gohman}; 385c22c8074404797f1313b1334757254fb5c6487aEli Friedman} // end anonymous namespace 395c22c8074404797f1313b1334757254fb5c6487aEli Friedman 40c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesvoid DereferenceChecker::AddDerefSource(raw_ostream &os, 41c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines SmallVectorImpl<SourceRange> &Ranges, 42c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const Expr *Ex, 43ea387fc3b8cf12c3c6ad218b81eca156e8173bbaPreston Gurd bool loadedFrom) { 445c22c8074404797f1313b1334757254fb5c6487aEli Friedman Ex = Ex->IgnoreParenLValueCasts(); 45c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines switch (Ex->getStmtClass()) { 465c22c8074404797f1313b1334757254fb5c6487aEli Friedman default: 475c22c8074404797f1313b1334757254fb5c6487aEli Friedman return; 485c22c8074404797f1313b1334757254fb5c6487aEli Friedman case Stmt::DeclRefExprClass: { 495c22c8074404797f1313b1334757254fb5c6487aEli Friedman const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); 505c22c8074404797f1313b1334757254fb5c6487aEli Friedman if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 515c22c8074404797f1313b1334757254fb5c6487aEli Friedman os << " (" << (loadedFrom ? "loaded from" : "from") 525c22c8074404797f1313b1334757254fb5c6487aEli Friedman << " variable '" << VD->getName() << "')"; 53c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines Ranges.push_back(DR->getSourceRange()); 545c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 55c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return; 56c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 575c22c8074404797f1313b1334757254fb5c6487aEli Friedman case Stmt::MemberExprClass: { 58c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const MemberExpr *ME = cast<MemberExpr>(Ex); 59c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines os << " (" << (loadedFrom ? "loaded from" : "via") 605c22c8074404797f1313b1334757254fb5c6487aEli Friedman << " field '" << ME->getMemberNameInfo() << "')"; 61c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines SourceLocation L = ME->getMemberLoc(); 62c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines Ranges.push_back(SourceRange(L, L)); 63c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines break; 64c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 65c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 66c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines} 67c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 68c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesvoid DereferenceChecker::checkLocation(SVal l, bool isLoad, 69c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines CheckerContext &C) const { 70c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines // Check for dereference of an undefined value. 71c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (l.isUndef()) { 72c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (ExplodedNode *N = C.generateSink()) { 7306cc324b9da1dc8fb7360a560343c28f5e7a940aNadav Rotem if (!BT_undef) 74c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); 75c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 7666de2af815f97e484c1940ff157ffbb809931b20Nadav Rotem BugReport *report = 77c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines new BugReport(*BT_undef, BT_undef->getDescription(), N); 78c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 79c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines bugreporter::GetDerefExpr(N)); 80c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines C.EmitReport(report); 81c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 82c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return; 83c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 84c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 85c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); 86c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 87c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines // Check for null dereferences. 88c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (!isa<Loc>(location)) 89c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return; 90c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 91c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const Stmt *S = C.getStmt(); 92c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const ProgramState *state = C.getState(); 93c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const ProgramState *notNullState, *nullState; 94c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines llvm::tie(notNullState, nullState) = state->assume(location); 95c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 96c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines // The explicit NULL case. 97c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (nullState) { 98c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (!notNullState) { 99dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines // Generate an error node. 100c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines ExplodedNode *N = C.generateSink(nullState); 101c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (!N) 102c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return; 103aec5861bb6ace3734163c000cb75ca2e22e29caaNadav Rotem 104e757f00446fb3c80a96d729f0530b87e9148db7fNadav Rotem // We know that 'location' cannot be non-null. This is what 105e9b58d0aac4e89b53a4be0e6f289b66649e1512bNadav Rotem // we call an "explicit" null dereference. 106e9b58d0aac4e89b53a4be0e6f289b66649e1512bNadav Rotem if (!BT_null) 1075c22c8074404797f1313b1334757254fb5c6487aEli Friedman BT_null.reset(new BuiltinBug("Dereference of null pointer")); 108c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 109c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines llvm::SmallString<100> buf; 110c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines SmallVector<SourceRange, 2> Ranges; 111c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 112c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines // Walk through lvalue casts to get the original expression 113c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines // that syntactically caused the load. 114c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (const Expr *expr = dyn_cast<Expr>(S)) 115c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines S = expr->IgnoreParenLValueCasts(); 116c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 117c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines switch (S->getStmtClass()) { 118c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines case Stmt::ArraySubscriptExprClass: { 119c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines llvm::raw_svector_ostream os(buf); 120c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines os << "Array access"; 121c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); 122c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts()); 123c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines os << " results in a null pointer dereference"; 124c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines break; 125c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines } 126c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines case Stmt::UnaryOperatorClass: { 127c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines llvm::raw_svector_ostream os(buf); 1285c22c8074404797f1313b1334757254fb5c6487aEli Friedman os << "Dereference of null pointer"; 1295c22c8074404797f1313b1334757254fb5c6487aEli Friedman const UnaryOperator *U = cast<UnaryOperator>(S); 1305c22c8074404797f1313b1334757254fb5c6487aEli Friedman AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true); 1315c22c8074404797f1313b1334757254fb5c6487aEli Friedman break; 1325c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1335c22c8074404797f1313b1334757254fb5c6487aEli Friedman case Stmt::MemberExprClass: { 134d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem const MemberExpr *M = cast<MemberExpr>(S); 135d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem if (M->isArrow()) { 136d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem llvm::raw_svector_ostream os(buf); 13736b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines os << "Access to field '" << M->getMemberNameInfo() 138d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem << "' results in a dereference of a null pointer"; 139d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true); 140d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem } 141d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem break; 142d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem } 143d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem case Stmt::ObjCIvarRefExprClass: { 144d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); 145d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem if (const DeclRefExpr *DR = 146d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { 147d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 148d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem llvm::raw_svector_ostream os(buf); 149d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem os << "Instance variable access (via '" << VD->getName() 150d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem << "') results in a null pointer dereference"; 151d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem } 152d99a5a3ab4d47c6532bcf17a01677b1730599057Nadav Rotem } 1535c22c8074404797f1313b1334757254fb5c6487aEli Friedman Ranges.push_back(IV->getSourceRange()); 1545c22c8074404797f1313b1334757254fb5c6487aEli Friedman break; 1555c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1565c22c8074404797f1313b1334757254fb5c6487aEli Friedman default: 1575c22c8074404797f1313b1334757254fb5c6487aEli Friedman break; 1585c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1595c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1605c22c8074404797f1313b1334757254fb5c6487aEli Friedman BugReport *report = 16136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines new BugReport(*BT_null, 1625c22c8074404797f1313b1334757254fb5c6487aEli Friedman buf.empty() ? BT_null->getDescription():buf.str(), 1635c22c8074404797f1313b1334757254fb5c6487aEli Friedman N); 1645c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1655c22c8074404797f1313b1334757254fb5c6487aEli Friedman report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 1665c22c8074404797f1313b1334757254fb5c6487aEli Friedman bugreporter::GetDerefExpr(N)); 1675c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1685c22c8074404797f1313b1334757254fb5c6487aEli Friedman for (SmallVectorImpl<SourceRange>::iterator 1695c22c8074404797f1313b1334757254fb5c6487aEli Friedman I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) 1705c22c8074404797f1313b1334757254fb5c6487aEli Friedman report->addRange(*I); 1715c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1725c22c8074404797f1313b1334757254fb5c6487aEli Friedman C.EmitReport(report); 1735c22c8074404797f1313b1334757254fb5c6487aEli Friedman return; 1745c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1755c22c8074404797f1313b1334757254fb5c6487aEli Friedman else { 1765c22c8074404797f1313b1334757254fb5c6487aEli Friedman // Otherwise, we have the case where the location could either be 1775c22c8074404797f1313b1334757254fb5c6487aEli Friedman // null or not-null. Record the error node as an "implicit" null 1785c22c8074404797f1313b1334757254fb5c6487aEli Friedman // dereference. 1795c22c8074404797f1313b1334757254fb5c6487aEli Friedman if (ExplodedNode *N = C.generateSink(nullState)) { 1805c22c8074404797f1313b1334757254fb5c6487aEli Friedman ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; 1815c22c8074404797f1313b1334757254fb5c6487aEli Friedman dispatchEvent(event); 1825c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1835c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1845c22c8074404797f1313b1334757254fb5c6487aEli Friedman } 1855c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1865c22c8074404797f1313b1334757254fb5c6487aEli Friedman // From this point forward, we know that the location is not null. 1875c22c8074404797f1313b1334757254fb5c6487aEli Friedman C.addTransition(notNullState); 1885c22c8074404797f1313b1334757254fb5c6487aEli Friedman} 1895c22c8074404797f1313b1334757254fb5c6487aEli Friedman 1905c22c8074404797f1313b1334757254fb5c6487aEli Friedmanvoid ento::registerDereferenceChecker(CheckerManager &mgr) { 1915c22c8074404797f1313b1334757254fb5c6487aEli Friedman mgr.registerChecker<DereferenceChecker>(); 1925c22c8074404797f1313b1334757254fb5c6487aEli Friedman} 1935c22c8074404797f1313b1334757254fb5c6487aEli Friedman