Adjust method calls to reflect name changes in
[clang.git] / lib / Checker / StackAddrLeakChecker.cpp
blobc67a81dced0a50fa7ceeed93d9293d33a17f70e5
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.
13 //===----------------------------------------------------------------------===//
15 #include "GRExprEngineInternalChecks.h"
16 #include "clang/Checker/BugReporter/BugType.h"
17 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
18 #include "clang/Checker/PathSensitive/GRState.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "llvm/ADT/SmallString.h"
21 using namespace clang;
23 namespace {
24 class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
25 BuiltinBug *BT_stackleak;
26 BuiltinBug *BT_returnstack;
28 public:
29 StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
30 static void *getTag() {
31 static int x;
32 return &x;
34 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
35 void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
36 private:
37 void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
38 SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
39 SourceManager &SM);
43 void clang::RegisterStackAddrLeakChecker(GRExprEngine &Eng) {
44 Eng.registerCheck(new StackAddrLeakChecker());
47 SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
48 const MemRegion *R,
49 SourceManager &SM) {
50 // Get the base region, stripping away fields and elements.
51 R = R->getBaseRegion();
52 SourceRange range;
53 os << "Address of ";
55 // Check if the region is a compound literal.
56 if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
57 const CompoundLiteralExpr* CL = CR->getLiteralExpr();
58 os << "stack memory associated with a compound literal "
59 "declared on line "
60 << SM.getInstantiationLineNumber(CL->getLocStart())
61 << " returned to caller";
62 range = CL->getSourceRange();
64 else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
65 const Expr* ARE = AR->getExpr();
66 SourceLocation L = ARE->getLocStart();
67 range = ARE->getSourceRange();
68 os << "stack memory allocated by call to alloca() on line "
69 << SM.getInstantiationLineNumber(L);
71 else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
72 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
73 SourceLocation L = BD->getLocStart();
74 range = BD->getSourceRange();
75 os << "stack-allocated block declared on line "
76 << SM.getInstantiationLineNumber(L);
78 else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
79 os << "stack memory associated with local variable '"
80 << VR->getString() << '\'';
81 range = VR->getDecl()->getSourceRange();
83 else {
84 assert(false && "Invalid region in ReturnStackAddressChecker.");
87 return range;
90 void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
91 const Expr *RetE) {
92 ExplodedNode *N = C.GenerateSink();
94 if (!N)
95 return;
97 if (!BT_returnstack)
98 BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
100 // Generate a report for this bug.
101 llvm::SmallString<512> buf;
102 llvm::raw_svector_ostream os(buf);
103 SourceRange range = GenName(os, R, C.getSourceManager());
104 os << " returned to caller";
105 RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
106 report->addRange(RetE->getSourceRange());
107 if (range.isValid())
108 report->addRange(range);
110 C.EmitReport(report);
113 void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
114 const ReturnStmt *RS) {
116 const Expr *RetE = RS->getRetValue();
117 if (!RetE)
118 return;
120 SVal V = C.getState()->getSVal(RetE);
121 const MemRegion *R = V.getAsRegion();
123 if (!R || !R->hasStackStorage())
124 return;
126 if (R->hasStackStorage()) {
127 EmitStackError(C, R, RetE);
128 return;
132 void StackAddrLeakChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
133 GRExprEngine &Eng) {
134 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
135 const GRState *state = B.getState();
137 // Iterate over all bindings to global variables and see if it contains
138 // a memory region in the stack space.
139 class CallBack : public StoreManager::BindingsHandler {
140 private:
141 const StackFrameContext *CurSFC;
142 public:
143 llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
145 CallBack(const LocationContext *LCtx)
146 : CurSFC(LCtx->getCurrentStackFrame()) {}
148 bool HandleBinding(StoreManager &SMgr, Store store,
149 const MemRegion *region, SVal val) {
151 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
152 return true;
154 const MemRegion *vR = val.getAsRegion();
155 if (!vR)
156 return true;
158 if (const StackSpaceRegion *SSR =
159 dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
160 // If the global variable holds a location in the current stack frame,
161 // record the binding to emit a warning.
162 if (SSR->getStackFrame() == CurSFC)
163 V.push_back(std::make_pair(region, vR));
166 return true;
170 CallBack cb(B.getPredecessor()->getLocationContext());
171 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
173 if (cb.V.empty())
174 return;
176 // Generate an error node.
177 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
178 if (!N)
179 return;
181 if (!BT_stackleak)
182 BT_stackleak =
183 new BuiltinBug("Stack address stored into global variable",
184 "Stack address was saved into a global variable. "
185 "This is dangerous because the address will become "
186 "invalid after returning from the function");
188 for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
189 // Generate a report for this bug.
190 llvm::SmallString<512> buf;
191 llvm::raw_svector_ostream os(buf);
192 SourceRange range = GenName(os, cb.V[i].second,
193 Eng.getContext().getSourceManager());
194 os << " is still referred to by the global variable '";
195 const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
196 os << VR->getDecl()->getNameAsString()
197 << "' upon returning to the caller. This will be a dangling reference";
198 RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
199 if (range.isValid())
200 report->addRange(range);
202 Eng.getBugReporter().EmitReport(report);