summaryrefslogtreecommitdiffstats
path: root/lib/Analysis/ReturnStackAddressChecker.cpp
blob: e4be8712d09b3ff8746c8d68e59a879254f86c6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines ReturnStackAddressChecker, which is a path-sensitive
// check which looks for the addresses of stack variables being returned to
// callers.
//
//===----------------------------------------------------------------------===//

#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "llvm/ADT/SmallString.h"

using namespace clang;

namespace {
class VISIBILITY_HIDDEN ReturnStackAddressChecker : 
    public CheckerVisitor<ReturnStackAddressChecker> {      
  BuiltinBug *BT;
public:
    ReturnStackAddressChecker() : BT(0) {}
    static void *getTag();
    void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
};
}

void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
  Eng.registerCheck(new ReturnStackAddressChecker());
}

void *ReturnStackAddressChecker::getTag() {
  static int x = 0; return &x;
}

void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
                                                   const ReturnStmt *RS) {
  
  const Expr *RetE = RS->getRetValue();
  if (!RetE)
    return;
 
  SVal V = C.getState()->getSVal(RetE);
  const MemRegion *R = V.getAsRegion();

  if (!R || !R->hasStackStorage())
    return;  
  
  ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);

  if (!N)
    return;
  
  if (!BT)
    BT = new BuiltinBug("Return of address to stack-allocated memory");
  
  // Generate a report for this bug.
  llvm::SmallString<100> buf;
  llvm::raw_svector_ostream os(buf);
  SourceRange range;
  
  // Check if the region is a compound literal.
  if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {    
    const CompoundLiteralExpr* CL = CR->getLiteralExpr();
    os << "Address of stack memory associated with a compound literal "
          "declared on line "
       << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
       << " returned to caller";    
    range = CL->getSourceRange();
  }
  else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
    const Expr* ARE = AR->getExpr();
    SourceLocation L = ARE->getLocStart();
    range = ARE->getSourceRange();    
    os << "Address of stack memory allocated by call to alloca() on line "
       << C.getSourceManager().getInstantiationLineNumber(L)
       << " returned to caller";
  }
  else {
    os << "Address of stack memory associated with local variable '"
        << R->getString() << "' returned.";
  }

  RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
  report->addRange(RS->getSourceRange());
  if (range.isValid())
    report->addRange(range);
  
  C.EmitReport(report);
}
OpenPOWER on IntegriCloud