clang  6.0.0svn
ReturnUndefChecker.cpp
Go to the documentation of this file.
1 //== ReturnUndefChecker.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 ReturnUndefChecker, which is a path-sensitive
11 // check which looks for undefined or garbage values being returned to the
12 // caller.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "ClangSACheckers.h"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
28  mutable std::unique_ptr<BuiltinBug> BT_Undef;
29  mutable std::unique_ptr<BuiltinBug> BT_NullReference;
30 
31  void emitUndef(CheckerContext &C, const Expr *RetE) const;
32  void checkReference(CheckerContext &C, const Expr *RetE,
33  DefinedOrUnknownSVal RetVal) const;
34 public:
35  void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
36 };
37 }
38 
39 void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
40  CheckerContext &C) const {
41  const Expr *RetE = RS->getRetValue();
42  if (!RetE)
43  return;
44  SVal RetVal = C.getSVal(RetE);
45 
46  const StackFrameContext *SFC = C.getStackFrame();
48 
49  if (RetVal.isUndef()) {
50  // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal
51  // to be returned in functions returning void to support this pattern:
52  // void foo() {
53  // return;
54  // }
55  // void test() {
56  // return foo();
57  // }
58  if (!RT.isNull() && RT->isVoidType())
59  return;
60 
61  // Not all blocks have explicitly-specified return types; if the return type
62  // is not available, but the return value expression has 'void' type, assume
63  // Sema already checked it.
64  if (RT.isNull() && isa<BlockDecl>(SFC->getDecl()) &&
65  RetE->getType()->isVoidType())
66  return;
67 
68  emitUndef(C, RetE);
69  return;
70  }
71 
72  if (RT.isNull())
73  return;
74 
75  if (RT->isReferenceType()) {
76  checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>());
77  return;
78  }
79 }
80 
81 static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
82  const Expr *TrackingE = nullptr) {
84  if (!N)
85  return;
86 
87  auto Report = llvm::make_unique<BugReport>(BT, BT.getDescription(), N);
88 
89  Report->addRange(RetE->getSourceRange());
90  bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);
91 
92  C.emitReport(std::move(Report));
93 }
94 
95 void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
96  if (!BT_Undef)
97  BT_Undef.reset(
98  new BuiltinBug(this, "Garbage return value",
99  "Undefined or garbage value returned to caller"));
100  emitBug(C, *BT_Undef, RetE);
101 }
102 
103 void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
104  DefinedOrUnknownSVal RetVal) const {
105  ProgramStateRef StNonNull, StNull;
106  std::tie(StNonNull, StNull) = C.getState()->assume(RetVal);
107 
108  if (StNonNull) {
109  // Going forward, assume the location is non-null.
110  C.addTransition(StNonNull);
111  return;
112  }
113 
114  // The return value is known to be null. Emit a bug report.
115  if (!BT_NullReference)
116  BT_NullReference.reset(new BuiltinBug(this, "Returning null reference"));
117 
118  emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
119 }
120 
121 void ento::registerReturnUndefChecker(CheckerManager &mgr) {
122  mgr.registerChecker<ReturnUndefChecker>();
123 }
const Expr * getDerefExpr(const Stmt *S)
A (possibly-)qualified type.
Definition: Type.h:614
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
StringRef getDescription() const
Definition: BugType.h:74
static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE, const Expr *TrackingE=nullptr)
const Expr * getRetValue() const
Definition: Stmt.cpp:905
bool isReferenceType() const
Definition: Type.h:5731
Expr - This represents one expression.
Definition: Expr.h:106
QualType getType() const
Definition: Expr.h:128
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
Definition: Stmt.h:1392
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:681
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
Dataflow Directional Tag Classes.
const Decl * getDecl() const
const StackFrameContext * getStackFrame() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:92
const ProgramStateRef & getState() const
static QualType getDeclaredResultType(const Decl *D)
Returns the result type of a function or method declaration.
Definition: CallEvent.cpp:274
bool isVoidType() const
Definition: Type.h:5916
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
Attempts to add visitors to trace a null or undefined value back to its point of origin, whether it is a symbol constrained to null or an explicit assignment.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:245
bool isUndef() const
Definition: SVals.h:132