clang  14.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 
18 
19 #include "Iterator.h"
20 
21 using namespace clang;
22 using namespace ento;
23 using namespace iterator;
24 
25 namespace {
26 
27 class DebugContainerModeling
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  ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
38 
39  typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
40  CheckerContext &) const;
41 
42  CallDescriptionMap<FnCheck> Callbacks = {
43  {{0, "clang_analyzer_container_begin", 1},
44  &DebugContainerModeling::analyzerContainerBegin},
45  {{0, "clang_analyzer_container_end", 1},
46  &DebugContainerModeling::analyzerContainerEnd},
47  };
48 
49 public:
50  DebugContainerModeling();
51 
52  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
53 };
54 
55 } //namespace
56 
57 DebugContainerModeling::DebugContainerModeling() {
58  DebugMsgBugType.reset(
59  new BugType(this, "Checking analyzer assumptions", "debug",
60  /*SuppressOnSink=*/true));
61 }
62 
63 bool DebugContainerModeling::evalCall(const CallEvent &Call,
64  CheckerContext &C) const {
65  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
66  if (!CE)
67  return false;
68 
69  const FnCheck *Handler = Callbacks.lookup(Call);
70  if (!Handler)
71  return false;
72 
73  (this->**Handler)(CE, C);
74  return true;
75 }
76 
77 template <typename Getter>
78 void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
79  CheckerContext &C,
80  Getter get) const {
81  if (CE->getNumArgs() == 0) {
82  reportDebugMsg("Missing container argument", C);
83  return;
84  }
85 
86  auto State = C.getState();
87  const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
88  if (Cont) {
89  const auto *Data = getContainerData(State, Cont);
90  if (Data) {
91  SymbolRef Field = get(Data);
92  if (Field) {
93  State = State->BindExpr(CE, C.getLocationContext(),
94  nonloc::SymbolVal(Field));
95 
96  // Progpagate interestingness from the container's data (marked
97  // interesting by an `ExprInspection` debug call to the container
98  // itself.
99  const NoteTag *InterestingTag =
100  C.getNoteTag(
101  [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
102  if (BR.isInteresting(Field)) {
103  BR.markInteresting(Cont);
104  }
105  return "";
106  });
107  C.addTransition(State, InterestingTag);
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 DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
119  CheckerContext &C) const {
120  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
121  return D->getBegin();
122  });
123 }
124 
125 void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
126  CheckerContext &C) const {
127  analyzerContainerDataField(CE, C, [](const ContainerData *D) {
128  return D->getEnd();
129  });
130 }
131 
132 ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
133  CheckerContext &C) const {
134  ExplodedNode *N = C.generateNonFatalErrorNode();
135  if (!N)
136  return nullptr;
137 
138  auto &BR = C.getBugReporter();
139  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
140  Msg, N));
141  return N;
142 }
143 
144 void ento::registerDebugContainerModeling(CheckerManager &mgr) {
145  mgr.registerChecker<DebugContainerModeling>();
146 }
147 
148 bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
149  return true;
150 }
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:54
clang::ento::SymbolRef
const SymExpr * SymbolRef
Definition: SymExpr.h:110
clang::index::SymbolRole::Call
@ Call
CallEvent.h
BuiltinCheckerRegistration.h
clang::CallExpr::getArg
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2986
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:2973
Iterator.h
State
LineState State
Definition: UnwrappedLineFormatter.cpp:986
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:2795