blob: 0bd9e02448661781b63274fe6af33e9e54ede1c0 [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"
17#include "clang/Checker/PathSensitive/Checker.h"
18#include "clang/Checker/PathSensitive/GRState.h"
19
20using namespace clang;
21
22namespace {
23class StackAddrLeakChecker : public Checker {
24 BuiltinBug *BT_stackleak;
25
26public:
27 StackAddrLeakChecker() : BT_stackleak(0) {}
28 static void *getTag() {
29 static int x;
30 return &x;
31 }
32
33 void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
34};
35}
36
37void clang::RegisterStackAddrLeakChecker(GRExprEngine &Eng) {
38 Eng.registerCheck(new StackAddrLeakChecker());
39}
40
41void StackAddrLeakChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
42 GRExprEngine &Eng) {
43 SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
44 const GRState *state = B.getState();
45 TranslationUnitDecl *TU = Eng.getContext().getTranslationUnitDecl();
46
47 // Check each global variable if it contains a MemRegionVal of a stack
48 // variable declared in the function we are leaving.
49 for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
50 I != E; ++I) {
51 if (VarDecl *VD = dyn_cast<VarDecl>(*I)) {
52 const LocationContext *LCtx = B.getPredecessor()->getLocationContext();
53 SVal L = state->getLValue(VD, LCtx);
54 SVal V = state->getSVal(cast<Loc>(L));
55 if (loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(&V)) {
56 const MemRegion *R = RV->getRegion();
57 // Strip fields or elements to get the variable region.
58 R = R->getBaseRegion();
59 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
60 const VarDecl *VD = VR->getDecl();
61 const DeclContext *DC = VD->getDeclContext();
62 // Get the function where the variable is declared.
63 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
64 // Check if the function is the function we are leaving.
65 if (FD == LCtx->getDecl()) {
66 // The variable is declared in the function scope which we are
67 // leaving. Keeping this variable's address in a global variable
68 // is dangerous.
69 // FIXME: Currently VarRegion does not carry context information.
70 // So we cannot tell if the local variable instance is in the
71 // current stack frame. This may produce false positive in
72 // recursive function call context. But that's a rare case.
73
74 // FIXME: better warning location.
75
76 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
77 if (N) {
78 if (!BT_stackleak)
79 BT_stackleak = new BuiltinBug("Stack address leak",
80 "Stack address was saved into a global variable. "
81 "This is dangerous because the address will become invalid "
82 "after returning from the function.");
83 BugReport *R = new BugReport(*BT_stackleak,
84 BT_stackleak->getDescription(), N);
85 Eng.getBugReporter().EmitReport(R);
86 }
87 }
88 }
89 }
90 }
91 }
92 }
93}
94