DereferenceChecker.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This defines NullDerefChecker, a builtin check in ExprEngine that performs
  11. // checks for null pointers at loads and stores.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/AST/ExprObjC.h"
  16. #include "clang/AST/ExprOpenMP.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  20. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  21. #include "llvm/ADT/SmallString.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. using namespace clang;
  24. using namespace ento;
  25. namespace {
  26. class DereferenceChecker
  27. : public Checker< check::Location,
  28. check::Bind,
  29. EventDispatcher<ImplicitNullDerefEvent> > {
  30. mutable std::unique_ptr<BuiltinBug> BT_null;
  31. mutable std::unique_ptr<BuiltinBug> BT_undef;
  32. void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C,
  33. bool IsBind = false) const;
  34. public:
  35. void checkLocation(SVal location, bool isLoad, const Stmt* S,
  36. CheckerContext &C) const;
  37. void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
  38. static void AddDerefSource(raw_ostream &os,
  39. SmallVectorImpl<SourceRange> &Ranges,
  40. const Expr *Ex, const ProgramState *state,
  41. const LocationContext *LCtx,
  42. bool loadedFrom = false);
  43. };
  44. } // end anonymous namespace
  45. void
  46. DereferenceChecker::AddDerefSource(raw_ostream &os,
  47. SmallVectorImpl<SourceRange> &Ranges,
  48. const Expr *Ex,
  49. const ProgramState *state,
  50. const LocationContext *LCtx,
  51. bool loadedFrom) {
  52. Ex = Ex->IgnoreParenLValueCasts();
  53. switch (Ex->getStmtClass()) {
  54. default:
  55. break;
  56. case Stmt::DeclRefExprClass: {
  57. const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
  58. if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
  59. os << " (" << (loadedFrom ? "loaded from" : "from")
  60. << " variable '" << VD->getName() << "')";
  61. Ranges.push_back(DR->getSourceRange());
  62. }
  63. break;
  64. }
  65. case Stmt::MemberExprClass: {
  66. const MemberExpr *ME = cast<MemberExpr>(Ex);
  67. os << " (" << (loadedFrom ? "loaded from" : "via")
  68. << " field '" << ME->getMemberNameInfo() << "')";
  69. SourceLocation L = ME->getMemberLoc();
  70. Ranges.push_back(SourceRange(L, L));
  71. break;
  72. }
  73. case Stmt::ObjCIvarRefExprClass: {
  74. const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
  75. os << " (" << (loadedFrom ? "loaded from" : "via")
  76. << " ivar '" << IV->getDecl()->getName() << "')";
  77. SourceLocation L = IV->getLocation();
  78. Ranges.push_back(SourceRange(L, L));
  79. break;
  80. }
  81. }
  82. }
  83. void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
  84. CheckerContext &C, bool IsBind) const {
  85. // Generate an error node.
  86. ExplodedNode *N = C.generateSink(State);
  87. if (!N)
  88. return;
  89. // We know that 'location' cannot be non-null. This is what
  90. // we call an "explicit" null dereference.
  91. if (!BT_null)
  92. BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
  93. SmallString<100> buf;
  94. llvm::raw_svector_ostream os(buf);
  95. SmallVector<SourceRange, 2> Ranges;
  96. // Walk through lvalue casts to get the original expression
  97. // that syntactically caused the load.
  98. if (const Expr *expr = dyn_cast<Expr>(S))
  99. S = expr->IgnoreParenLValueCasts();
  100. if (IsBind) {
  101. if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
  102. if (BO->isAssignmentOp())
  103. S = BO->getRHS();
  104. } else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
  105. assert(DS->isSingleDecl() && "We process decls one by one");
  106. if (const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
  107. if (const Expr *Init = VD->getAnyInitializer())
  108. S = Init;
  109. }
  110. }
  111. switch (S->getStmtClass()) {
  112. case Stmt::ArraySubscriptExprClass: {
  113. os << "Array access";
  114. const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
  115. AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
  116. State.get(), N->getLocationContext());
  117. os << " results in a null pointer dereference";
  118. break;
  119. }
  120. case Stmt::OMPArraySectionExprClass: {
  121. os << "Array access";
  122. const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
  123. AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
  124. State.get(), N->getLocationContext());
  125. os << " results in a null pointer dereference";
  126. break;
  127. }
  128. case Stmt::UnaryOperatorClass: {
  129. os << "Dereference of null pointer";
  130. const UnaryOperator *U = cast<UnaryOperator>(S);
  131. AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
  132. State.get(), N->getLocationContext(), true);
  133. break;
  134. }
  135. case Stmt::MemberExprClass: {
  136. const MemberExpr *M = cast<MemberExpr>(S);
  137. if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) {
  138. os << "Access to field '" << M->getMemberNameInfo()
  139. << "' results in a dereference of a null pointer";
  140. AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
  141. State.get(), N->getLocationContext(), true);
  142. }
  143. break;
  144. }
  145. case Stmt::ObjCIvarRefExprClass: {
  146. const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
  147. os << "Access to instance variable '" << *IV->getDecl()
  148. << "' results in a dereference of a null pointer";
  149. AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
  150. State.get(), N->getLocationContext(), true);
  151. break;
  152. }
  153. default:
  154. break;
  155. }
  156. auto report = llvm::make_unique<BugReport>(
  157. *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
  158. bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S), *report);
  159. for (SmallVectorImpl<SourceRange>::iterator
  160. I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
  161. report->addRange(*I);
  162. C.emitReport(std::move(report));
  163. }
  164. void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
  165. CheckerContext &C) const {
  166. // Check for dereference of an undefined value.
  167. if (l.isUndef()) {
  168. if (ExplodedNode *N = C.generateSink()) {
  169. if (!BT_undef)
  170. BT_undef.reset(
  171. new BuiltinBug(this, "Dereference of undefined pointer value"));
  172. auto report =
  173. llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
  174. bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S),
  175. *report);
  176. C.emitReport(std::move(report));
  177. }
  178. return;
  179. }
  180. DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
  181. // Check for null dereferences.
  182. if (!location.getAs<Loc>())
  183. return;
  184. ProgramStateRef state = C.getState();
  185. ProgramStateRef notNullState, nullState;
  186. std::tie(notNullState, nullState) = state->assume(location);
  187. // The explicit NULL case.
  188. if (nullState) {
  189. if (!notNullState) {
  190. reportBug(nullState, S, C);
  191. return;
  192. }
  193. // Otherwise, we have the case where the location could either be
  194. // null or not-null. Record the error node as an "implicit" null
  195. // dereference.
  196. if (ExplodedNode *N = C.generateSink(nullState)) {
  197. ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
  198. /*IsDirectDereference=*/false};
  199. dispatchEvent(event);
  200. }
  201. }
  202. // From this point forward, we know that the location is not null.
  203. C.addTransition(notNullState);
  204. }
  205. void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
  206. CheckerContext &C) const {
  207. // If we're binding to a reference, check if the value is known to be null.
  208. if (V.isUndef())
  209. return;
  210. const MemRegion *MR = L.getAsRegion();
  211. const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
  212. if (!TVR)
  213. return;
  214. if (!TVR->getValueType()->isReferenceType())
  215. return;
  216. ProgramStateRef State = C.getState();
  217. ProgramStateRef StNonNull, StNull;
  218. std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
  219. if (StNull) {
  220. if (!StNonNull) {
  221. reportBug(StNull, S, C, /*isBind=*/true);
  222. return;
  223. }
  224. // At this point the value could be either null or non-null.
  225. // Record this as an "implicit" null dereference.
  226. if (ExplodedNode *N = C.generateSink(StNull)) {
  227. ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
  228. &C.getBugReporter(),
  229. /*IsDirectDereference=*/false};
  230. dispatchEvent(event);
  231. }
  232. }
  233. // Unlike a regular null dereference, initializing a reference with a
  234. // dereferenced null pointer does not actually cause a runtime exception in
  235. // Clang's implementation of references.
  236. //
  237. // int &r = *p; // safe??
  238. // if (p != NULL) return; // uh-oh
  239. // r = 5; // trap here
  240. //
  241. // The standard says this is invalid as soon as we try to create a "null
  242. // reference" (there is no such thing), but turning this into an assumption
  243. // that 'p' is never null will not match our actual runtime behavior.
  244. // So we do not record this assumption, allowing us to warn on the last line
  245. // of this example.
  246. //
  247. // We do need to add a transition because we may have generated a sink for
  248. // the "implicit" null dereference.
  249. C.addTransition(State, this);
  250. }
  251. void ento::registerDereferenceChecker(CheckerManager &mgr) {
  252. mgr.registerChecker<DereferenceChecker>();
  253. }