blob: 34a06fb500e581ec4a91ba37c6b60074c8cfd6ae [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);
Zhongxing Xu1622a542010-06-08 10:00:00 +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);
Zhongxing Xu1622a542010-06-08 10:00:00 +000038};
39}
40
41void clang::RegisterStackAddrLeakChecker(GRExprEngine &Eng) {
42 Eng.registerCheck(new StackAddrLeakChecker());
43}
Zhongxing Xu9b146832010-06-09 06:08:24 +000044void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
45 const Expr *RetE) {
46 ExplodedNode *N = C.GenerateSink();
47
48 if (!N)
49 return;
50
51 if (!BT_returnstack)
52 BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
53
54 // Generate a report for this bug.
55 llvm::SmallString<512> buf;
56 llvm::raw_svector_ostream os(buf);
57 SourceRange range;
58
59 // Get the base region, stripping away fields and elements.
60 R = R->getBaseRegion();
61
62 // Check if the region is a compound literal.
63 if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
64 const CompoundLiteralExpr* CL = CR->getLiteralExpr();
65 os << "Address of stack memory associated with a compound literal "
66 "declared on line "
67 << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
68 << " returned to caller";
69 range = CL->getSourceRange();
70 }
71 else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
72 const Expr* ARE = AR->getExpr();
73 SourceLocation L = ARE->getLocStart();
74 range = ARE->getSourceRange();
75 os << "Address of stack memory allocated by call to alloca() on line "
76 << C.getSourceManager().getInstantiationLineNumber(L)
77 << " returned to caller";
78 }
79 else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
80 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
81 SourceLocation L = BD->getLocStart();
82 range = BD->getSourceRange();
83 os << "Address of stack-allocated block declared on line "
84 << C.getSourceManager().getInstantiationLineNumber(L)
85 << " returned to caller";
86 }
87 else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
88 os << "Address of stack memory associated with local variable '"
89 << VR->getString() << "' returned";
90 range = VR->getDecl()->getSourceRange();
91 }
92 else {
93 assert(false && "Invalid region in ReturnStackAddressChecker.");
94 return;
95 }
96
97 RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
98 report->addRange(RetE->getSourceRange());
99 if (range.isValid())
100 report->addRange(range);
101
102 C.EmitReport(report);
103}
104
105void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
106 const ReturnStmt *RS) {
107
108 const Expr *RetE = RS->getRetValue();
109 if (!RetE)
110 return;
111
112 SVal V = C.getState()->getSVal(RetE);
113 const MemRegion *R = V.getAsRegion();
114
115 if (!R || !R->hasStackStorage())
116 return;
117
118 if (R->hasStackStorage()) {
119 EmitStackError(C, R, RetE);
120 return;
121 }
122}
Zhongxing Xu1622a542010-06-08 10:00:00 +0000123
124void StackAddrLeakChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
125 GRExprEngine &Eng) {
126 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
127 const GRState *state = B.getState();
Zhongxing Xu1622a542010-06-08 10:00:00 +0000128
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000129 // Iterate over all bindings to global variables and see if it contains
130 // a memory region in the stack space.
131 class CallBack : public StoreManager::BindingsHandler {
132 private:
133 const StackFrameContext *CurSFC;
134 public:
135 const MemRegion *src, *dst;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000136
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000137 CallBack(const LocationContext *LCtx)
138 : CurSFC(LCtx->getCurrentStackFrame()), src(0), dst(0) {}
139
140 bool HandleBinding(StoreManager &SMgr, Store store,
141 const MemRegion *region, SVal val) {
142
143 if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
144 return true;
145
146 const MemRegion *vR = val.getAsRegion();
147 if (!vR)
148 return true;
149
150 if (const StackSpaceRegion *SSR =
151 dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
152 // If the global variable holds a location in the current stack frame,
153 // record the binding to emit a warning.
154 if (SSR->getStackFrame() == CurSFC) {
155 src = region;
156 dst = vR;
157 return false;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000158 }
159 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000160
161 return true;
Zhongxing Xu1622a542010-06-08 10:00:00 +0000162 }
Ted Kremenek551bd1f2010-06-17 00:24:44 +0000163 };
164
165 CallBack cb(B.getPredecessor()->getLocationContext());
166 state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
167
168 // Did we find any globals referencing stack memory?
169 if (!cb.src)
170 return;
171
172 // Generate an error node.
173 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
174 if (!N)
175 return;
176
177 if (!BT_stackleak)
178 BT_stackleak = new BuiltinBug("Stack address stored into global variable",
179 "Stack address was saved into a global variable. "
180 "is dangerous because the address will become invalid "
181 "after returning from the function");
182
183 BugReport *R =
184 new BugReport(*BT_stackleak, BT_stackleak->getDescription(), N);
185
186 Eng.getBugReporter().EmitReport(R);
Zhongxing Xu1622a542010-06-08 10:00:00 +0000187}