DereferenceChecker.cpp revision e576af2754bfa309bb10a518bbc17c81b9e0723f
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// 10bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// This defines NullDerefChecker, a builtin check in GRExprEngine that performs 11bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// checks for null pointers at loads and stores. 12bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek// 13bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek//===----------------------------------------------------------------------===// 14bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 15dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h" 16b4b817d704287836b52b34369009e682f208aa2bTed Kremenek#include "clang/Analysis/PathSensitive/Checker.h" 17bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek#include "clang/Analysis/PathSensitive/GRExprEngine.h" 18bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek#include "clang/Analysis/PathSensitive/BugReporter.h" 19b4b817d704287836b52b34369009e682f208aa2bTed Kremenek#include "GRExprEngineInternalChecks.h" 20bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 21bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenekusing namespace clang; 22bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 23b4b817d704287836b52b34369009e682f208aa2bTed Kremeneknamespace { 24b4b817d704287836b52b34369009e682f208aa2bTed Kremenekclass VISIBILITY_HIDDEN DereferenceChecker : public Checker { 25b4b817d704287836b52b34369009e682f208aa2bTed Kremenek BuiltinBug *BT_null; 26b4b817d704287836b52b34369009e682f208aa2bTed Kremenek BuiltinBug *BT_undef; 27b4b817d704287836b52b34369009e682f208aa2bTed Kremenek llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; 28b4b817d704287836b52b34369009e682f208aa2bTed Kremenekpublic: 29b4b817d704287836b52b34369009e682f208aa2bTed Kremenek DereferenceChecker() : BT_null(0), BT_undef(0) {} 30b4b817d704287836b52b34369009e682f208aa2bTed Kremenek static void *getTag() { static int tag = 0; return &tag; } 31b4b817d704287836b52b34369009e682f208aa2bTed Kremenek void VisitLocation(CheckerContext &C, const Stmt *S, SVal location); 32bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 33b4b817d704287836b52b34369009e682f208aa2bTed Kremenek std::pair<ExplodedNode * const*, ExplodedNode * const*> 34b4b817d704287836b52b34369009e682f208aa2bTed Kremenek getImplicitNodes() const { 35b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return std::make_pair(ImplicitNullDerefNodes.data(), 36b4b817d704287836b52b34369009e682f208aa2bTed Kremenek ImplicitNullDerefNodes.data() + 37b4b817d704287836b52b34369009e682f208aa2bTed Kremenek ImplicitNullDerefNodes.size()); 38bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek } 39b4b817d704287836b52b34369009e682f208aa2bTed Kremenek}; 40b4b817d704287836b52b34369009e682f208aa2bTed Kremenek} // end anonymous namespace 41bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 42b4b817d704287836b52b34369009e682f208aa2bTed Kremenekvoid clang::RegisterDereferenceChecker(GRExprEngine &Eng) { 43b4b817d704287836b52b34369009e682f208aa2bTed Kremenek Eng.registerCheck(new DereferenceChecker()); 44bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek} 45dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek 46b4b817d704287836b52b34369009e682f208aa2bTed Kremenekstd::pair<ExplodedNode * const *, ExplodedNode * const *> 47b4b817d704287836b52b34369009e682f208aa2bTed Kremenekclang::GetImplicitNullDereferences(GRExprEngine &Eng) { 48b4b817d704287836b52b34369009e682f208aa2bTed Kremenek DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>(); 49b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!checker) 50b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return std::make_pair((ExplodedNode * const *) 0, 51b4b817d704287836b52b34369009e682f208aa2bTed Kremenek (ExplodedNode * const *) 0); 52b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return checker->getImplicitNodes(); 53dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek} 54dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek 55b4b817d704287836b52b34369009e682f208aa2bTed Kremenekvoid DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S, 56b4b817d704287836b52b34369009e682f208aa2bTed Kremenek SVal l) { 57b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Check for dereference of an undefined value. 58b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (l.isUndef()) { 5919d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek if (ExplodedNode *N = C.GenerateSink()) { 60b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!BT_undef) 61b4b817d704287836b52b34369009e682f208aa2bTed Kremenek BT_undef = new BuiltinBug("Dereference of undefined pointer value"); 62b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 63b4b817d704287836b52b34369009e682f208aa2bTed Kremenek EnhancedBugReport *report = 64d02e232c43b979758810794de24d3f5cde40fe93Benjamin Kramer new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); 65b4b817d704287836b52b34369009e682f208aa2bTed Kremenek report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 66b4b817d704287836b52b34369009e682f208aa2bTed Kremenek bugreporter::GetDerefExpr(N)); 67b4b817d704287836b52b34369009e682f208aa2bTed Kremenek C.EmitReport(report); 68b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 69b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 70b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 71b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 72b4b817d704287836b52b34369009e682f208aa2bTed Kremenek DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); 73b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 74b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Check for null dereferences. 75b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!isa<Loc>(location)) 76b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 77b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 78b4b817d704287836b52b34369009e682f208aa2bTed Kremenek const GRState *state = C.getState(); 79b4b817d704287836b52b34369009e682f208aa2bTed Kremenek const GRState *notNullState, *nullState; 80b4b817d704287836b52b34369009e682f208aa2bTed Kremenek llvm::tie(notNullState, nullState) = state->Assume(location); 81b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 82b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // The explicit NULL case. 83b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (nullState) { 8478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek if (!notNullState) { 8578d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // Generate an error node. 8619d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek ExplodedNode *N = C.GenerateSink(nullState); 8778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek if (!N) 88b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 8978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek 9078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // We know that 'location' cannot be non-null. This is what 9178d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // we call an "explicit" null dereference. 9278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek if (!BT_null) 93e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek BT_null = new BuiltinBug("Dereference of null pointer"); 94e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 95e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek llvm::SmallString<100> buf; 96e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 97e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek switch (S->getStmtClass()) { 98e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek case Stmt::UnaryOperatorClass: { 99e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek const UnaryOperator *U = cast<UnaryOperator>(S); 100e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek const Expr *SU = U->getSubExpr()->IgnoreParens(); 101e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) { 102e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 103e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek llvm::raw_svector_ostream os(buf); 104e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek os << "Dereference of null pointer loaded from variable '" 105e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek << VD->getName() << '\''; 106e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 107e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 108e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 109e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek default: 110e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek break; 111e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek } 112dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek 11378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek EnhancedBugReport *report = 114e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek new EnhancedBugReport(*BT_null, 115e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek buf.empty() ? BT_null->getDescription():buf.str(), 116e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek N); 117e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 11878d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 11978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek bugreporter::GetDerefExpr(N)); 12078d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek 12178d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek C.EmitReport(report); 12278d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek return; 12378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek } 12478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek else { 125b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Otherwise, we have the case where the location could either be 126b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // null or not-null. Record the error node as an "implicit" null 12778d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek // dereference. 12819d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek if (ExplodedNode *N = C.GenerateSink(nullState)) 12978d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek ImplicitNullDerefNodes.push_back(N); 130dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 131dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 132b4b817d704287836b52b34369009e682f208aa2bTed Kremenek 133b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // From this point forward, we know that the location is not null. 13419d67b52b73c04ef8eb663980330a1de2b47c845Ted Kremenek C.addTransition(notNullState); 135dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek} 136