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" 218fe83e1df954d72c0f4ffc15d20a5222ec151c21Benjamin Kramer#include "llvm/ADT/SmallString.h" 22bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 23bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenekusing namespace clang; 249ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 25bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 26b4b817d704287836b52b34369009e682f208aa2bTed Kremeneknamespace { 27b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisclass DereferenceChecker 28ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis : public Checker< check::Location, 299f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose check::Bind, 309f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose EventDispatcher<ImplicitNullDerefEvent> > { 316f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith mutable OwningPtr<BuiltinBug> BT_null; 326f42b62b6194f53bcbc349f5d17388e1936535d7Dylan Noblesmith mutable OwningPtr<BuiltinBug> BT_undef; 33b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 349f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C, 359f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose bool IsBind = false) const; 369f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 37b4b817d704287836b52b34369009e682f208aa2bTed Kremenekpublic: 38390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks void checkLocation(SVal location, bool isLoad, const Stmt* S, 39390909c89c98ab1807e15e033a72e975f866fb23Anna Zaks CheckerContext &C) const; 409f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const; 41b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 429bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks static void AddDerefSource(raw_ostream &os, 435f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner SmallVectorImpl<SourceRange> &Ranges, 4476aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek const Expr *Ex, const ProgramState *state, 4576aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek const LocationContext *LCtx, 4676aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek bool loadedFrom = false); 47b4b817d704287836b52b34369009e682f208aa2bTed Kremenek}; 48b4b817d704287836b52b34369009e682f208aa2bTed Kremenek} // end anonymous namespace 49bc3a021df7f9ee4c4d1e9ec3c2aac2ef6d883206Ted Kremenek 509bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaksvoid 5176aadc346c3a4c363238a1e1232f324c3355d9e0Ted KremenekDereferenceChecker::AddDerefSource(raw_ostream &os, 5276aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek SmallVectorImpl<SourceRange> &Ranges, 5376aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek const Expr *Ex, 5476aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek const ProgramState *state, 5576aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek const LocationContext *LCtx, 5676aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek bool loadedFrom) { 57f6a1648197562e0b133440d612d9af297d0a86ccJohn McCall Ex = Ex->IgnoreParenLValueCasts(); 58646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek switch (Ex->getStmtClass()) { 59646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek default: 6076aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek break; 61646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek case Stmt::DeclRefExprClass: { 62646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const DeclRefExpr *DR = cast<DeclRefExpr>(Ex); 63646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 64646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << " (" << (loadedFrom ? "loaded from" : "from") 65646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek << " variable '" << VD->getName() << "')"; 66646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek Ranges.push_back(DR->getSourceRange()); 67646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 6876aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek break; 69646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 70646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek case Stmt::MemberExprClass: { 71646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek const MemberExpr *ME = cast<MemberExpr>(Ex); 72646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek os << " (" << (loadedFrom ? "loaded from" : "via") 73646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek << " field '" << ME->getMemberNameInfo() << "')"; 74646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek SourceLocation L = ME->getMemberLoc(); 75646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek Ranges.push_back(SourceRange(L, L)); 76646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek break; 77646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 78646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek } 79646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek} 80646c3c3beaf71fc64453d766dff22024dd5e0409Ted Kremenek 819f3b9d54ccbbf212591602f389ebde7923627490Jordan Rosevoid DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, 829f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose CheckerContext &C, bool IsBind) const { 839f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // Generate an error node. 849f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose ExplodedNode *N = C.generateSink(State); 859f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (!N) 869f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose return; 879f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 889f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // We know that 'location' cannot be non-null. This is what 899f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // we call an "explicit" null dereference. 909f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (!BT_null) 919f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose BT_null.reset(new BuiltinBug("Dereference of null pointer")); 929f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 939f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose SmallString<100> buf; 949f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose SmallVector<SourceRange, 2> Ranges; 959f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 969f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // Walk through lvalue casts to get the original expression 979f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // that syntactically caused the load. 989f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const Expr *expr = dyn_cast<Expr>(S)) 999f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose S = expr->IgnoreParenLValueCasts(); 1009f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1019f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (IsBind) { 1029f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { 1039f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (BO->isAssignmentOp()) 1049f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose S = BO->getRHS(); 1059f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { 1069f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose assert(DS->isSingleDecl() && "We process decls one by one"); 1079f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl())) 1089f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const Expr *Init = VD->getAnyInitializer()) 1099f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose S = Init; 1109f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1119f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1129f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1139f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose switch (S->getStmtClass()) { 1149f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose case Stmt::ArraySubscriptExprClass: { 1159f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose llvm::raw_svector_ostream os(buf); 1169f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose os << "Array access"; 1179f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); 1189bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), 1199bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks State.getPtr(), N->getLocationContext()); 1209f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose os << " results in a null pointer dereference"; 1219f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose break; 1229f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1239f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose case Stmt::UnaryOperatorClass: { 1249f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose llvm::raw_svector_ostream os(buf); 1259f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose os << "Dereference of null pointer"; 1269f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const UnaryOperator *U = cast<UnaryOperator>(S); 1279bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), 1289bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks State.getPtr(), N->getLocationContext(), true); 1299f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose break; 1309f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1319f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose case Stmt::MemberExprClass: { 1329f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const MemberExpr *M = cast<MemberExpr>(S); 1339b925ac059089dfe74e3b8fa5effe519fb9ee885Anna Zaks if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) { 1349f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose llvm::raw_svector_ostream os(buf); 1359f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose os << "Access to field '" << M->getMemberNameInfo() 1369f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose << "' results in a dereference of a null pointer"; 1379bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), 1389bc1e6db1c0a1d57eaf9b35eb3ab8a60ffb437edAnna Zaks State.getPtr(), N->getLocationContext(), true); 1399f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1409f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose break; 1419f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1429f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose case Stmt::ObjCIvarRefExprClass: { 1439f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); 1449f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const DeclRefExpr *DR = 1459f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { 1469f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { 1479f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose llvm::raw_svector_ostream os(buf); 1489f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose os << "Instance variable access (via '" << VD->getName() 1499f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose << "') results in a null pointer dereference"; 1509f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1519f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1529f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose Ranges.push_back(IV->getSourceRange()); 1539f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose break; 1549f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1559f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose default: 1569f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose break; 1579f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 1589f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1599f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose BugReport *report = 1609f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose new BugReport(*BT_null, 1619f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose buf.empty() ? BT_null->getDescription() : buf.str(), 1629f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose N); 1639f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 164a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report); 1659f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1669f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose for (SmallVectorImpl<SourceRange>::iterator 1679f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) 1689f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose report->addRange(*I); 1699f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1709f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose C.EmitReport(report); 1719f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose} 1729f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 173390909c89c98ab1807e15e033a72e975f866fb23Anna Zaksvoid DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, 174b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis CheckerContext &C) const { 175b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // Check for dereference of an undefined value. 176b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (l.isUndef()) { 177d048c6ef5b6cfaa0cecb8cc1d4bdace32ed21d07Ted Kremenek if (ExplodedNode *N = C.generateSink()) { 178b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!BT_undef) 179b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); 180452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 181e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks BugReport *report = 182e172e8b9e7fc67d7d03589af7e92fe777afcf33aAnna Zaks new BugReport(*BT_undef, BT_undef->getDescription(), N); 183a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), 184a1f81bb0e55749a1414b1b5124bb83b9052ff2acJordan Rose *report); 185b4b817d704287836b52b34369009e682f208aa2bTed Kremenek C.EmitReport(report); 186b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 187b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 188b4b817d704287836b52b34369009e682f208aa2bTed Kremenek } 189452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 190b4b817d704287836b52b34369009e682f208aa2bTed Kremenek DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l); 191452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 192452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek // Check for null dereferences. 193b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (!isa<Loc>(location)) 194b4b817d704287836b52b34369009e682f208aa2bTed Kremenek return; 195452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 1968bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef state = C.getState(); 1979f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 1988bef8238181a30e52dea380789a7e2d760eac532Ted Kremenek ProgramStateRef notNullState, nullState; 19928f47b92e760ccf641ac91cb0fe1c12d9ca89795Ted Kremenek llvm::tie(notNullState, nullState) = state->assume(location); 200452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 201b4b817d704287836b52b34369009e682f208aa2bTed Kremenek // The explicit NULL case. 202b4b817d704287836b52b34369009e682f208aa2bTed Kremenek if (nullState) { 203452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek if (!notNullState) { 2049f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose reportBug(nullState, S, C); 2059f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose return; 2069f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 207dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek 2089f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // Otherwise, we have the case where the location could either be 2099f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // null or not-null. Record the error node as an "implicit" null 2109f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // dereference. 2119f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (ExplodedNode *N = C.generateSink(nullState)) { 2129f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; 2139f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose dispatchEvent(event); 2149f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 2159f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose } 216e576af2754bfa309bb10a518bbc17c81b9e0723fTed Kremenek 2179f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // From this point forward, we know that the location is not null. 2189f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose C.addTransition(notNullState); 2199f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose} 220452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 2219f3b9d54ccbbf212591602f389ebde7923627490Jordan Rosevoid DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, 2229f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose CheckerContext &C) const { 223522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // If we're binding to a reference, check if the value is known to be null. 2249f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (V.isUndef()) 2259f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose return; 226452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 2279f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const MemRegion *MR = L.getAsRegion(); 2289f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR); 2299f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (!TVR) 2309f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose return; 23176aadc346c3a4c363238a1e1232f324c3355d9e0Ted Kremenek 2329f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (!TVR->getValueType()->isReferenceType()) 2339f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose return; 2349f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 2359f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose ProgramStateRef State = C.getState(); 2369f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 2379f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose ProgramStateRef StNonNull, StNull; 2389f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V)); 2399f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 2409f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (StNull) { 2419f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (!StNonNull) { 2429f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose reportBug(StNull, S, C, /*isBind=*/true); 24378d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek return; 24478d722fb2b55e53914bc80046db65d113138b2a7Ted Kremenek } 2459f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose 2469f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // At this point the value could be either null or non-null. 2479f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose // Record this as an "implicit" null dereference. 2489f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose if (ExplodedNode *N = C.generateSink(StNull)) { 2499f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose ImplicitNullDerefEvent event = { V, /*isLoad=*/true, N, 2509f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose &C.getBugReporter() }; 2519f3b9d54ccbbf212591602f389ebde7923627490Jordan Rose dispatchEvent(event); 252dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 253dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek } 254452b84ded735d7e7de6d099953ab959a4c9910f0Ted Kremenek 255522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // Unlike a regular null dereference, initializing a reference with a 256522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // dereferenced null pointer does not actually cause a runtime exception in 257522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // Clang's implementation of references. 258522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // 259522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // int &r = *p; // safe?? 260522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // if (p != NULL) return; // uh-oh 261522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // r = 5; // trap here 262522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // 263522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // The standard says this is invalid as soon as we try to create a "null 264522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // reference" (there is no such thing), but turning this into an assumption 265522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // that 'p' is never null will not match our actual runtime behavior. 266522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // So we do not record this assumption, allowing us to warn on the last line 267522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // of this example. 268522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // 269522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // We do need to add a transition because we may have generated a sink for 270522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose // the "implicit" null dereference. 271522f46f497d9ccecc8bc2f5ec132b9bb7060dee1Jordan Rose C.addTransition(State, this); 272dc998c1b90a17d747ca2fb05e967779740747162Ted Kremenek} 273b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis 274b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidisvoid ento::registerDereferenceChecker(CheckerManager &mgr) { 275b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis mgr.registerChecker<DereferenceChecker>(); 276b3d74da3e1620c9a7a378afb5f244e4987e6713eArgyrios Kyrtzidis} 277