blob: ae410ed27d230b52fcead176081b7f330dec711e [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();
128 TranslationUnitDecl *TU = Eng.getContext().getTranslationUnitDecl();
129
130 // Check each global variable if it contains a MemRegionVal of a stack
131 // variable declared in the function we are leaving.
132 for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
133 I != E; ++I) {
134 if (VarDecl *VD = dyn_cast<VarDecl>(*I)) {
135 const LocationContext *LCtx = B.getPredecessor()->getLocationContext();
Zhongxing Xubd409d02010-06-16 06:16:46 +0000136 Loc L = state->getLValue(VD, LCtx);
137 SVal V = state->getSVal(L);
Zhongxing Xu1622a542010-06-08 10:00:00 +0000138 if (loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(&V)) {
139 const MemRegion *R = RV->getRegion();
Zhongxing Xu1622a542010-06-08 10:00:00 +0000140
Zhongxing Xu2c464582010-06-09 05:50:38 +0000141 if (const StackSpaceRegion *SSR =
142 dyn_cast<StackSpaceRegion>(R->getMemorySpace())) {
143 const StackFrameContext *ValSFC = SSR->getStackFrame();
144 const StackFrameContext *CurSFC = LCtx->getCurrentStackFrame();
145 // If the global variable holds a location in the current stack frame,
146 // emit a warning.
147 if (ValSFC == CurSFC) {
148 // The variable is declared in the function scope which we are
149 // leaving. Keeping this variable's address in a global variable
150 // is dangerous.
Zhongxing Xu1622a542010-06-08 10:00:00 +0000151
Zhongxing Xu2c464582010-06-09 05:50:38 +0000152 // FIXME: better warning location.
153
154 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
155 if (N) {
156 if (!BT_stackleak)
157 BT_stackleak = new BuiltinBug("Stack address leak",
158 "Stack address was saved into a global variable. "
159 "is dangerous because the address will become invalid "
160 "after returning from the function.");
161 BugReport *R = new BugReport(*BT_stackleak,
162 BT_stackleak->getDescription(), N);
163 Eng.getBugReporter().EmitReport(R);
Zhongxing Xu1622a542010-06-08 10:00:00 +0000164 }
Zhongxing Xu2c464582010-06-09 05:50:38 +0000165 }
Zhongxing Xu1622a542010-06-08 10:00:00 +0000166 }
167 }
168 }
169 }
170}