clang  10.0.0git
DebugIteratorModeling.cpp
Go to the documentation of this file.
1 //===-- DebugIteratorModeling.cpp ---------------------------------*- 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 // Defines a checker for debugging iterator modeling.
10 //
11 //===----------------------------------------------------------------------===//
12 
18 
19 #include "Iterator.h"
20 
21 using namespace clang;
22 using namespace ento;
23 using namespace iterator;
24 
25 namespace {
26 
27 class DebugIteratorModeling
28  : public Checker<eval::Call> {
29 
30  std::unique_ptr<BugType> DebugMsgBugType;
31 
32  template <typename Getter>
33  void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
34  Getter get) const;
35  void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
36  void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
37  template <typename Getter>
38  void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
39  Getter get, SVal Default) const;
40  void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
41  void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
42  void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
43  ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
44 
45  typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
46  CheckerContext &) const;
47 
48  CallDescriptionMap<FnCheck> Callbacks = {
49  {{0, "clang_analyzer_container_begin", 1},
50  &DebugIteratorModeling::analyzerContainerBegin},
51  {{0, "clang_analyzer_container_end", 1},
52  &DebugIteratorModeling::analyzerContainerEnd},
53  {{0, "clang_analyzer_iterator_position", 1},
54  &DebugIteratorModeling::analyzerIteratorPosition},
55  {{0, "clang_analyzer_iterator_container", 1},
56  &DebugIteratorModeling::analyzerIteratorContainer},
57  {{0, "clang_analyzer_iterator_validity", 1},
58  &DebugIteratorModeling::analyzerIteratorValidity},
59  };
60 
61 public:
62  DebugIteratorModeling();
63 
64  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
65 };
66 
67 } //namespace
68 
69 DebugIteratorModeling::DebugIteratorModeling() {
70  DebugMsgBugType.reset(
71  new BugType(this, "Checking analyzer assumptions", "debug",
72  /*SuppressOnSink=*/true));
73 }
74 
75 bool DebugIteratorModeling::evalCall(const CallEvent &Call,
76  CheckerContext &C) const {
77  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
78  if (!CE)
79  return false;
80 
81  const FnCheck *Handler = Callbacks.lookup(Call);
82  if (!Handler)
83  return false;
84 
85  (this->**Handler)(CE, C);
86  return true;
87 }
88 
89 template <typename Getter>
90 void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE,
91  CheckerContext &C,
92  Getter get) const {
93  if (CE->getNumArgs() == 0) {
94  reportDebugMsg("Missing container argument", C);
95  return;
96  }
97 
98  auto State = C.getState();
99  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
100  if (Cont) {
101  const auto *Data = getContainerData(State, Cont);
102  if (Data) {
103  SymbolRef Field = get(Data);
104  if (Field) {
105  State = State->BindExpr(CE, C.getLocationContext(),
106  nonloc::SymbolVal(Field));
107  C.addTransition(State);
108  return;
109  }
110  }
111  }
112 
113  auto &BVF = C.getSValBuilder().getBasicValueFactory();
114  State = State->BindExpr(CE, C.getLocationContext(),
115  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
116 }
117 
118 void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE,
119  CheckerContext &C) const {
120  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121  return D->getBegin();
122  });
123 }
124 
125 void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE,
126  CheckerContext &C) const {
127  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
128  return D->getEnd();
129  });
130 }
131 
132 template <typename Getter>
133 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
134  CheckerContext &C,
135  Getter get,
136  SVal Default) const {
137  if (CE->getNumArgs() == 0) {
138  reportDebugMsg("Missing iterator argument", C);
139  return;
140  }
141 
142  auto State = C.getState();
143  SVal V = C.getSVal(CE->getArg(0));
144  const auto *Pos = getIteratorPosition(State, V);
145  if (Pos) {
146  State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
147  } else {
148  State = State->BindExpr(CE, C.getLocationContext(), Default);
149  }
150  C.addTransition(State);
151 }
152 
153 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
154  CheckerContext &C) const {
155  auto &BVF = C.getSValBuilder().getBasicValueFactory();
156  analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
157  return nonloc::SymbolVal(P->getOffset());
158  }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
159 }
160 
161 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
162  CheckerContext &C) const {
163  auto &BVF = C.getSValBuilder().getBasicValueFactory();
164  analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
165  return loc::MemRegionVal(P->getContainer());
166  }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
167 }
168 
169 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
170  CheckerContext &C) const {
171  auto &BVF = C.getSValBuilder().getBasicValueFactory();
172  analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
173  return
174  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
175  }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
176 }
177 
178 ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
179  CheckerContext &C) const {
180  ExplodedNode *N = C.generateNonFatalErrorNode();
181  if (!N)
182  return nullptr;
183 
184  auto &BR = C.getBugReporter();
185  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
186  Msg, N));
187  return N;
188 }
189 
190 void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
191  mgr.registerChecker<DebugIteratorModeling>();
192 }
193 
194 bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) {
195  return true;
196 }
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2702
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2689
StringRef P
const SymExpr * SymbolRef
Definition: SymExpr.h:110
LineState State
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:53
const IteratorPosition * getIteratorPosition(ProgramStateRef State, const SVal &Val)
Definition: Iterator.cpp:154
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
Definition: Iterator.cpp:149
#define V(N, I)
Definition: ASTContext.h:2941
Dataflow Directional Tag Classes.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2546
An immutable map from CallDescriptions to arbitrary data.
Definition: CallEvent.h:1110