blob: 0e9c0ecab67db3a385d7181aa588ea543fea1b06 [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
15#include "GRExprEngineInternalChecks.h"
16#include "clang/Checker/BugReporter/BugType.h"
Zhongxing Xu9b146832010-06-09 06:08:24 +000017#include "clang/Checker/PathSensitive/CheckerVisitor.h"
Zhongxing Xu1622a542010-06-08 10:00:00 +000018#include "clang/Checker/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;
22
23namespace {
Zhongxing Xu9b146832010-06-09 06:08:24 +000024class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
Zhongxing Xu1622a542010-06-08 10:00:00 +000025 BuiltinBug *BT_stackleak;
Zhongxing Xu9b146832010-06-09 06:08:24 +000026 BuiltinBug *BT_returnstack;
Zhongxing Xu1622a542010-06-08 10:00:00 +000027
28public:
Zhongxing Xu9b146832010-06-09 06:08:24 +000029 StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
Zhongxing Xu1622a542010-06-08 10:00:00 +000030 static void *getTag() {
31 static int x;
32 return &x;
33 }
Zhongxing Xu9b146832010-06-09 06:08:24 +000034 void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
Ted Kremenek9c149532010-12-01 21:57:22 +000035 void evalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
Zhongxing Xu9b146832010-06-09 06:08:24 +000036private:
37 void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
Ted Kremeneka8166152010-06-17 04:21:37 +000038 SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
39 SourceManager &SM);
Zhongxing Xu1622a542010-06-08 10:00:00 +000040};
41}
42
43void clang::RegisterStackAddrLeakChecker(GRExprEngine &Eng) {
44 Eng.registerCheck(new StackAddrLeakChecker());
45}
Ted Kremeneka8166152010-06-17 04:21:37 +000046
47SourceRange 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 ";
54
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();
63 }
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);
70 }
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);
77 }
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();
82 }
83 else {
84 assert(false && "Invalid region in ReturnStackAddressChecker.");
85 }
86
87 return range;
88}
89
Zhongxing Xu9b146832010-06-09 06:08:24 +000090void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
91 const Expr *RetE) {
Ted Kremenekd048c6e2010-12-20 21:19:09 +000092 ExplodedNode *N = C.generateSink();
Zhongxing Xu9b146832010-06-09 06:08:24 +000093
94 if (!N)
95 return;
96
97 if (!BT_returnstack)
98 BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
99
100 // Generate a report for this bug.
101 llvm::SmallString<512> buf;
102 llvm::raw_svector_ostream os(buf);
Ted Kremeneka8166152010-06-17 04:21:37 +0000103 SourceRange range = GenName(os, R, C.getSourceManager());
104 os << " returned to caller";
Zhongxing Xu9b146832010-06-09 06:08:24 +0000105 RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
106 report->addRange(RetE->getSourceRange());
107 if (range.isValid())
108 report->addRange(range);
109
110 C.EmitReport(report);
Eli Friedmana7e68452010-08-22 01:00:03 +0000111}
Zhongxing Xu9b146832010-06-09 06:08:24 +0000112
113void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
114 const ReturnStmt *RS) {
115
116 const Expr *RetE = RS->getRetValue();
117 if (!RetE)
118 return;
119
120 SVal V = C.getState()->getSVal(RetE);
121 const MemRegion *R = V.getAsRegion();
122
123 if (!R || !R->hasStackStorage())
124 return;
125
126 if (R->hasStackStorage()) {
127 EmitStackError(C, R, RetE);
128 return;
129 }
130}
Zhongxing Xu1622a542010-06-08 10:00:00 +0000131
Ted Kremenek9c149532010-12-01 21:57:22 +0000132void StackAddrLeakChecker::evalEndPath(GREndPathNodeBuilder &B, void *tag,
Zhongxing Xu1622a542010-06-08 10:00:00 +0000133 GRExprEngine &Eng) {
134 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
135 const GRState *state = B.getState();
Zhongxing Xu1622a542010-06-08 10:00:00 +0000136
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000137 // 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:
Ted Kremeneka8166152010-06-17 04:21:37 +0000143 llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000144
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000145 CallBack(const LocationContext *LCtx)
Ted Kremeneka8166152010-06-17 04:21:37 +0000146 : CurSFC(LCtx->getCurrentStackFrame()) {}
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000147
148 bool HandleBinding(StoreManager &SMgr, Store store,
149 const MemRegion *region, SVal val) {
150
151 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
152 return true;
153
154 const MemRegion *vR = val.getAsRegion();
155 if (!vR)
156 return true;
157
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.
Ted Kremeneka8166152010-06-17 04:21:37 +0000162 if (SSR->getStackFrame() == CurSFC)
163 V.push_back(std::make_pair(region, vR));
Zhongxing Xu1622a542010-06-08 10:00:00 +0000164 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000165
166 return true;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000167 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000168 };
169
170 CallBack cb(B.getPredecessor()->getLocationContext());
171 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
Ted Kremeneka8166152010-06-17 04:21:37 +0000172
173 if (cb.V.empty())
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000174 return;
175
176 // Generate an error node.
177 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
178 if (!N)
179 return;
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000180
Ted Kremeneka8166152010-06-17 04:21:37 +0000181 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");
187
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);
201
202 Eng.getBugReporter().EmitReport(report);
203 }
Zhongxing Xu1622a542010-06-08 10:00:00 +0000204}