DereferenceChecker.cpp revision 80de487e03dd0f44e4572e2122ebc1aa6a3961f5
13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==// 23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// The LLVM Compiler Infrastructure 43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// This file is distributed under the University of Illinois Open Source 63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// License. See LICENSE.TXT for details. 73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// This defines NullDerefChecker, a builtin check in ExprEngine that performs 113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// checks for null pointers at loads and stores. 123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// 133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry//===----------------------------------------------------------------------===// 143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "ClangSACheckers.h" 163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "clang/AST/ExprObjC.h" 173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "clang/StaticAnalyzer/Core/Checker.h" 183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "clang/StaticAnalyzer/Core/CheckerManager.h" 193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "llvm/ADT/SmallString.h" 223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 233c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace clang; 243c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing namespace ento; 253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 263c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace { 273c827367444ee418f129b2c238299f49d3264554Jarkko Poyryclass DereferenceChecker 283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry : public Checker< check::Location, 293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry check::Bind, 303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry EventDispatcher<ImplicitNullDerefEvent> > { 313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry mutable OwningPtr<BuiltinBug> BT_null; 323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry mutable OwningPtr<BuiltinBug> BT_undef; 333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, 353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry bool IsBind = false) const; 363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 373c827367444ee418f129b2c238299f49d3264554Jarkko Poyrypublic: 383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry void checkLocation(SVal location, bool isLoad, const Stmt* S, 393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry CheckerContext &C) const; 403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const; 413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry static const MemRegion *AddDerefSource(raw_ostream &os, 433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SmallVectorImpl<SourceRange> &Ranges, 443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const Expr *Ex, const ProgramState *state, 453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const LocationContext *LCtx, 463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry bool loadedFrom = false); 473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry}; 483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // end anonymous namespace 493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 503c827367444ee418f129b2c238299f49d3264554Jarkko Poyryconst MemRegion * 513c827367444ee418f129b2c238299f49d3264554Jarkko PoyryDereferenceChecker::AddDerefSource(raw_ostream &os, 523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SmallVectorImpl<SourceRange> &Ranges, 533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const Expr *Ex, 543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const ProgramState *state, 553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const LocationContext *LCtx, 563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry bool loadedFrom) { 573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Ex = Ex->IgnoreParenLValueCasts(); 583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const MemRegion *sourceR = 0; 593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry switch (Ex->getStmtClass()) { 603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry default: 613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::DeclRefExprClass: { 633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); 643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << " (" << (loadedFrom ? "loaded from" : "from") 663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry << " variable '" << VD->getName() << "')"; 673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Ranges.push_back(DR->getSourceRange()); 683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sourceR = state->getLValue(VD, LCtx).getAsRegion(); 693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::MemberExprClass: { 733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const MemberExpr *ME = cast<MemberExpr>(Ex); 743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << " (" << (loadedFrom ? "loaded from" : "via") 753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry << " field '" << ME->getMemberNameInfo() << "')"; 763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SourceLocation L = ME->getMemberLoc(); 773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Ranges.push_back(SourceRange(L, L)); 783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return sourceR; 823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 843c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, 853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry CheckerContext &C, bool IsBind) const { 863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Generate an error node. 873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ExplodedNode *N = C.generateSink(State); 883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!N) 893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // We know that 'location' cannot be non-null. This is what 923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // we call an "explicit" null dereference. 933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!BT_null) 943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry BT_null.reset(new BuiltinBug("Dereference of null pointer")); 953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SmallString<100> buf; 973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry SmallVector<SourceRange, 2> Ranges; 983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Walk through lvalue casts to get the original expression 1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // that syntactically caused the load. 1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const Expr *expr = dyn_cast<Expr>(S)) 1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry S = expr->IgnoreParenLValueCasts(); 1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const MemRegion *sourceR = 0; 1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (IsBind) { 1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { 1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (BO->isAssignmentOp()) 1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry S = BO->getRHS(); 1103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { 1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry assert(DS->isSingleDecl() && "We process decls one by one"); 1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) 1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const Expr *Init = VD->getAnyInitializer()) 1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry S = Init; 1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry switch (S->getStmtClass()) { 1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::ArraySubscriptExprClass: { 1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::raw_svector_ostream os(buf); 1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << "Array access"; 1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); 1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), 1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry State.getPtr(), N->getLocationContext()); 1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << " results in a null pointer dereference"; 1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::UnaryOperatorClass: { 1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::raw_svector_ostream os(buf); 1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << "Dereference of null pointer"; 1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const UnaryOperator *U = cast<UnaryOperator>(S); 1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), 1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry State.getPtr(), N->getLocationContext(), true); 1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::MemberExprClass: { 1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const MemberExpr *M = cast<MemberExpr>(S); 1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (M->isArrow()) { 1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::raw_svector_ostream os(buf); 1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << "Access to field '" << M->getMemberNameInfo() 1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry << "' results in a dereference of a null pointer"; 1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), 1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry State.getPtr(), N->getLocationContext(), true); 1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry case Stmt::ObjCIvarRefExprClass: { 1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); 1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const DeclRefExpr *DR = 1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { 1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::raw_svector_ostream os(buf); 1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry os << "Instance variable access (via '" << VD->getName() 1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry << "') results in a null pointer dereference"; 1553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Ranges.push_back(IV->getSourceRange()); 1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry default: 1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry BugReport *report = 1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry new BugReport(*BT_null, 1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry buf.empty() ? BT_null->getDescription() : buf.str(), 1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry N); 1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report); 1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (SmallVectorImpl<SourceRange>::iterator 1723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) 1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry report->addRange(*I); 1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (sourceR) { 1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry report->markInteresting(sourceR); 1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR))); 1783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry C.EmitReport(report); 1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, 1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry CheckerContext &C) const { 1853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Check for dereference of an undefined value. 1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (l.isUndef()) { 1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (ExplodedNode *N = C.generateSink()) { 1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!BT_undef) 1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); 1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry BugReport *report = 1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry new BugReport(*BT_undef, BT_undef->getDescription(), N); 1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), 1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *report); 1953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry C.EmitReport(report); 1963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 1983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); 2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Check for null dereferences. 2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!isa<Loc>(location)) 2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ProgramStateRef state = C.getState(); 2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ProgramStateRef notNullState, nullState; 2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::tie(notNullState, nullState) = state->assume(location); 2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // The explicit NULL case. 2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (nullState) { 2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!notNullState) { 2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry reportBug(nullState, S, C); 2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Otherwise, we have the case where the location could either be 2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // null or not-null. Record the error node as an "implicit" null 2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // dereference. 2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (ExplodedNode *N = C.generateSink(nullState)) { 2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; 2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry dispatchEvent(event); 2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // From this point forward, we know that the location is not null. 2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry C.addTransition(notNullState); 2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, 2323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry CheckerContext &C) const { 2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // If we're binding to a reference, check if the value is known to be null. 2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (V.isUndef()) 2353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const MemRegion *MR = L.getAsRegion(); 2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR); 2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!TVR) 2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!TVR->getValueType()->isReferenceType()) 2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ProgramStateRef State = C.getState(); 2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2473c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ProgramStateRef StNonNull, StNull; 2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V)); 2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (StNull) { 2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!StNonNull) { 2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry reportBug(StNull, S, C, /*isBind=*/true); 2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return; 2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // At this point the value could be either null or non-null. 2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Record this as an "implicit" null dereference. 2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (ExplodedNode *N = C.generateSink(StNull)) { 2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry ImplicitNullDerefEvent event = { V, /*isLoad=*/true, N, 2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry &C.getBugReporter() }; 2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry dispatchEvent(event); 2623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Unlike a regular null dereference, initializing a reference with a 2663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // dereferenced null pointer does not actually cause a runtime exception in 2673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Clang's implementation of references. 2683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // 2693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // int &r = *p; // safe?? 2703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // if (p != NULL) return; // uh-oh 2713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // r = 5; // trap here 2723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // 2733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // The standard says this is invalid as soon as we try to create a "null 2743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // reference" (there is no such thing), but turning this into an assumption 2753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // that 'p' is never null will not match our actual runtime behavior. 2763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // So we do not record this assumption, allowing us to warn on the last line 2773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // of this example. 2783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // 2793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // We do need to add a transition because we may have generated a sink for 2803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // the "implicit" null dereference. 2813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry C.addTransition(State, this); 2823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2843c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid ento::registerDereferenceChecker(CheckerManager &mgr) { 2853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry mgr.registerChecker<DereferenceChecker>(); 2863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry