blob: 3ef78a46fb1b58f79b671e6ae126dfe8147ecfcd [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 Kyrtzidisd2592a32010-12-22 18:53:44 +000015#include "ExprEngineInternalChecks.h"
Argyrios Kyrtzidis98cabba2010-12-22 18:51:49 +000016#include "clang/GR/BugReporter/BugType.h"
17#include "clang/GR/PathSensitive/CheckerVisitor.h"
18#include "clang/GR/PathSensitive/GRState.h"
Zhongxing Xu9b146832010-06-09 06:08:24 +000019#include "clang/Basic/SourceManager.h"
20#include "llvm/ADT/SmallString.h"
Zhongxing Xu1622a542010-06-08 10:00:00 +000021using namespace clang;
Argyrios Kyrtzidis5a4f98f2010-12-22 18:53:20 +000022using namespace GR;
Zhongxing Xu1622a542010-06-08 10:00:00 +000023
24namespace {
Zhongxing Xu9b146832010-06-09 06:08:24 +000025class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
Zhongxing Xu1622a542010-06-08 10:00:00 +000026 BuiltinBug *BT_stackleak;
Zhongxing Xu9b146832010-06-09 06:08:24 +000027 BuiltinBug *BT_returnstack;
Zhongxing Xu1622a542010-06-08 10:00:00 +000028
29public:
Zhongxing Xu9b146832010-06-09 06:08:24 +000030 StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
Zhongxing Xu1622a542010-06-08 10:00:00 +000031 static void *getTag() {
32 static int x;
33 return &x;
34 }
Zhongxing Xu9b146832010-06-09 06:08:24 +000035 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000036 void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
Zhongxing Xu9b146832010-06-09 06:08:24 +000037private:
38 void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
Ted Kremeneka8166152010-06-17 04:21:37 +000039 SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
40 SourceManager &SM);
Zhongxing Xu1622a542010-06-08 10:00:00 +000041};
42}
43
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +000044void GR::RegisterStackAddrLeakChecker(ExprEngine &Eng) {
Zhongxing Xu1622a542010-06-08 10:00:00 +000045 Eng.registerCheck(new StackAddrLeakChecker());
46}
Ted Kremeneka8166152010-06-17 04:21:37 +000047
48SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
49 const MemRegion *R,
50 SourceManager &SM) {
51 // Get the base region, stripping away fields and elements.
52 R = R->getBaseRegion();
53 SourceRange range;
54 os << "Address of ";
55
56 // Check if the region is a compound literal.
57 if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
58 const CompoundLiteralExpr* CL = CR->getLiteralExpr();
59 os << "stack memory associated with a compound literal "
60 "declared on line "
61 << SM.getInstantiationLineNumber(CL->getLocStart())
62 << " returned to caller";
63 range = CL->getSourceRange();
64 }
65 else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
66 const Expr* ARE = AR->getExpr();
67 SourceLocation L = ARE->getLocStart();
68 range = ARE->getSourceRange();
69 os << "stack memory allocated by call to alloca() on line "
70 << SM.getInstantiationLineNumber(L);
71 }
72 else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
73 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
74 SourceLocation L = BD->getLocStart();
75 range = BD->getSourceRange();
76 os << "stack-allocated block declared on line "
77 << SM.getInstantiationLineNumber(L);
78 }
79 else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
80 os << "stack memory associated with local variable '"
81 << VR->getString() << '\'';
82 range = VR->getDecl()->getSourceRange();
83 }
84 else {
85 assert(false && "Invalid region in ReturnStackAddressChecker.");
86 }
87
88 return range;
89}
90
Zhongxing Xu9b146832010-06-09 06:08:24 +000091void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
92 const Expr *RetE) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000093 ExplodedNode *N = C.generateSink();
Zhongxing Xu9b146832010-06-09 06:08:24 +000094
95 if (!N)
96 return;
97
98 if (!BT_returnstack)
99 BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
100
101 // Generate a report for this bug.
102 llvm::SmallString<512> buf;
103 llvm::raw_svector_ostream os(buf);
Ted Kremeneka8166152010-06-17 04:21:37 +0000104 SourceRange range = GenName(os, R, C.getSourceManager());
105 os << " returned to caller";
Zhongxing Xu9b146832010-06-09 06:08:24 +0000106 RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
107 report->addRange(RetE->getSourceRange());
108 if (range.isValid())
109 report->addRange(range);
110
111 C.EmitReport(report);
Eli Friedmana7e68452010-08-22 01:00:03 +0000112}
Zhongxing Xu9b146832010-06-09 06:08:24 +0000113
114void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
115 const ReturnStmt *RS) {
116
117 const Expr *RetE = RS->getRetValue();
118 if (!RetE)
119 return;
120
121 SVal V = C.getState()->getSVal(RetE);
122 const MemRegion *R = V.getAsRegion();
123
124 if (!R || !R->hasStackStorage())
125 return;
126
127 if (R->hasStackStorage()) {
128 EmitStackError(C, R, RetE);
129 return;
130 }
131}
Zhongxing Xu1622a542010-06-08 10:00:00 +0000132
Argyrios Kyrtzidisd2592a32010-12-22 18:53:44 +0000133void StackAddrLeakChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
134 ExprEngine &Eng) {
Zhongxing Xu1622a542010-06-08 10:00:00 +0000135 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
136 const GRState *state = B.getState();
Zhongxing Xu1622a542010-06-08 10:00:00 +0000137
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000138 // Iterate over all bindings to global variables and see if it contains
139 // a memory region in the stack space.
140 class CallBack : public StoreManager::BindingsHandler {
141 private:
142 const StackFrameContext *CurSFC;
143 public:
Ted Kremeneka8166152010-06-17 04:21:37 +0000144 llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000145
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000146 CallBack(const LocationContext *LCtx)
Ted Kremeneka8166152010-06-17 04:21:37 +0000147 : CurSFC(LCtx->getCurrentStackFrame()) {}
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000148
149 bool HandleBinding(StoreManager &SMgr, Store store,
150 const MemRegion *region, SVal val) {
151
152 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
153 return true;
154
155 const MemRegion *vR = val.getAsRegion();
156 if (!vR)
157 return true;
158
159 if (const StackSpaceRegion *SSR =
160 dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
161 // If the global variable holds a location in the current stack frame,
162 // record the binding to emit a warning.
Ted Kremeneka8166152010-06-17 04:21:37 +0000163 if (SSR->getStackFrame() == CurSFC)
164 V.push_back(std::make_pair(region, vR));
Zhongxing Xu1622a542010-06-08 10:00:00 +0000165 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000166
167 return true;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000168 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000169 };
170
171 CallBack cb(B.getPredecessor()->getLocationContext());
172 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
Ted Kremeneka8166152010-06-17 04:21:37 +0000173
174 if (cb.V.empty())
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000175 return;
176
177 // Generate an error node.
178 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
179 if (!N)
180 return;
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000181
Ted Kremeneka8166152010-06-17 04:21:37 +0000182 if (!BT_stackleak)
183 BT_stackleak =
184 new BuiltinBug("Stack address stored into global variable",
185 "Stack address was saved into a global variable. "
186 "This is dangerous because the address will become "
187 "invalid after returning from the function");
188
189 for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
190 // Generate a report for this bug.
191 llvm::SmallString<512> buf;
192 llvm::raw_svector_ostream os(buf);
193 SourceRange range = GenName(os, cb.V[i].second,
194 Eng.getContext().getSourceManager());
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()->getNameAsString()
198 << "' upon returning to the caller. This will be a dangling reference";
199 RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
200 if (range.isValid())
201 report->addRange(range);
202
203 Eng.getBugReporter().EmitReport(report);
204 }
Zhongxing Xu1622a542010-06-08 10:00:00 +0000205}