]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Checker/ReturnStackAddressChecker.cpp
Update clang to r97873.
[FreeBSD/FreeBSD.git] / lib / Checker / ReturnStackAddressChecker.cpp
1 //== ReturnStackAddressChecker.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 ReturnStackAddressChecker, which is a path-sensitive
11 // check which looks for the addresses of stack variables being returned to
12 // callers.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "GRExprEngineInternalChecks.h"
17 #include "clang/Checker/PathSensitive/GRExprEngine.h"
18 #include "clang/Checker/BugReporter/BugReporter.h"
19 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
20 #include "clang/Basic/SourceManager.h"
21 #include "llvm/ADT/SmallString.h"
22
23 using namespace clang;
24
25 namespace {
26 class ReturnStackAddressChecker : 
27     public CheckerVisitor<ReturnStackAddressChecker> {      
28   BuiltinBug *BT;
29 public:
30   ReturnStackAddressChecker() : BT(0) {}
31   static void *getTag();
32   void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
33 private:
34   void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
35 };
36 }
37
38 void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
39   Eng.registerCheck(new ReturnStackAddressChecker());
40 }
41
42 void *ReturnStackAddressChecker::getTag() {
43   static int x = 0; return &x;
44 }
45
46 void ReturnStackAddressChecker::EmitStackError(CheckerContext &C,
47                                                const MemRegion *R,
48                                                const Expr *RetE) {
49         ExplodedNode *N = C.GenerateSink();
50
51         if (!N)
52                 return;
53
54         if (!BT)
55                 BT = new BuiltinBug("Return of address to stack-allocated memory");
56
57         // Generate a report for this bug.
58         llvm::SmallString<512> buf;
59         llvm::raw_svector_ostream os(buf);
60         SourceRange range;
61
62         // Get the base region, stripping away fields and elements.
63         R = R->getBaseRegion();
64
65         // Check if the region is a compound literal.
66         if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {    
67                 const CompoundLiteralExpr* CL = CR->getLiteralExpr();
68                 os << "Address of stack memory associated with a compound literal "
69           "declared on line "
70        << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
71        << " returned to caller";    
72                 range = CL->getSourceRange();
73         }
74         else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
75                 const Expr* ARE = AR->getExpr();
76                 SourceLocation L = ARE->getLocStart();
77                 range = ARE->getSourceRange();    
78                 os << "Address of stack memory allocated by call to alloca() on line "
79        << C.getSourceManager().getInstantiationLineNumber(L)
80        << " returned to caller";
81         }
82         else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
83                 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
84                 SourceLocation L = BD->getLocStart();
85                 range = BD->getSourceRange();
86                 os << "Address of stack-allocated block declared on line "
87        << C.getSourceManager().getInstantiationLineNumber(L)
88        << " returned to caller";
89         }
90         else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
91                 os << "Address of stack memory associated with local variable '"
92        << VR->getString() << "' returned";
93                 range = VR->getDecl()->getSourceRange();
94         }
95         else {
96                 assert(false && "Invalid region in ReturnStackAddressChecker.");
97                 return;
98         }
99
100         RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
101         report->addRange(RetE->getSourceRange());
102         if (range.isValid())
103                 report->addRange(range);
104
105         C.EmitReport(report);
106 }       
107
108 void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
109                                                    const ReturnStmt *RS) {
110   
111   const Expr *RetE = RS->getRetValue();
112   if (!RetE)
113     return;
114  
115   SVal V = C.getState()->getSVal(RetE);
116   const MemRegion *R = V.getAsRegion();
117
118   if (!R || !R->hasStackStorage())
119     return;  
120   
121   if (R->hasStackStorage()) {
122     EmitStackError(C, R, RetE);
123     return;
124   }
125 }