DereferenceChecker.cpp revision c35fb7d67d515659ad2325b4f6ec97c9fe64fb63
1bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==// 2bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 3bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// The LLVM Compiler Infrastructure 4bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 5bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// This file is distributed under the University of Illinois Open Source 6bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// License. See LICENSE.TXT for details. 7bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 8bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===// 9bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 10d2592a34a059e7cbb2b11dc53649ac4912422909Argyrios Kyrtzidis// This defines NullDerefChecker, a builtin check in ExprEngine that performs 11bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// checks for null pointers at loads and stores. 12bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 13bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===// 14bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 15b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "ClangSACheckers.h" 16c35fb7d67d515659ad2325b4f6ec97c9fe64fb63Benjamin Kramer#include "clang/AST/ExprObjC.h" 17ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/Checker.h" 18b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/CheckerManager.h" 19b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 209b663716449b618ba0390b1dbebc54fa8e971124Ted Kremenek#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 22bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenekusing namespace clang; 239ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 24bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 25b4b817d704287836b52b34369009e682f208aa2bTed Kremeneknamespace { 26b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisclass DereferenceChecker 27ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis : public Checker< check::Location, 28b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis EventDispatcher<ImplicitNullDerefEvent> > { 29b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis mutable llvm::OwningPtr<BuiltinBug> BT_null; 30b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis mutable llvm::OwningPtr<BuiltinBug> BT_undef; 31b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 32b4b817d704287836b52b34369009e682f208aa2bTed Kremenekpublic: 33390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks void checkLocation(SVal location, bool isLoad, const Stmt* S, 34390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks CheckerContext &C) const; 35b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 365f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner static void AddDerefSource(raw_ostream &os, 375f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner SmallVectorImpl<SourceRange> &Ranges, 38b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis const Expr *Ex, bool loadedFrom = false); 39b4b817d704287836b52b34369009e682f208aa2bTed Kremenek}; 40b4b817d704287836b52b34369009e682f208aa2bTed Kremenek} // end anonymous namespace 41bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 425f9e272e632e951b1efe824cd16acb4d96077930Chris Lattnervoid DereferenceChecker::AddDerefSource(raw_ostream &os, 43390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks SmallVectorImpl<SourceRange> &Ranges, 44646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const Expr *Ex, 45646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek bool loadedFrom) { 46f6a1648197562e0b133440d612d9af297d0a86ccJohn McCall Ex = Ex->IgnoreParenLValueCasts(); 47646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek switch (Ex->getStmtClass()) { 48646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek default: 49646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek return; 50646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek case Stmt::DeclRefExprClass: { 51646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); 52646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 53646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << " (" << (loadedFrom ? "loaded from" : "from") 54646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek << " variable '" << VD->getName() << "')"; 55646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek Ranges.push_back(DR->getSourceRange()); 56646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 57646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek return; 58646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 59646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek case Stmt::MemberExprClass: { 60646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const MemberExpr *ME = cast<MemberExpr>(Ex); 61646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << " (" << (loadedFrom ? "loaded from" : "via") 62646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek << " field '" << ME->getMemberNameInfo() << "')"; 63646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek SourceLocation L = ME->getMemberLoc(); 64646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek Ranges.push_back(SourceRange(L, L)); 65646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek break; 66646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 67646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 68646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek} 69646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek 70390909c89c98ab1807e15e033a72e975f866fb23Anna Zaksvoid DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, 71b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis CheckerContext &C) const { 72b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Check for dereference of an undefined value. 73b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (l.isUndef()) { 74d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek if (ExplodedNode *N = C.generateSink()) { 75b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!BT_undef) 76b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); 77452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 78e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 79e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT_undef, BT_undef->getDescription(), N); 8050bbc165b063155cc23c360deb7b865502e068e2Anna Zaks report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 8150bbc165b063155cc23c360deb7b865502e068e2Anna Zaks bugreporter::GetDerefExpr(N))); 82b4b817d704287836b52b34369009e682f208aa2bTed Kremenek C.EmitReport(report); 83b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 84b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 85b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 86452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 87b4b817d704287836b52b34369009e682f208aa2bTed Kremenek DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); 88452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 89452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek // Check for null dereferences. 90b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!isa<Loc>(location)) 91b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 92452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 938bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 948bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef notNullState, nullState; 9528f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek llvm::tie(notNullState, nullState) = state->assume(location); 96452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 97b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // The explicit NULL case. 98b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (nullState) { 99452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek if (!notNullState) { 10078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // Generate an error node. 101d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek ExplodedNode *N = C.generateSink(nullState); 10278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek if (!N) 103b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 104452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 10578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // We know that 'location' cannot be non-null. This is what 106452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek // we call an "explicit" null dereference. 10778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek if (!BT_null) 108b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis BT_null.reset(new BuiltinBug("Dereference of null pointer")); 109452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 110e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek llvm::SmallString<100> buf; 1115f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner SmallVector<SourceRange, 2> Ranges; 112892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek 113892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek // Walk through lvalue casts to get the original expression 114892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek // that syntactically caused the load. 115892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek if (const Expr *expr = dyn_cast<Expr>(S)) 116892697dd2287caf7c29aaaa82909b0e90b8b63feTed Kremenek S = expr->IgnoreParenLValueCasts(); 117e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 118e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek switch (S->getStmtClass()) { 119646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek case Stmt::ArraySubscriptExprClass: { 120646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek llvm::raw_svector_ostream os(buf); 121646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << "Array access"; 122646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); 123646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts()); 124646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << " results in a null pointer dereference"; 125646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek break; 126646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 127e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek case Stmt::UnaryOperatorClass: { 128646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek llvm::raw_svector_ostream os(buf); 129646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << "Dereference of null pointer"; 130e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek const UnaryOperator *U = cast<UnaryOperator>(S); 131646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true); 132452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek break; 133452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek } 134452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek case Stmt::MemberExprClass: { 135452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek const MemberExpr *M = cast<MemberExpr>(S); 136646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek if (M->isArrow()) { 137646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek llvm::raw_svector_ostream os(buf); 138646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << "Access to field '" << M->getMemberNameInfo() 139646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek << "' results in a dereference of a null pointer"; 140646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true); 141646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 142452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek break; 143e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 1440853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek case Stmt::ObjCIvarRefExprClass: { 1450853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); 1460853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek if (const DeclRefExpr *DR = 1470853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { 1480853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 1490853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek llvm::raw_svector_ostream os(buf); 1500853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek os << "Instance variable access (via '" << VD->getName() 1510853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek << "') results in a null pointer dereference"; 1520853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek } 1530853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek } 1540853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek Ranges.push_back(IV->getSourceRange()); 1550853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek break; 1560853c7f840ee8e23c8271572e73ebab3d26b8fd5Ted Kremenek } 157e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek default: 158e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek break; 159e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 160dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek 161e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 162e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT_null, 163e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek buf.empty() ? BT_null->getDescription():buf.str(), 164e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek N); 165e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 16650bbc165b063155cc23c360deb7b865502e068e2Anna Zaks report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, 16750bbc165b063155cc23c360deb7b865502e068e2Anna Zaks bugreporter::GetDerefExpr(N))); 168452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 1695f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner for (SmallVectorImpl<SourceRange>::iterator 170452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) 171452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek report->addRange(*I); 172452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 17378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek C.EmitReport(report); 17478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek return; 17578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek } 17678d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek else { 177b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Otherwise, we have the case where the location could either be 178b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // null or not-null. Record the error node as an "implicit" null 179452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek // dereference. 180b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis if (ExplodedNode *N = C.generateSink(nullState)) { 181b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; 182b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis dispatchEvent(event); 183b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis } 184dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 185dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 186452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 187b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // From this point forward, we know that the location is not null. 1880bd6b110e908892d4b5c8671a9f435a1d72ad16aAnna Zaks C.addTransition(notNullState); 189dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek} 190b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 191b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisvoid ento::registerDereferenceChecker(CheckerManager &mgr) { 192b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis mgr.registerChecker<DereferenceChecker>(); 193b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis} 194