1 //=== StackAddrLeakChecker.cpp ------------------------------------*- C++ -*--//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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
;
24 class StackAddrLeakChecker
: public CheckerVisitor
<StackAddrLeakChecker
> {
25 BuiltinBug
*BT_stackleak
;
26 BuiltinBug
*BT_returnstack
;
29 StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
30 static void *getTag() {
34 void PreVisitReturnStmt(CheckerContext
&C
, const ReturnStmt
*RS
);
35 void EvalEndPath(GREndPathNodeBuilder
&B
, void *tag
, GRExprEngine
&Eng
);
37 void EmitStackError(CheckerContext
&C
, const MemRegion
*R
, const Expr
*RetE
);
38 SourceRange
GenName(llvm::raw_ostream
&os
, const MemRegion
*R
,
43 void clang::RegisterStackAddrLeakChecker(GRExprEngine
&Eng
) {
44 Eng
.registerCheck(new StackAddrLeakChecker());
47 SourceRange
StackAddrLeakChecker::GenName(llvm::raw_ostream
&os
,
50 // Get the base region, stripping away fields and elements.
51 R
= R
->getBaseRegion();
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 "
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();
84 assert(false && "Invalid region in ReturnStackAddressChecker.");
90 void StackAddrLeakChecker::EmitStackError(CheckerContext
&C
, const MemRegion
*R
,
92 ExplodedNode
*N
= C
.GenerateSink();
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());
108 report
->addRange(range
);
110 C
.EmitReport(report
);
113 void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext
&C
,
114 const ReturnStmt
*RS
) {
116 const Expr
*RetE
= RS
->getRetValue();
120 SVal V
= C
.getState()->getSVal(RetE
);
121 const MemRegion
*R
= V
.getAsRegion();
123 if (!R
|| !R
->hasStackStorage())
126 if (R
->hasStackStorage()) {
127 EmitStackError(C
, R
, RetE
);
132 void StackAddrLeakChecker::EvalEndPath(GREndPathNodeBuilder
&B
, void *tag
,
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
{
141 const StackFrameContext
*CurSFC
;
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()))
154 const MemRegion
*vR
= val
.getAsRegion();
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
));
170 CallBack
cb(B
.getPredecessor()->getLocationContext());
171 state
->getStateManager().getStoreManager().iterBindings(state
->getStore(),cb
);
176 // Generate an error node.
177 ExplodedNode
*N
= B
.generateNode(state
, tag
, B
.getPredecessor());
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
);
200 report
->addRange(range
);
202 Eng
.getBugReporter().EmitReport(report
);