StackAddrEscapeChecker.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. //=== StackAddrEscapeChecker.cpp ----------------------------------*- 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 file defines stack address leak checker, which checks if an invalid
  11. // stack address is stored into a global or heap location. See CERT DCL30-C.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/StaticAnalyzer/Core/Checker.h"
  16. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  18. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
  20. #include "clang/Basic/SourceManager.h"
  21. #include "llvm/ADT/SmallString.h"
  22. using namespace clang;
  23. using namespace ento;
  24. namespace {
  25. class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
  26. check::EndPath > {
  27. mutable OwningPtr<BuiltinBug> BT_stackleak;
  28. mutable OwningPtr<BuiltinBug> BT_returnstack;
  29. public:
  30. void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
  31. void checkEndPath(CheckerContext &Ctx) const;
  32. private:
  33. void EmitStackError(CheckerContext &C, const MemRegion *R,
  34. const Expr *RetE) const;
  35. static SourceRange GenName(raw_ostream &os, const MemRegion *R,
  36. SourceManager &SM);
  37. };
  38. }
  39. SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
  40. const MemRegion *R,
  41. SourceManager &SM) {
  42. // Get the base region, stripping away fields and elements.
  43. R = R->getBaseRegion();
  44. SourceRange range;
  45. os << "Address of ";
  46. // Check if the region is a compound literal.
  47. if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
  48. const CompoundLiteralExpr *CL = CR->getLiteralExpr();
  49. os << "stack memory associated with a compound literal "
  50. "declared on line "
  51. << SM.getExpansionLineNumber(CL->getLocStart())
  52. << " returned to caller";
  53. range = CL->getSourceRange();
  54. }
  55. else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
  56. const Expr *ARE = AR->getExpr();
  57. SourceLocation L = ARE->getLocStart();
  58. range = ARE->getSourceRange();
  59. os << "stack memory allocated by call to alloca() on line "
  60. << SM.getExpansionLineNumber(L);
  61. }
  62. else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
  63. const BlockDecl *BD = BR->getCodeRegion()->getDecl();
  64. SourceLocation L = BD->getLocStart();
  65. range = BD->getSourceRange();
  66. os << "stack-allocated block declared on line "
  67. << SM.getExpansionLineNumber(L);
  68. }
  69. else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
  70. os << "stack memory associated with local variable '"
  71. << VR->getString() << '\'';
  72. range = VR->getDecl()->getSourceRange();
  73. }
  74. else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) {
  75. os << "stack memory associated with temporary object of type '"
  76. << TOR->getValueType().getAsString() << '\'';
  77. range = TOR->getExpr()->getSourceRange();
  78. }
  79. else {
  80. llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
  81. }
  82. return range;
  83. }
  84. void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
  85. const Expr *RetE) const {
  86. ExplodedNode *N = C.generateSink();
  87. if (!N)
  88. return;
  89. if (!BT_returnstack)
  90. BT_returnstack.reset(
  91. new BuiltinBug("Return of address to stack-allocated memory"));
  92. // Generate a report for this bug.
  93. SmallString<512> buf;
  94. llvm::raw_svector_ostream os(buf);
  95. SourceRange range = GenName(os, R, C.getSourceManager());
  96. os << " returned to caller";
  97. BugReport *report = new BugReport(*BT_returnstack, os.str(), N);
  98. report->addRange(RetE->getSourceRange());
  99. if (range.isValid())
  100. report->addRange(range);
  101. C.EmitReport(report);
  102. }
  103. void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
  104. CheckerContext &C) const {
  105. const Expr *RetE = RS->getRetValue();
  106. if (!RetE)
  107. return;
  108. SVal V = C.getState()->getSVal(RetE, C.getLocationContext());
  109. const MemRegion *R = V.getAsRegion();
  110. if (!R || !R->hasStackStorage())
  111. return;
  112. if (R->hasStackStorage()) {
  113. // Automatic reference counting automatically copies blocks.
  114. if (C.getASTContext().getLangOptions().ObjCAutoRefCount &&
  115. isa<BlockDataRegion>(R))
  116. return;
  117. EmitStackError(C, R, RetE);
  118. return;
  119. }
  120. }
  121. void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
  122. ProgramStateRef state = Ctx.getState();
  123. // Iterate over all bindings to global variables and see if it contains
  124. // a memory region in the stack space.
  125. class CallBack : public StoreManager::BindingsHandler {
  126. private:
  127. CheckerContext &Ctx;
  128. const StackFrameContext *CurSFC;
  129. public:
  130. SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
  131. CallBack(CheckerContext &CC) :
  132. Ctx(CC),
  133. CurSFC(CC.getLocationContext()->getCurrentStackFrame())
  134. {}
  135. bool HandleBinding(StoreManager &SMgr, Store store,
  136. const MemRegion *region, SVal val) {
  137. if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
  138. return true;
  139. const MemRegion *vR = val.getAsRegion();
  140. if (!vR)
  141. return true;
  142. // Under automated retain release, it is okay to assign a block
  143. // directly to a global variable.
  144. if (Ctx.getASTContext().getLangOptions().ObjCAutoRefCount &&
  145. isa<BlockDataRegion>(vR))
  146. return true;
  147. if (const StackSpaceRegion *SSR =
  148. dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
  149. // If the global variable holds a location in the current stack frame,
  150. // record the binding to emit a warning.
  151. if (SSR->getStackFrame() == CurSFC)
  152. V.push_back(std::make_pair(region, vR));
  153. }
  154. return true;
  155. }
  156. };
  157. CallBack cb(Ctx);
  158. state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
  159. if (cb.V.empty())
  160. return;
  161. // Generate an error node.
  162. ExplodedNode *N = Ctx.addTransition(state);
  163. if (!N)
  164. return;
  165. if (!BT_stackleak)
  166. BT_stackleak.reset(
  167. new BuiltinBug("Stack address stored into global variable",
  168. "Stack address was saved into a global variable. "
  169. "This is dangerous because the address will become "
  170. "invalid after returning from the function"));
  171. for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
  172. // Generate a report for this bug.
  173. SmallString<512> buf;
  174. llvm::raw_svector_ostream os(buf);
  175. SourceRange range = GenName(os, cb.V[i].second,
  176. Ctx.getSourceManager());
  177. os << " is still referred to by the global variable '";
  178. const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
  179. os << *VR->getDecl()
  180. << "' upon returning to the caller. This will be a dangling reference";
  181. BugReport *report = new BugReport(*BT_stackleak, os.str(), N);
  182. if (range.isValid())
  183. report->addRange(range);
  184. Ctx.EmitReport(report);
  185. }
  186. }
  187. void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) {
  188. mgr.registerChecker<StackAddrEscapeChecker>();
  189. }