clang  15.0.0git
DebugContainerModeling.cpp
Go to the documentation of this file.
1 //==-- DebugContainerModeling.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 DebugContainerModeling
29  : public Checker<eval::Call> {
30 
31  std::unique_ptr<BugType> DebugMsgBugType;
32 
33  template <typename Getter>
34  void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
35  Getter get) const;
36  void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
37  void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
38  ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
39 
40  typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
41  CheckerContext &) const;
42 
43  CallDescriptionMap<FnCheck> Callbacks = {
44  {{"clang_analyzer_container_begin", 1},
45  &DebugContainerModeling::analyzerContainerBegin},
46  {{"clang_analyzer_container_end", 1},
47  &DebugContainerModeling::analyzerContainerEnd},
48  };
49 
50 public:
51  DebugContainerModeling();
52 
53  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
54 };
55 
56 } //namespace
57 
58 DebugContainerModeling::DebugContainerModeling() {
59  DebugMsgBugType.reset(
60  new BugType(this, "Checking analyzer assumptions", "debug",
61  /*SuppressOnSink=*/true));
62 }
63 
64 bool DebugContainerModeling::evalCall(const CallEvent &Call,
65  CheckerContext &C) const {
66  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
67  if (!CE)
68  return false;
69 
70  const FnCheck *Handler = Callbacks.lookup(Call);
71  if (!Handler)
72  return false;
73 
74  (this->**Handler)(CE, C);
75  return true;
76 }
77 
78 template <typename Getter>
79 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
80  CheckerContext &C,
81  Getter get) const {
82  if (CE->getNumArgs() == 0) {
83  reportDebugMsg("Missing container argument", C);
84  return;
85  }
86 
87  auto State = C.getState();
88  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
89  if (Cont) {
90  const auto *Data = getContainerData(State, Cont);
91  if (Data) {
92  SymbolRef Field = get(Data);
93  if (Field) {
94  State = State->BindExpr(CE, C.getLocationContext(),
95  nonloc::SymbolVal(Field));
96 
97  // Progpagate interestingness from the container's data (marked
98  // interesting by an `ExprInspection` debug call to the container
99  // itself.
100  const NoteTag *InterestingTag =
101  C.getNoteTag(
102  [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
103  if (BR.isInteresting(Field)) {
104  BR.markInteresting(Cont);
105  }
106  return "";
107  });
108  C.addTransition(State, InterestingTag);
109  return;
110  }
111  }
112  }
113 
114  auto &BVF = C.getSValBuilder().getBasicValueFactory();
115  State = State->BindExpr(CE, C.getLocationContext(),
116  nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
117 }
118 
119 void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
120  CheckerContext &C) const {
121  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
122  return D->getBegin();
123  });
124 }
125 
126 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
127  CheckerContext &C) const {
128  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
129  return D->getEnd();
130  });
131 }
132 
133 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
134  CheckerContext &C) const {
135  ExplodedNode *N = C.generateNonFatalErrorNode();
136  if (!N)
137  return nullptr;
138 
139  auto &BR = C.getBugReporter();
140  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
141  Msg, N));
142  return N;
143 }
144 
145 void ento::registerDebugContainerModeling(CheckerManager &mgr) {
146  mgr.registerChecker<DebugContainerModeling>();
147 }
148 
149 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
150  return true;
151 }
CallDescription.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:55
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:111
clang::index::SymbolRole::Call
@ Call
CallEvent.h
BuiltinCheckerRegistration.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2992
clang::index::SymbolKind::Field
@ Field
clang::ento::iterator::getContainerData
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
Definition: Iterator.cpp:179
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