clang  15.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 
19 
20 #include "Iterator.h"
21 
22 using namespace clang;
23 using namespace ento;
24 using namespace iterator;
25 
26 namespace {
27 
28 class DebugIteratorModeling
29  : public Checker<eval::Call> {
30 
31  std::unique_ptr<BugType> DebugMsgBugType;
32 
33  template <typename Getter>
34  void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
35  Getter get, SVal Default) const;
36  void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const;
37  void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const;
38  void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const;
39  ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
40 
41  typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *,
42  CheckerContext &) const;
43 
44  CallDescriptionMap<FnCheck> Callbacks = {
45  {{"clang_analyzer_iterator_position", 1},
46  &DebugIteratorModeling::analyzerIteratorPosition},
47  {{"clang_analyzer_iterator_container", 1},
48  &DebugIteratorModeling::analyzerIteratorContainer},
49  {{"clang_analyzer_iterator_validity", 1},
50  &DebugIteratorModeling::analyzerIteratorValidity},
51  };
52 
53 public:
54  DebugIteratorModeling();
55 
56  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
57 };
58 
59 } //namespace
60 
61 DebugIteratorModeling::DebugIteratorModeling() {
62  DebugMsgBugType.reset(
63  new BugType(this, "Checking analyzer assumptions", "debug",
64  /*SuppressOnSink=*/true));
65 }
66 
67 bool DebugIteratorModeling::evalCall(const CallEvent &Call,
68  CheckerContext &C) const {
69  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
70  if (!CE)
71  return false;
72 
73  const FnCheck *Handler = Callbacks.lookup(Call);
74  if (!Handler)
75  return false;
76 
77  (this->**Handler)(CE, C);
78  return true;
79 }
80 
81 template <typename Getter>
82 void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE,
83  CheckerContext &C,
84  Getter get,
85  SVal Default) const {
86  if (CE->getNumArgs() == 0) {
87  reportDebugMsg("Missing iterator argument", C);
88  return;
89  }
90 
91  auto State = C.getState();
92  SVal V = C.getSVal(CE->getArg(0));
93  const auto *Pos = getIteratorPosition(State, V);
94  if (Pos) {
95  State = State->BindExpr(CE, C.getLocationContext(), get(Pos));
96  } else {
97  State = State->BindExpr(CE, C.getLocationContext(), Default);
98  }
99  C.addTransition(State);
100 }
101 
102 void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE,
103  CheckerContext &C) const {
104  auto &BVF = C.getSValBuilder().getBasicValueFactory();
105  analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
106  return nonloc::SymbolVal(P->getOffset());
107  }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
108 }
109 
110 void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE,
111  CheckerContext &C) const {
112  auto &BVF = C.getSValBuilder().getBasicValueFactory();
113  analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) {
114  return loc::MemRegionVal(P->getContainer());
115  }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
116 }
117 
118 void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE,
119  CheckerContext &C) const {
120  auto &BVF = C.getSValBuilder().getBasicValueFactory();
121  analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) {
122  return
123  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid()))));
124  }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
125 }
126 
127 ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
128  CheckerContext &C) const {
129  ExplodedNode *N = C.generateNonFatalErrorNode();
130  if (!N)
131  return nullptr;
132 
133  auto &BR = C.getBugReporter();
134  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
135  Msg, N));
136  return N;
137 }
138 
139 void ento::registerDebugIteratorModeling(CheckerManager &mgr) {
140  mgr.registerChecker<DebugIteratorModeling>();
141 }
142 
143 bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) {
144  return true;
145 }
CallDescription.h
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
clang::index::SymbolRole::Call
@ Call
CallEvent.h
V
#define V(N, I)
Definition: ASTContext.h:3176
BuiltinCheckerRegistration.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2992
clang::ento::iterator::getIteratorPosition
const IteratorPosition * getIteratorPosition(ProgramStateRef State, const SVal &Val)
Definition: Iterator.cpp:184
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
BugType.h
clang::CallExpr::getNumArgs
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2979
Iterator.h
State
LineState State
Definition: UnwrappedLineFormatter.cpp:1126
CheckerContext.h
Checker.h
clang
Definition: CalledOnceCheck.h:17
clang::CallExpr
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2801