StackAddrLeakChecker.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. //=== StackAddrLeakChecker.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 "InternalChecks.h"
  15. #include "clang/StaticAnalyzer/BugReporter/BugType.h"
  16. #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
  17. #include "clang/StaticAnalyzer/PathSensitive/GRState.h"
  18. #include "clang/Basic/SourceManager.h"
  19. #include "llvm/ADT/SmallString.h"
  20. using namespace clang;
  21. using namespace ento;
  22. namespace {
  23. class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
  24. BuiltinBug *BT_stackleak;
  25. BuiltinBug *BT_returnstack;
  26. public:
  27. StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
  28. static void *getTag() {
  29. static int x;
  30. return &x;
  31. }
  32. void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
  33. void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
  34. private:
  35. void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
  36. SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
  37. SourceManager &SM);
  38. };
  39. }
  40. void ento::RegisterStackAddrLeakChecker(ExprEngine &Eng) {
  41. Eng.registerCheck(new StackAddrLeakChecker());
  42. }
  43. SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
  44. const MemRegion *R,
  45. SourceManager &SM) {
  46. // Get the base region, stripping away fields and elements.
  47. R = R->getBaseRegion();
  48. SourceRange range;
  49. os << "Address of ";
  50. // Check if the region is a compound literal.
  51. if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
  52. const CompoundLiteralExpr* CL = CR->getLiteralExpr();
  53. os << "stack memory associated with a compound literal "
  54. "declared on line "
  55. << SM.getInstantiationLineNumber(CL->getLocStart())
  56. << " returned to caller";
  57. range = CL->getSourceRange();
  58. }
  59. else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
  60. const Expr* ARE = AR->getExpr();
  61. SourceLocation L = ARE->getLocStart();
  62. range = ARE->getSourceRange();
  63. os << "stack memory allocated by call to alloca() on line "
  64. << SM.getInstantiationLineNumber(L);
  65. }
  66. else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
  67. const BlockDecl *BD = BR->getCodeRegion()->getDecl();
  68. SourceLocation L = BD->getLocStart();
  69. range = BD->getSourceRange();
  70. os << "stack-allocated block declared on line "
  71. << SM.getInstantiationLineNumber(L);
  72. }
  73. else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
  74. os << "stack memory associated with local variable '"
  75. << VR->getString() << '\'';
  76. range = VR->getDecl()->getSourceRange();
  77. }
  78. else {
  79. assert(false && "Invalid region in ReturnStackAddressChecker.");
  80. }
  81. return range;
  82. }
  83. void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
  84. const Expr *RetE) {
  85. ExplodedNode *N = C.generateSink();
  86. if (!N)
  87. return;
  88. if (!BT_returnstack)
  89. BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
  90. // Generate a report for this bug.
  91. llvm::SmallString<512> buf;
  92. llvm::raw_svector_ostream os(buf);
  93. SourceRange range = GenName(os, R, C.getSourceManager());
  94. os << " returned to caller";
  95. RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
  96. report->addRange(RetE->getSourceRange());
  97. if (range.isValid())
  98. report->addRange(range);
  99. C.EmitReport(report);
  100. }
  101. void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
  102. const ReturnStmt *RS) {
  103. const Expr *RetE = RS->getRetValue();
  104. if (!RetE)
  105. return;
  106. SVal V = C.getState()->getSVal(RetE);
  107. const MemRegion *R = V.getAsRegion();
  108. if (!R || !R->hasStackStorage())
  109. return;
  110. if (R->hasStackStorage()) {
  111. EmitStackError(C, R, RetE);
  112. return;
  113. }
  114. }
  115. void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
  116. ExprEngine &Eng) {
  117. const GRState *state = B.getState();
  118. // Iterate over all bindings to global variables and see if it contains
  119. // a memory region in the stack space.
  120. class CallBack : public StoreManager::BindingsHandler {
  121. private:
  122. const StackFrameContext *CurSFC;
  123. public:
  124. llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
  125. CallBack(const LocationContext *LCtx)
  126. : CurSFC(LCtx->getCurrentStackFrame()) {}
  127. bool HandleBinding(StoreManager &SMgr, Store store,
  128. const MemRegion *region, SVal val) {
  129. if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
  130. return true;
  131. const MemRegion *vR = val.getAsRegion();
  132. if (!vR)
  133. return true;
  134. if (const StackSpaceRegion *SSR =
  135. dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
  136. // If the global variable holds a location in the current stack frame,
  137. // record the binding to emit a warning.
  138. if (SSR->getStackFrame() == CurSFC)
  139. V.push_back(std::make_pair(region, vR));
  140. }
  141. return true;
  142. }
  143. };
  144. CallBack cb(B.getPredecessor()->getLocationContext());
  145. state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
  146. if (cb.V.empty())
  147. return;
  148. // Generate an error node.
  149. ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
  150. if (!N)
  151. return;
  152. if (!BT_stackleak)
  153. BT_stackleak =
  154. new BuiltinBug("Stack address stored into global variable",
  155. "Stack address was saved into a global variable. "
  156. "This is dangerous because the address will become "
  157. "invalid after returning from the function");
  158. for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
  159. // Generate a report for this bug.
  160. llvm::SmallString<512> buf;
  161. llvm::raw_svector_ostream os(buf);
  162. SourceRange range = GenName(os, cb.V[i].second,
  163. Eng.getContext().getSourceManager());
  164. os << " is still referred to by the global variable '";
  165. const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
  166. os << VR->getDecl()->getNameAsString()
  167. << "' upon returning to the caller. This will be a dangling reference";
  168. RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
  169. if (range.isValid())
  170. report->addRange(range);
  171. Eng.getBugReporter().EmitReport(report);
  172. }
  173. }