blob: 63da1da43386f03e2aab58462ad6c086b84b38a7 [file] [log] [blame]
Zhongxing Xu1622a542010-06-08 10:00:00 +00001//=== 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
Argyrios Kyrtzidis027a6ab2011-02-15 07:42:33 +000015#include "ClangSACheckers.h"
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000016#include "clang/StaticAnalyzer/Core/CheckerManager.h"
Ted Kremenek9b663712011-02-10 01:03:03 +000017#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
Zhongxing Xu9b146832010-06-09 06:08:24 +000020#include "clang/Basic/SourceManager.h"
21#include "llvm/ADT/SmallString.h"
Zhongxing Xu1622a542010-06-08 10:00:00 +000022using namespace clang;
Ted Kremenek9ef65372010-12-23 07:20:52 +000023using namespace ento;
Zhongxing Xu1622a542010-06-08 10:00:00 +000024
25namespace {
Zhongxing Xu9b146832010-06-09 06:08:24 +000026class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
Zhongxing Xu1622a542010-06-08 10:00:00 +000027 BuiltinBug *BT_stackleak;
Zhongxing Xu9b146832010-06-09 06:08:24 +000028 BuiltinBug *BT_returnstack;
Zhongxing Xu1622a542010-06-08 10:00:00 +000029
30public:
Zhongxing Xu9b146832010-06-09 06:08:24 +000031 StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
Zhongxing Xu1622a542010-06-08 10:00:00 +000032 static void *getTag() {
33 static int x;
34 return &x;
35 }
Zhongxing Xu9b146832010-06-09 06:08:24 +000036 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
Ted Kremeneke36de1f2011-01-11 02:34:45 +000037 void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng);
Zhongxing Xu9b146832010-06-09 06:08:24 +000038private:
39 void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
Ted Kremeneka8166152010-06-17 04:21:37 +000040 SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
41 SourceManager &SM);
Zhongxing Xu1622a542010-06-08 10:00:00 +000042};
43}
44
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000045static void RegisterStackAddrLeakChecker(ExprEngine &Eng) {
Zhongxing Xu1622a542010-06-08 10:00:00 +000046 Eng.registerCheck(new StackAddrLeakChecker());
47}
Ted Kremeneka8166152010-06-17 04:21:37 +000048
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000049void ento::registerStackAddrLeakChecker(CheckerManager &mgr) {
50 mgr.addCheckerRegisterFunction(RegisterStackAddrLeakChecker);
51}
52
Ted Kremeneka8166152010-06-17 04:21:37 +000053SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
54 const MemRegion *R,
55 SourceManager &SM) {
56 // Get the base region, stripping away fields and elements.
57 R = R->getBaseRegion();
58 SourceRange range;
59 os << "Address of ";
60
61 // Check if the region is a compound literal.
62 if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
63 const CompoundLiteralExpr* CL = CR->getLiteralExpr();
64 os << "stack memory associated with a compound literal "
65 "declared on line "
66 << SM.getInstantiationLineNumber(CL->getLocStart())
67 << " returned to caller";
68 range = CL->getSourceRange();
69 }
70 else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
71 const Expr* ARE = AR->getExpr();
72 SourceLocation L = ARE->getLocStart();
73 range = ARE->getSourceRange();
74 os << "stack memory allocated by call to alloca() on line "
75 << SM.getInstantiationLineNumber(L);
76 }
77 else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
78 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
79 SourceLocation L = BD->getLocStart();
80 range = BD->getSourceRange();
81 os << "stack-allocated block declared on line "
82 << SM.getInstantiationLineNumber(L);
83 }
84 else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
85 os << "stack memory associated with local variable '"
86 << VR->getString() << '\'';
87 range = VR->getDecl()->getSourceRange();
88 }
89 else {
90 assert(false && "Invalid region in ReturnStackAddressChecker.");
91 }
92
93 return range;
94}
95
Zhongxing Xu9b146832010-06-09 06:08:24 +000096void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
97 const Expr *RetE) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000098 ExplodedNode *N = C.generateSink();
Zhongxing Xu9b146832010-06-09 06:08:24 +000099
100 if (!N)
101 return;
102
103 if (!BT_returnstack)
104 BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
105
106 // Generate a report for this bug.
107 llvm::SmallString<512> buf;
108 llvm::raw_svector_ostream os(buf);
Ted Kremeneka8166152010-06-17 04:21:37 +0000109 SourceRange range = GenName(os, R, C.getSourceManager());
110 os << " returned to caller";
Zhongxing Xu9b146832010-06-09 06:08:24 +0000111 RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
112 report->addRange(RetE->getSourceRange());
113 if (range.isValid())
114 report->addRange(range);
115
116 C.EmitReport(report);
Eli Friedmana7e68452010-08-22 01:00:03 +0000117}
Zhongxing Xu9b146832010-06-09 06:08:24 +0000118
119void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
120 const ReturnStmt *RS) {
121
122 const Expr *RetE = RS->getRetValue();
123 if (!RetE)
124 return;
125
126 SVal V = C.getState()->getSVal(RetE);
127 const MemRegion *R = V.getAsRegion();
128
129 if (!R || !R->hasStackStorage())
130 return;
131
132 if (R->hasStackStorage()) {
133 EmitStackError(C, R, RetE);
134 return;
135 }
136}
Zhongxing Xu1622a542010-06-08 10:00:00 +0000137
Ted Kremeneke36de1f2011-01-11 02:34:45 +0000138void StackAddrLeakChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag,
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +0000139 ExprEngine &Eng) {
Ted Kremenekba37d3b2011-01-13 04:36:40 +0000140
Zhongxing Xu1622a542010-06-08 10:00:00 +0000141 const GRState *state = B.getState();
Zhongxing Xu1622a542010-06-08 10:00:00 +0000142
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000143 // Iterate over all bindings to global variables and see if it contains
144 // a memory region in the stack space.
145 class CallBack : public StoreManager::BindingsHandler {
146 private:
147 const StackFrameContext *CurSFC;
148 public:
Ted Kremeneka8166152010-06-17 04:21:37 +0000149 llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000150
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000151 CallBack(const LocationContext *LCtx)
Ted Kremeneka8166152010-06-17 04:21:37 +0000152 : CurSFC(LCtx->getCurrentStackFrame()) {}
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000153
154 bool HandleBinding(StoreManager &SMgr, Store store,
155 const MemRegion *region, SVal val) {
156
157 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
158 return true;
159
160 const MemRegion *vR = val.getAsRegion();
161 if (!vR)
162 return true;
163
164 if (const StackSpaceRegion *SSR =
165 dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
166 // If the global variable holds a location in the current stack frame,
167 // record the binding to emit a warning.
Ted Kremeneka8166152010-06-17 04:21:37 +0000168 if (SSR->getStackFrame() == CurSFC)
169 V.push_back(std::make_pair(region, vR));
Zhongxing Xu1622a542010-06-08 10:00:00 +0000170 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000171
172 return true;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000173 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000174 };
175
176 CallBack cb(B.getPredecessor()->getLocationContext());
177 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
Ted Kremeneka8166152010-06-17 04:21:37 +0000178
179 if (cb.V.empty())
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000180 return;
181
182 // Generate an error node.
Argyrios Kyrtzidisf178ac82011-02-23 21:04:49 +0000183 ExplodedNode *N = B.generateNode(state);
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000184 if (!N)
185 return;
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000186
Ted Kremeneka8166152010-06-17 04:21:37 +0000187 if (!BT_stackleak)
188 BT_stackleak =
189 new BuiltinBug("Stack address stored into global variable",
190 "Stack address was saved into a global variable. "
191 "This is dangerous because the address will become "
192 "invalid after returning from the function");
193
194 for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
195 // Generate a report for this bug.
196 llvm::SmallString<512> buf;
197 llvm::raw_svector_ostream os(buf);
198 SourceRange range = GenName(os, cb.V[i].second,
199 Eng.getContext().getSourceManager());
200 os << " is still referred to by the global variable '";
201 const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
202 os << VR->getDecl()->getNameAsString()
203 << "' upon returning to the caller. This will be a dangling reference";
204 RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
205 if (range.isValid())
206 report->addRange(range);
207
208 Eng.getBugReporter().EmitReport(report);
209 }
Zhongxing Xu1622a542010-06-08 10:00:00 +0000210}