StackAddrEscapeChecker.cpp 8.3 KB

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