blob: 8aa359e49ef16bee34b67514d0759992a0672296 [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();
Zhongxing Xu1622a542010-06-08 10:00:00 +000057
Zhongxing Xu2c464582010-06-09 05:50:38 +000058 if (const StackSpaceRegion *SSR =
59 dyn_cast<StackSpaceRegion>(R->getMemorySpace())) {
60 const StackFrameContext *ValSFC = SSR->getStackFrame();
61 const StackFrameContext *CurSFC = LCtx->getCurrentStackFrame();
62 // If the global variable holds a location in the current stack frame,
63 // emit a warning.
64 if (ValSFC == CurSFC) {
65 // The variable is declared in the function scope which we are
66 // leaving. Keeping this variable's address in a global variable
67 // is dangerous.
Zhongxing Xu1622a542010-06-08 10:00:00 +000068
Zhongxing Xu2c464582010-06-09 05:50:38 +000069 // FIXME: better warning location.
70
71 ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
72 if (N) {
73 if (!BT_stackleak)
74 BT_stackleak = new BuiltinBug("Stack address leak",
75 "Stack address was saved into a global variable. "
76 "is dangerous because the address will become invalid "
77 "after returning from the function.");
78 BugReport *R = new BugReport(*BT_stackleak,
79 BT_stackleak->getDescription(), N);
80 Eng.getBugReporter().EmitReport(R);
Zhongxing Xu1622a542010-06-08 10:00:00 +000081 }
Zhongxing Xu2c464582010-06-09 05:50:38 +000082 }
Zhongxing Xu1622a542010-06-08 10:00:00 +000083 }
84 }
85 }
86 }
87}