clang  3.9.0
StackAddrEscapeChecker.cpp
Go to the documentation of this file.
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 
15 #include "ClangSACheckers.h"
16 #include "clang/AST/ExprCXX.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
30  check::EndFunction > {
31  mutable std::unique_ptr<BuiltinBug> BT_stackleak;
32  mutable std::unique_ptr<BuiltinBug> BT_returnstack;
33 
34 public:
35  void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
36  void checkEndFunction(CheckerContext &Ctx) const;
37 private:
38  void EmitStackError(CheckerContext &C, const MemRegion *R,
39  const Expr *RetE) const;
40  static SourceRange genName(raw_ostream &os, const MemRegion *R,
41  ASTContext &Ctx);
42 };
43 }
44 
45 SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
46  ASTContext &Ctx) {
47  // Get the base region, stripping away fields and elements.
48  R = R->getBaseRegion();
50  SourceRange range;
51  os << "Address of ";
52 
53  // Check if the region is a compound literal.
54  if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
55  const CompoundLiteralExpr *CL = CR->getLiteralExpr();
56  os << "stack memory associated with a compound literal "
57  "declared on line "
59  << " returned to caller";
60  range = CL->getSourceRange();
61  }
62  else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
63  const Expr *ARE = AR->getExpr();
64  SourceLocation L = ARE->getLocStart();
65  range = ARE->getSourceRange();
66  os << "stack memory allocated by call to alloca() on line "
67  << SM.getExpansionLineNumber(L);
68  }
69  else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
70  const BlockDecl *BD = BR->getCodeRegion()->getDecl();
71  SourceLocation L = BD->getLocStart();
72  range = BD->getSourceRange();
73  os << "stack-allocated block declared on line "
74  << SM.getExpansionLineNumber(L);
75  }
76  else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
77  os << "stack memory associated with local variable '"
78  << VR->getString() << '\'';
79  range = VR->getDecl()->getSourceRange();
80  }
81  else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) {
82  QualType Ty = TOR->getValueType().getLocalUnqualifiedType();
83  os << "stack memory associated with temporary object of type '";
84  Ty.print(os, Ctx.getPrintingPolicy());
85  os << "'";
86  range = TOR->getExpr()->getSourceRange();
87  }
88  else {
89  llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
90  }
91 
92  return range;
93 }
94 
95 void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
96  const Expr *RetE) const {
98 
99  if (!N)
100  return;
101 
102  if (!BT_returnstack)
103  BT_returnstack.reset(
104  new BuiltinBug(this, "Return of address to stack-allocated memory"));
105 
106  // Generate a report for this bug.
107  SmallString<512> buf;
108  llvm::raw_svector_ostream os(buf);
109  SourceRange range = genName(os, R, C.getASTContext());
110  os << " returned to caller";
111  auto report = llvm::make_unique<BugReport>(*BT_returnstack, os.str(), N);
112  report->addRange(RetE->getSourceRange());
113  if (range.isValid())
114  report->addRange(range);
115 
116  C.emitReport(std::move(report));
117 }
118 
119 void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
120  CheckerContext &C) const {
121 
122  const Expr *RetE = RS->getRetValue();
123  if (!RetE)
124  return;
125  RetE = RetE->IgnoreParens();
126 
127  const LocationContext *LCtx = C.getLocationContext();
128  SVal V = C.getState()->getSVal(RetE, LCtx);
129  const MemRegion *R = V.getAsRegion();
130 
131  if (!R)
132  return;
133 
134  const StackSpaceRegion *SS =
135  dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace());
136 
137  if (!SS)
138  return;
139 
140  // Return stack memory in an ancestor stack frame is fine.
141  const StackFrameContext *CurFrame = LCtx->getCurrentStackFrame();
142  const StackFrameContext *MemFrame = SS->getStackFrame();
143  if (MemFrame != CurFrame)
144  return;
145 
146  // Automatic reference counting automatically copies blocks.
147  if (C.getASTContext().getLangOpts().ObjCAutoRefCount &&
148  isa<BlockDataRegion>(R))
149  return;
150 
151  // Returning a record by value is fine. (In this case, the returned
152  // expression will be a copy-constructor, possibly wrapped in an
153  // ExprWithCleanups node.)
154  if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
155  RetE = Cleanup->getSubExpr();
156  if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType())
157  return;
158 
159  // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
160  // so the stack address is not escaping here.
161  if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
162  if (isa<BlockDataRegion>(R) &&
163  ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
164  return;
165  }
166  }
167 
168  EmitStackError(C, R, RetE);
169 }
170 
171 void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
173 
174  // Iterate over all bindings to global variables and see if it contains
175  // a memory region in the stack space.
176  class CallBack : public StoreManager::BindingsHandler {
177  private:
178  CheckerContext &Ctx;
179  const StackFrameContext *CurSFC;
180  public:
182 
183  CallBack(CheckerContext &CC) :
184  Ctx(CC),
185  CurSFC(CC.getLocationContext()->getCurrentStackFrame())
186  {}
187 
188  bool HandleBinding(StoreManager &SMgr, Store store,
189  const MemRegion *region, SVal val) override {
190 
191  if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
192  return true;
193 
194  const MemRegion *vR = val.getAsRegion();
195  if (!vR)
196  return true;
197 
198  // Under automated retain release, it is okay to assign a block
199  // directly to a global variable.
200  if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount &&
201  isa<BlockDataRegion>(vR))
202  return true;
203 
204  if (const StackSpaceRegion *SSR =
205  dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
206  // If the global variable holds a location in the current stack frame,
207  // record the binding to emit a warning.
208  if (SSR->getStackFrame() == CurSFC)
209  V.push_back(std::make_pair(region, vR));
210  }
211 
212  return true;
213  }
214  };
215 
216  CallBack cb(Ctx);
217  state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
218 
219  if (cb.V.empty())
220  return;
221 
222  // Generate an error node.
223  ExplodedNode *N = Ctx.generateNonFatalErrorNode(state);
224  if (!N)
225  return;
226 
227  if (!BT_stackleak)
228  BT_stackleak.reset(
229  new BuiltinBug(this, "Stack address stored into global variable",
230  "Stack address was saved into a global variable. "
231  "This is dangerous because the address will become "
232  "invalid after returning from the function"));
233 
234  for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
235  // Generate a report for this bug.
236  SmallString<512> buf;
237  llvm::raw_svector_ostream os(buf);
238  SourceRange range = genName(os, cb.V[i].second, Ctx.getASTContext());
239  os << " is still referred to by the ";
240  if (isa<StaticGlobalSpaceRegion>(cb.V[i].first->getMemorySpace()))
241  os << "static";
242  else
243  os << "global";
244  os << " variable '";
245  const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
246  os << *VR->getDecl()
247  << "' upon returning to the caller. This will be a dangling reference";
248  auto report = llvm::make_unique<BugReport>(*BT_stackleak, os.str(), N);
249  if (range.isValid())
250  report->addRange(range);
251 
252  Ctx.emitReport(std::move(report));
253  }
254 }
255 
256 void ento::registerStackAddrEscapeChecker(CheckerManager &mgr) {
257  mgr.registerChecker<StackAddrEscapeChecker>();
258 }
CompoundLiteralRegion - A memory region representing a compound literal.
Definition: MemRegion.h:809
A (possibly-)qualified type.
Definition: Type.h:598
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Defines the SourceManager interface.
bool isRecordType() const
Definition: Type.h:5539
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
Definition: StoreRef.h:26
AllocaRegion - A region that represents an untyped blob of bytes created by a call to 'alloca'...
Definition: MemRegion.h:441
CompoundLiteralExpr - [C99 6.5.2.5].
Definition: Expr.h:2562
const MemRegion * getBaseRegion() const
Definition: MemRegion.cpp:1129
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition: ExprCXX.h:2936
Defines the clang::Expr interface and subclasses for C++ expressions.
const MemSpaceRegion * getMemorySpace() const
Definition: MemRegion.cpp:1097
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:92
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
const VarDecl * getDecl() const
Definition: MemRegion.h:873
BlockDataRegion - A region that represents a block instance.
Definition: MemRegion.h:627
const LangOptions & getLangOpts() const
Definition: ASTContext.h:604
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
Definition: Type.h:934
const StackFrameContext * getStackFrame() const
Definition: MemRegion.h:368
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
Definition: Decl.h:3456
Expr - This represents one expression.
Definition: Expr.h:105
const ProgramStateRef & getState() const
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Definition: Stmt.h:1366
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
const SourceManager & SM
Definition: Format.cpp:1184
const clang::PrintingPolicy & getPrintingPolicy() const
Definition: ASTContext.h:553
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
SourceLocation getLocStart() const LLVM_READONLY
Definition: Expr.h:2605
CHECKER * registerChecker()
Used to register checkers.
Encodes a location in the source.
const StackFrameContext * getCurrentStackFrame() const
bool isValid() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:46
QualType getType() const
Definition: Expr.h:126
const MemRegion * getAsRegion() const
Definition: SVals.cpp:135
const Expr * getRetValue() const
Definition: Stmt.cpp:899
SourceManager & getSourceManager()
Definition: ASTContext.h:561
SourceRange getSourceRange() const override LLVM_READONLY
Definition: Decl.cpp:3910
A trivial tuple used to represent a source range.
This class handles loading and caching of source files into memory.
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
Definition: Expr.cpp:2295
const LocationContext * getLocationContext() const