Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This defines CastValueChecker which models casts of custom RTTIs.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14
#include "clang/StaticAnalyzer/Core/Checker.h"
15
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
16
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
17
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
18
#include "llvm/ADT/Optional.h"
19
20
using namespace clang;
21
using namespace ento;
22
23
namespace {
24
class CastValueChecker : public Checker<eval::Call> {
25
  using CastCheck =
26
      std::function<void(const CastValueChecker *, const CallExpr *,
27
                         DefinedOrUnknownSVal, CheckerContext &)>;
28
29
public:
30
  // We have three cases to evaluate a cast:
31
  // 1) The parameter is non-null, the return value is non-null
32
  // 2) The parameter is non-null, the return value is null
33
  // 3) The parameter is null, the return value is null
34
  //
35
  // cast: 1;  dyn_cast: 1, 2;  cast_or_null: 1, 3;  dyn_cast_or_null: 1, 2, 3.
36
  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
37
38
private:
39
  // These are known in the LLVM project.
40
  const CallDescriptionMap<CastCheck> CDM = {
41
      {{{"llvm", "cast"}, 1}, &CastValueChecker::evalCast},
42
      {{{"llvm", "dyn_cast"}, 1}, &CastValueChecker::evalDynCast},
43
      {{{"llvm", "cast_or_null"}, 1}, &CastValueChecker::evalCastOrNull},
44
      {{{"llvm", "dyn_cast_or_null"}, 1},
45
       &CastValueChecker::evalDynCastOrNull}};
46
47
  void evalCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
48
                CheckerContext &C) const;
49
  void evalDynCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
50
                   CheckerContext &C) const;
51
  void evalCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
52
                      CheckerContext &C) const;
53
  void evalDynCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
54
                         CheckerContext &C) const;
55
};
56
} // namespace
57
58
56
static std::string getCastName(const Expr *Cast) {
59
56
  return Cast->getType()->getPointeeCXXRecordDecl()->getNameAsString();
60
56
}
61
62
static void evalNonNullParamNonNullReturn(const CallExpr *CE,
63
                                          DefinedOrUnknownSVal ParamDV,
64
18
                                          CheckerContext &C) {
65
18
  ProgramStateRef State = C.getState()->assume(ParamDV, true);
66
18
  if (!State)
67
2
    return;
68
16
69
16
  State = State->BindExpr(CE, C.getLocationContext(), ParamDV, false);
70
16
71
16
  std::string CastFromName = getCastName(CE->getArg(0));
72
16
  std::string CastToName = getCastName(CE);
73
16
74
16
  const NoteTag *CastTag = C.getNoteTag(
75
16
      [CastFromName, CastToName](BugReport &) -> std::string {
76
9
        SmallString<128> Msg;
77
9
        llvm::raw_svector_ostream Out(Msg);
78
9
79
9
        Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
80
9
            << CastToName << "' succeeds";
81
9
        return Out.str();
82
9
      },
83
16
      /*IsPrunable=*/true);
84
16
85
16
  C.addTransition(State, CastTag);
86
16
}
87
88
static void evalNonNullParamNullReturn(const CallExpr *CE,
89
                                       DefinedOrUnknownSVal ParamDV,
90
14
                                       CheckerContext &C) {
91
14
  ProgramStateRef State = C.getState()->assume(ParamDV, true);
92
14
  if (!State)
93
2
    return;
94
12
95
12
  State = State->BindExpr(CE, C.getLocationContext(),
96
12
                          C.getSValBuilder().makeNull(), false);
97
12
98
12
  std::string CastFromName = getCastName(CE->getArg(0));
99
12
  std::string CastToName = getCastName(CE);
100
12
101
12
  const NoteTag *CastTag = C.getNoteTag(
102
12
      [CastFromName, CastToName](BugReport &) -> std::string {
103
5
        SmallString<128> Msg;
104
5
        llvm::raw_svector_ostream Out(Msg);
105
5
106
5
        Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
107
5
            << CastToName << "' fails";
108
5
        return Out.str();
109
5
      },
110
12
      /*IsPrunable=*/true);
111
12
112
12
  C.addTransition(State, CastTag);
113
12
}
114
115
static void evalNullParamNullReturn(const CallExpr *CE,
116
                                    DefinedOrUnknownSVal ParamDV,
117
14
                                    CheckerContext &C) {
118
14
  ProgramStateRef State = C.getState()->assume(ParamDV, false);
119
14
  if (!State)
120
2
    return;
121
12
122
12
  State = State->BindExpr(CE, C.getLocationContext(),
123
12
                          C.getSValBuilder().makeNull(), false);
124
12
125
12
  const NoteTag *CastTag =
126
12
      C.getNoteTag("Assuming null pointer is passed into cast",
127
12
                   /*IsPrunable=*/true);
128
12
129
12
  C.addTransition(State, CastTag);
130
12
}
131
132
void CastValueChecker::evalCast(const CallExpr *CE,
133
                                DefinedOrUnknownSVal ParamDV,
134
2
                                CheckerContext &C) const {
135
2
  evalNonNullParamNonNullReturn(CE, ParamDV, C);
136
2
}
137
138
void CastValueChecker::evalDynCast(const CallExpr *CE,
139
                                   DefinedOrUnknownSVal ParamDV,
140
2
                                   CheckerContext &C) const {
141
2
  evalNonNullParamNonNullReturn(CE, ParamDV, C);
142
2
  evalNonNullParamNullReturn(CE, ParamDV, C);
143
2
}
144
145
void CastValueChecker::evalCastOrNull(const CallExpr *CE,
146
                                      DefinedOrUnknownSVal ParamDV,
147
2
                                      CheckerContext &C) const {
148
2
  evalNonNullParamNonNullReturn(CE, ParamDV, C);
149
2
  evalNullParamNullReturn(CE, ParamDV, C);
150
2
}
151
152
void CastValueChecker::evalDynCastOrNull(const CallExpr *CE,
153
                                         DefinedOrUnknownSVal ParamDV,
154
12
                                         CheckerContext &C) const {
155
12
  evalNonNullParamNonNullReturn(CE, ParamDV, C);
156
12
  evalNonNullParamNullReturn(CE, ParamDV, C);
157
12
  evalNullParamNullReturn(CE, ParamDV, C);
158
12
}
159
160
bool CastValueChecker::evalCall(const CallEvent &Call,
161
196
                                CheckerContext &C) const {
162
196
  const CastCheck *Check = CDM.lookup(Call);
163
196
  if (!Check)
164
178
    return false;
165
18
166
18
  const auto *CE = cast<CallExpr>(Call.getOriginExpr());
167
18
  if (!CE)
168
0
    return false;
169
18
170
18
  // If we cannot obtain both of the classes we cannot be sure how to model it.
171
18
  if (!CE->getType()->getPointeeCXXRecordDecl() ||
172
18
      !CE->getArg(0)->getType()->getPointeeCXXRecordDecl())
173
0
    return false;
174
18
175
18
  SVal ParamV = Call.getArgSVal(0);
176
18
  auto ParamDV = ParamV.getAs<DefinedOrUnknownSVal>();
177
18
  if (!ParamDV)
178
0
    return false;
179
18
180
18
  (*Check)(this, CE, *ParamDV, C);
181
18
  return true;
182
18
}
183
184
12
void ento::registerCastValueChecker(CheckerManager &Mgr) {
185
12
  Mgr.registerChecker<CastValueChecker>();
186
12
}
187
188
12
bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) {
189
12
  return true;
190
12
}