clang  20.0.0git
MoveChecker.cpp
Go to the documentation of this file.
1 // MoveChecker.cpp - Check use of moved-from objects. - 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 checker which checks for potential misuses of a moved-from
10 // object. That means method calls on the object or copying it in moved-from
11 // state.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/AST/Attr.h"
16 #include "clang/AST/ExprCXX.h"
24 #include "llvm/ADT/StringSet.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 struct RegionState {
31 private:
32  enum Kind { Moved, Reported } K;
33  RegionState(Kind InK) : K(InK) {}
34 
35 public:
36  bool isReported() const { return K == Reported; }
37  bool isMoved() const { return K == Moved; }
38 
39  static RegionState getReported() { return RegionState(Reported); }
40  static RegionState getMoved() { return RegionState(Moved); }
41 
42  bool operator==(const RegionState &X) const { return K == X.K; }
43  void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
44 };
45 } // end of anonymous namespace
46 
47 namespace {
48 class MoveChecker
49  : public Checker<check::PreCall, check::PostCall,
50  check::DeadSymbols, check::RegionChanges> {
51 public:
52  void checkPreCall(const CallEvent &MC, CheckerContext &C) const;
53  void checkPostCall(const CallEvent &MC, CheckerContext &C) const;
54  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
56  checkRegionChanges(ProgramStateRef State,
57  const InvalidatedSymbols *Invalidated,
58  ArrayRef<const MemRegion *> RequestedRegions,
59  ArrayRef<const MemRegion *> InvalidatedRegions,
60  const LocationContext *LCtx, const CallEvent *Call) const;
61  void printState(raw_ostream &Out, ProgramStateRef State,
62  const char *NL, const char *Sep) const override;
63 
64 private:
65  enum MisuseKind { MK_FunCall, MK_Copy, MK_Move, MK_Dereference };
66  enum StdObjectKind { SK_NonStd, SK_Unsafe, SK_Safe, SK_SmartPtr };
67 
68  enum AggressivenessKind { // In any case, don't warn after a reset.
69  AK_Invalid = -1,
70  AK_KnownsOnly = 0, // Warn only about known move-unsafe classes.
71  AK_KnownsAndLocals = 1, // Also warn about all local objects.
72  AK_All = 2, // Warn on any use-after-move.
73  AK_NumKinds = AK_All
74  };
75 
76  static bool misuseCausesCrash(MisuseKind MK) {
77  return MK == MK_Dereference;
78  }
79 
80  struct ObjectKind {
81  // Is this a local variable or a local rvalue reference?
82  bool IsLocal;
83  // Is this an STL object? If so, of what kind?
84  StdObjectKind StdKind;
85  };
86 
87  // STL smart pointers are automatically re-initialized to null when moved
88  // from. So we can't warn on many methods, but we can warn when it is
89  // dereferenced, which is UB even if the resulting lvalue never gets read.
90  const llvm::StringSet<> StdSmartPtrClasses = {
91  "shared_ptr",
92  "unique_ptr",
93  "weak_ptr",
94  };
95 
96  // Not all of these are entirely move-safe, but they do provide *some*
97  // guarantees, and it means that somebody is using them after move
98  // in a valid manner.
99  // TODO: We can still try to identify *unsafe* use after move,
100  // like we did with smart pointers.
101  const llvm::StringSet<> StdSafeClasses = {
102  "basic_filebuf",
103  "basic_ios",
104  "future",
105  "optional",
106  "packaged_task",
107  "promise",
108  "shared_future",
109  "shared_lock",
110  "thread",
111  "unique_lock",
112  };
113 
114  // Should we bother tracking the state of the object?
115  bool shouldBeTracked(ObjectKind OK) const {
116  // In non-aggressive mode, only warn on use-after-move of local variables
117  // (or local rvalue references) and of STL objects. The former is possible
118  // because local variables (or local rvalue references) are not tempting
119  // their user to re-use the storage. The latter is possible because STL
120  // objects are known to end up in a valid but unspecified state after the
121  // move and their state-reset methods are also known, which allows us to
122  // predict precisely when use-after-move is invalid.
123  // Some STL objects are known to conform to additional contracts after move,
124  // so they are not tracked. However, smart pointers specifically are tracked
125  // because we can perform extra checking over them.
126  // In aggressive mode, warn on any use-after-move because the user has
127  // intentionally asked us to completely eliminate use-after-move
128  // in his code.
129  return (Aggressiveness == AK_All) ||
130  (Aggressiveness >= AK_KnownsAndLocals && OK.IsLocal) ||
131  OK.StdKind == SK_Unsafe || OK.StdKind == SK_SmartPtr;
132  }
133 
134  // Some objects only suffer from some kinds of misuses, but we need to track
135  // them anyway because we cannot know in advance what misuse will we find.
136  bool shouldWarnAbout(ObjectKind OK, MisuseKind MK) const {
137  // Additionally, only warn on smart pointers when they are dereferenced (or
138  // local or we are aggressive).
139  return shouldBeTracked(OK) &&
140  ((Aggressiveness == AK_All) ||
141  (Aggressiveness >= AK_KnownsAndLocals && OK.IsLocal) ||
142  OK.StdKind != SK_SmartPtr || MK == MK_Dereference);
143  }
144 
145  // Obtains ObjectKind of an object. Because class declaration cannot always
146  // be easily obtained from the memory region, it is supplied separately.
147  ObjectKind classifyObject(const MemRegion *MR, const CXXRecordDecl *RD) const;
148 
149  // Classifies the object and dumps a user-friendly description string to
150  // the stream.
151  void explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
152  const CXXRecordDecl *RD, MisuseKind MK) const;
153 
154  bool belongsTo(const CXXRecordDecl *RD, const llvm::StringSet<> &Set) const;
155 
156  class MovedBugVisitor : public BugReporterVisitor {
157  public:
158  MovedBugVisitor(const MoveChecker &Chk, const MemRegion *R,
159  const CXXRecordDecl *RD, MisuseKind MK)
160  : Chk(Chk), Region(R), RD(RD), MK(MK), Found(false) {}
161 
162  void Profile(llvm::FoldingSetNodeID &ID) const override {
163  static int X = 0;
164  ID.AddPointer(&X);
165  ID.AddPointer(Region);
166  // Don't add RD because it's, in theory, uniquely determined by
167  // the region. In practice though, it's not always possible to obtain
168  // the declaration directly from the region, that's why we store it
169  // in the first place.
170  }
171 
172  PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
173  BugReporterContext &BRC,
174  PathSensitiveBugReport &BR) override;
175 
176  private:
177  const MoveChecker &Chk;
178  // The tracked region.
179  const MemRegion *Region;
180  // The class of the tracked object.
181  const CXXRecordDecl *RD;
182  // How exactly the object was misused.
183  const MisuseKind MK;
184  bool Found;
185  };
186 
187  AggressivenessKind Aggressiveness = AK_KnownsAndLocals;
188 
189 public:
190  void setAggressiveness(StringRef Str, CheckerManager &Mgr) {
191  Aggressiveness =
192  llvm::StringSwitch<AggressivenessKind>(Str)
193  .Case("KnownsOnly", AK_KnownsOnly)
194  .Case("KnownsAndLocals", AK_KnownsAndLocals)
195  .Case("All", AK_All)
196  .Default(AK_Invalid);
197 
198  if (Aggressiveness == AK_Invalid)
199  Mgr.reportInvalidCheckerOptionValue(this, "WarnOn",
200  "either \"KnownsOnly\", \"KnownsAndLocals\" or \"All\" string value");
201  };
202 
203 private:
204  BugType BT{this, "Use-after-move", categories::CXXMoveSemantics};
205 
206  // Check if the given form of potential misuse of a given object
207  // should be reported. If so, get it reported. The callback from which
208  // this function was called should immediately return after the call
209  // because this function adds one or two transitions.
210  void modelUse(ProgramStateRef State, const MemRegion *Region,
211  const CXXRecordDecl *RD, MisuseKind MK,
212  CheckerContext &C) const;
213 
214  // Returns the exploded node against which the report was emitted.
215  // The caller *must* add any further transitions against this node.
216  // Returns nullptr and does not report if such node already exists.
217  ExplodedNode *tryToReportBug(const MemRegion *Region, const CXXRecordDecl *RD,
218  CheckerContext &C, MisuseKind MK) const;
219 
220  bool isInMoveSafeContext(const LocationContext *LC) const;
221  bool isStateResetMethod(const CXXMethodDecl *MethodDec) const;
222  bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const;
223  const ExplodedNode *getMoveLocation(const ExplodedNode *N,
224  const MemRegion *Region,
225  CheckerContext &C) const;
226 };
227 } // end anonymous namespace
228 
229 REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, RegionState)
230 
231 // Define the inter-checker API.
232 namespace clang {
233 namespace ento {
234 namespace move {
236  const RegionState *RS = State->get<TrackedRegionMap>(Region);
237  return RS && (RS->isMoved() || RS->isReported());
238 }
239 } // namespace move
240 } // namespace ento
241 } // namespace clang
242 
243 // If a region is removed all of the subregions needs to be removed too.
245  const MemRegion *Region) {
246  if (!Region)
247  return State;
248  for (auto &E : State->get<TrackedRegionMap>()) {
249  if (E.first->isSubRegionOf(Region))
250  State = State->remove<TrackedRegionMap>(E.first);
251  }
252  return State;
253 }
254 
256  const MemRegion *Region) {
257  for (auto &E : State->get<TrackedRegionMap>()) {
258  if (Region->isSubRegionOf(E.first) && E.second.isReported())
259  return true;
260  }
261  return false;
262 }
263 
265  if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(MR)) {
266  SymbolRef Sym = SR->getSymbol();
267  if (Sym->getType()->isRValueReferenceType())
268  if (const MemRegion *OriginMR = Sym->getOriginRegion())
269  return OriginMR;
270  }
271  return MR;
272 }
273 
275 MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
276  BugReporterContext &BRC,
278  // We need only the last move of the reported object's region.
279  // The visitor walks the ExplodedGraph backwards.
280  if (Found)
281  return nullptr;
283  ProgramStateRef StatePrev = N->getFirstPred()->getState();
284  const RegionState *TrackedObject = State->get<TrackedRegionMap>(Region);
285  const RegionState *TrackedObjectPrev =
286  StatePrev->get<TrackedRegionMap>(Region);
287  if (!TrackedObject)
288  return nullptr;
289  if (TrackedObjectPrev && TrackedObject)
290  return nullptr;
291 
292  // Retrieve the associated statement.
293  const Stmt *S = N->getStmtForDiagnostics();
294  if (!S)
295  return nullptr;
296  Found = true;
297 
298  SmallString<128> Str;
299  llvm::raw_svector_ostream OS(Str);
300 
301  ObjectKind OK = Chk.classifyObject(Region, RD);
302  switch (OK.StdKind) {
303  case SK_SmartPtr:
304  if (MK == MK_Dereference) {
305  OS << "Smart pointer";
306  Chk.explainObject(OS, Region, RD, MK);
307  OS << " is reset to null when moved from";
308  break;
309  }
310 
311  // If it's not a dereference, we don't care if it was reset to null
312  // or that it is even a smart pointer.
313  [[fallthrough]];
314  case SK_NonStd:
315  case SK_Safe:
316  OS << "Object";
317  Chk.explainObject(OS, Region, RD, MK);
318  OS << " is moved";
319  break;
320  case SK_Unsafe:
321  OS << "Object";
322  Chk.explainObject(OS, Region, RD, MK);
323  OS << " is left in a valid but unspecified state after move";
324  break;
325  }
326 
327  // Generate the extra diagnostic.
329  N->getLocationContext());
330  return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
331 }
332 
333 const ExplodedNode *MoveChecker::getMoveLocation(const ExplodedNode *N,
334  const MemRegion *Region,
335  CheckerContext &C) const {
336  // Walk the ExplodedGraph backwards and find the first node that referred to
337  // the tracked region.
338  const ExplodedNode *MoveNode = N;
339 
340  while (N) {
342  if (!State->get<TrackedRegionMap>(Region))
343  break;
344  MoveNode = N;
345  N = N->pred_empty() ? nullptr : *(N->pred_begin());
346  }
347  return MoveNode;
348 }
349 
350 void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region,
351  const CXXRecordDecl *RD, MisuseKind MK,
352  CheckerContext &C) const {
353  assert(!C.isDifferent() && "No transitions should have been made by now");
354  const RegionState *RS = State->get<TrackedRegionMap>(Region);
355  ObjectKind OK = classifyObject(Region, RD);
356 
357  // Just in case: if it's not a smart pointer but it does have operator *,
358  // we shouldn't call the bug a dereference.
359  if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr)
360  MK = MK_FunCall;
361 
362  if (!RS || !shouldWarnAbout(OK, MK)
363  || isInMoveSafeContext(C.getLocationContext())) {
364  // Finalize changes made by the caller.
365  C.addTransition(State);
366  return;
367  }
368 
369  // Don't report it in case if any base region is already reported.
370  // But still generate a sink in case of UB.
371  // And still finalize changes made by the caller.
372  if (isAnyBaseRegionReported(State, Region)) {
373  if (misuseCausesCrash(MK)) {
374  C.generateSink(State, C.getPredecessor());
375  } else {
376  C.addTransition(State);
377  }
378  return;
379  }
380 
381  ExplodedNode *N = tryToReportBug(Region, RD, C, MK);
382 
383  // If the program has already crashed on this path, don't bother.
384  if (!N || N->isSink())
385  return;
386 
387  State = State->set<TrackedRegionMap>(Region, RegionState::getReported());
388  C.addTransition(State, N);
389 }
390 
391 ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
392  const CXXRecordDecl *RD,
393  CheckerContext &C,
394  MisuseKind MK) const {
395  if (ExplodedNode *N = misuseCausesCrash(MK) ? C.generateErrorNode()
396  : C.generateNonFatalErrorNode()) {
397  // Uniqueing report to the same object.
398  PathDiagnosticLocation LocUsedForUniqueing;
399  const ExplodedNode *MoveNode = getMoveLocation(N, Region, C);
400 
401  if (const Stmt *MoveStmt = MoveNode->getStmtForDiagnostics())
402  LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
403  MoveStmt, C.getSourceManager(), MoveNode->getLocationContext());
404 
405  // Creating the error message.
407  llvm::raw_svector_ostream OS(Str);
408  switch(MK) {
409  case MK_FunCall:
410  OS << "Method called on moved-from object";
411  explainObject(OS, Region, RD, MK);
412  break;
413  case MK_Copy:
414  OS << "Moved-from object";
415  explainObject(OS, Region, RD, MK);
416  OS << " is copied";
417  break;
418  case MK_Move:
419  OS << "Moved-from object";
420  explainObject(OS, Region, RD, MK);
421  OS << " is moved";
422  break;
423  case MK_Dereference:
424  OS << "Dereference of null smart pointer";
425  explainObject(OS, Region, RD, MK);
426  break;
427  }
428 
429  auto R = std::make_unique<PathSensitiveBugReport>(
430  BT, OS.str(), N, LocUsedForUniqueing,
431  MoveNode->getLocationContext()->getDecl());
432  R->addVisitor(std::make_unique<MovedBugVisitor>(*this, Region, RD, MK));
433  C.emitReport(std::move(R));
434  return N;
435  }
436  return nullptr;
437 }
438 
439 void MoveChecker::checkPostCall(const CallEvent &Call,
440  CheckerContext &C) const {
441  const auto *AFC = dyn_cast<AnyFunctionCall>(&Call);
442  if (!AFC)
443  return;
444 
445  ProgramStateRef State = C.getState();
446  const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(AFC->getDecl());
447  if (!MethodDecl)
448  return;
449 
450  // Check if an object became moved-from.
451  // Object can become moved from after a call to move assignment operator or
452  // move constructor .
453  const auto *ConstructorDecl = dyn_cast<CXXConstructorDecl>(MethodDecl);
454  if (ConstructorDecl && !ConstructorDecl->isMoveConstructor())
455  return;
456 
457  if (!ConstructorDecl && !MethodDecl->isMoveAssignmentOperator())
458  return;
459 
460  const auto ArgRegion = AFC->getArgSVal(0).getAsRegion();
461  if (!ArgRegion)
462  return;
463 
464  // Skip moving the object to itself.
465  const auto *CC = dyn_cast_or_null<CXXConstructorCall>(&Call);
466  if (CC && CC->getCXXThisVal().getAsRegion() == ArgRegion)
467  return;
468 
469  if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC))
470  if (IC->getCXXThisVal().getAsRegion() == ArgRegion)
471  return;
472 
473  const MemRegion *BaseRegion = ArgRegion->getBaseRegion();
474  // Skip temp objects because of their short lifetime.
475  if (BaseRegion->getAs<CXXTempObjectRegion>() ||
476  AFC->getArgExpr(0)->isPRValue())
477  return;
478  // If it has already been reported do not need to modify the state.
479 
480  if (State->get<TrackedRegionMap>(ArgRegion))
481  return;
482 
483  const CXXRecordDecl *RD = MethodDecl->getParent();
484  ObjectKind OK = classifyObject(ArgRegion, RD);
485  if (shouldBeTracked(OK)) {
486  // Mark object as moved-from.
487  State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved());
488  C.addTransition(State);
489  return;
490  }
491  assert(!C.isDifferent() && "Should not have made transitions on this path!");
492 }
493 
494 bool MoveChecker::isMoveSafeMethod(const CXXMethodDecl *MethodDec) const {
495  // We abandon the cases where bool/void/void* conversion happens.
496  if (const auto *ConversionDec =
497  dyn_cast_or_null<CXXConversionDecl>(MethodDec)) {
498  const Type *Tp = ConversionDec->getConversionType().getTypePtrOrNull();
499  if (!Tp)
500  return false;
501  if (Tp->isBooleanType() || Tp->isVoidType() || Tp->isVoidPointerType())
502  return true;
503  }
504  // Function call `empty` can be skipped.
505  return (MethodDec && MethodDec->getDeclName().isIdentifier() &&
506  (MethodDec->getName().lower() == "empty" ||
507  MethodDec->getName().lower() == "isempty"));
508 }
509 
510 bool MoveChecker::isStateResetMethod(const CXXMethodDecl *MethodDec) const {
511  if (!MethodDec)
512  return false;
513  if (MethodDec->hasAttr<ReinitializesAttr>())
514  return true;
515  if (MethodDec->getDeclName().isIdentifier()) {
516  std::string MethodName = MethodDec->getName().lower();
517  // TODO: Some of these methods (eg., resize) are not always resetting
518  // the state, so we should consider looking at the arguments.
519  if (MethodName == "assign" || MethodName == "clear" ||
520  MethodName == "destroy" || MethodName == "reset" ||
521  MethodName == "resize" || MethodName == "shrink")
522  return true;
523  }
524  return false;
525 }
526 
527 // Don't report an error inside a move related operation.
528 // We assume that the programmer knows what she does.
529 bool MoveChecker::isInMoveSafeContext(const LocationContext *LC) const {
530  do {
531  const auto *CtxDec = LC->getDecl();
532  auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(CtxDec);
533  auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(CtxDec);
534  auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(CtxDec);
535  if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) ||
536  (MethodDec && MethodDec->isOverloadedOperator() &&
537  MethodDec->getOverloadedOperator() == OO_Equal) ||
538  isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec))
539  return true;
540  } while ((LC = LC->getParent()));
541  return false;
542 }
543 
544 bool MoveChecker::belongsTo(const CXXRecordDecl *RD,
545  const llvm::StringSet<> &Set) const {
546  const IdentifierInfo *II = RD->getIdentifier();
547  return II && Set.count(II->getName());
548 }
549 
550 MoveChecker::ObjectKind
551 MoveChecker::classifyObject(const MemRegion *MR,
552  const CXXRecordDecl *RD) const {
553  // Local variables and local rvalue references are classified as "Local".
554  // For the purposes of this checker, we classify move-safe STL types
555  // as not-"STL" types, because that's how the checker treats them.
557  bool IsLocal =
558  isa_and_nonnull<VarRegion, CXXLifetimeExtendedObjectRegion>(MR) &&
559  isa<StackSpaceRegion>(MR->getMemorySpace());
560 
561  if (!RD || !RD->getDeclContext()->isStdNamespace())
562  return { IsLocal, SK_NonStd };
563 
564  if (belongsTo(RD, StdSmartPtrClasses))
565  return { IsLocal, SK_SmartPtr };
566 
567  if (belongsTo(RD, StdSafeClasses))
568  return { IsLocal, SK_Safe };
569 
570  return { IsLocal, SK_Unsafe };
571 }
572 
573 void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
574  const CXXRecordDecl *RD, MisuseKind MK) const {
575  // We may need a leading space every time we actually explain anything,
576  // and we never know if we are to explain anything until we try.
577  if (const auto DR =
578  dyn_cast_or_null<DeclRegion>(unwrapRValueReferenceIndirection(MR))) {
579  const auto *RegionDecl = cast<NamedDecl>(DR->getDecl());
580  OS << " '" << RegionDecl->getDeclName() << "'";
581  }
582 
583  ObjectKind OK = classifyObject(MR, RD);
584  switch (OK.StdKind) {
585  case SK_NonStd:
586  case SK_Safe:
587  break;
588  case SK_SmartPtr:
589  if (MK != MK_Dereference)
590  break;
591 
592  // We only care about the type if it's a dereference.
593  [[fallthrough]];
594  case SK_Unsafe:
595  OS << " of type '" << RD->getQualifiedNameAsString() << "'";
596  break;
597  };
598 }
599 
600 void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
601  ProgramStateRef State = C.getState();
602 
603  // Remove the MemRegions from the map on which a ctor/dtor call or assignment
604  // happened.
605 
606  // Checking constructor calls.
607  if (const auto *CC = dyn_cast<CXXConstructorCall>(&Call)) {
608  State = removeFromState(State, CC->getCXXThisVal().getAsRegion());
609  auto CtorDec = CC->getDecl();
610  // Check for copying a moved-from object and report the bug.
611  if (CtorDec && CtorDec->isCopyOrMoveConstructor()) {
612  const MemRegion *ArgRegion = CC->getArgSVal(0).getAsRegion();
613  const CXXRecordDecl *RD = CtorDec->getParent();
614  MisuseKind MK = CtorDec->isMoveConstructor() ? MK_Move : MK_Copy;
615  modelUse(State, ArgRegion, RD, MK, C);
616  return;
617  }
618  }
619 
620  const auto IC = dyn_cast<CXXInstanceCall>(&Call);
621  if (!IC)
622  return;
623 
624  const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
625  if (!ThisRegion)
626  return;
627 
628  // The remaining part is check only for method call on a moved-from object.
629  const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(IC->getDecl());
630  if (!MethodDecl)
631  return;
632 
633  // Calling a destructor on a moved object is fine.
634  if (isa<CXXDestructorDecl>(MethodDecl))
635  return;
636 
637  // We want to investigate the whole object, not only sub-object of a parent
638  // class in which the encountered method defined.
639  ThisRegion = ThisRegion->getMostDerivedObjectRegion();
640 
641  if (isStateResetMethod(MethodDecl)) {
642  State = removeFromState(State, ThisRegion);
643  C.addTransition(State);
644  return;
645  }
646 
647  if (isMoveSafeMethod(MethodDecl))
648  return;
649 
650  // Store class declaration as well, for bug reporting purposes.
651  const CXXRecordDecl *RD = MethodDecl->getParent();
652 
653  if (MethodDecl->isOverloadedOperator()) {
654  OverloadedOperatorKind OOK = MethodDecl->getOverloadedOperator();
655 
656  if (OOK == OO_Equal) {
657  // Remove the tracked object for every assignment operator, but report bug
658  // only for move or copy assignment's argument.
659  State = removeFromState(State, ThisRegion);
660 
661  if (MethodDecl->isCopyAssignmentOperator() ||
662  MethodDecl->isMoveAssignmentOperator()) {
663  const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion();
664  MisuseKind MK =
665  MethodDecl->isMoveAssignmentOperator() ? MK_Move : MK_Copy;
666  modelUse(State, ArgRegion, RD, MK, C);
667  return;
668  }
669  C.addTransition(State);
670  return;
671  }
672 
673  if (OOK == OO_Star || OOK == OO_Arrow) {
674  modelUse(State, ThisRegion, RD, MK_Dereference, C);
675  return;
676  }
677  }
678 
679  modelUse(State, ThisRegion, RD, MK_FunCall, C);
680 }
681 
682 void MoveChecker::checkDeadSymbols(SymbolReaper &SymReaper,
683  CheckerContext &C) const {
684  ProgramStateRef State = C.getState();
685  TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>();
686  for (auto E : TrackedRegions) {
687  const MemRegion *Region = E.first;
688  bool IsRegDead = !SymReaper.isLiveRegion(Region);
689 
690  // Remove the dead regions from the region map.
691  if (IsRegDead) {
692  State = State->remove<TrackedRegionMap>(Region);
693  }
694  }
695  C.addTransition(State);
696 }
697 
698 ProgramStateRef MoveChecker::checkRegionChanges(
699  ProgramStateRef State, const InvalidatedSymbols *Invalidated,
700  ArrayRef<const MemRegion *> RequestedRegions,
701  ArrayRef<const MemRegion *> InvalidatedRegions,
702  const LocationContext *LCtx, const CallEvent *Call) const {
703  if (Call) {
704  // Relax invalidation upon function calls: only invalidate parameters
705  // that are passed directly via non-const pointers or non-const references
706  // or rvalue references.
707  // In case of an InstanceCall don't invalidate the this-region since
708  // it is fully handled in checkPreCall and checkPostCall.
709  const MemRegion *ThisRegion = nullptr;
710  if (const auto *IC = dyn_cast<CXXInstanceCall>(Call))
711  ThisRegion = IC->getCXXThisVal().getAsRegion();
712 
713  // Requested ("explicit") regions are the regions passed into the call
714  // directly, but not all of them end up being invalidated.
715  // But when they do, they appear in the InvalidatedRegions array as well.
716  for (const auto *Region : RequestedRegions) {
717  if (ThisRegion != Region &&
718  llvm::is_contained(InvalidatedRegions, Region))
719  State = removeFromState(State, Region);
720  }
721  } else {
722  // For invalidations that aren't caused by calls, assume nothing. In
723  // particular, direct write into an object's field invalidates the status.
724  for (const auto *Region : InvalidatedRegions)
726  }
727 
728  return State;
729 }
730 
731 void MoveChecker::printState(raw_ostream &Out, ProgramStateRef State,
732  const char *NL, const char *Sep) const {
733 
734  TrackedRegionMapTy RS = State->get<TrackedRegionMap>();
735 
736  if (!RS.isEmpty()) {
737  Out << Sep << "Moved-from objects :" << NL;
738  for (auto I: RS) {
739  I.first->dumpToStream(Out);
740  if (I.second.isMoved())
741  Out << ": moved";
742  else
743  Out << ": moved and reported";
744  Out << NL;
745  }
746  }
747 }
748 void ento::registerMoveChecker(CheckerManager &mgr) {
749  MoveChecker *chk = mgr.registerChecker<MoveChecker>();
750  chk->setAggressiveness(
751  mgr.getAnalyzerOptions().getCheckerStringOption(chk, "WarnOn"), mgr);
752 }
753 
754 bool ento::shouldRegisterMoveChecker(const CheckerManager &mgr) {
755  return true;
756 }
static char ID
Definition: Arena.cpp:183
enum clang::sema::@1659::IndirectLocalPathEntry::EntryKind Kind
Expr * E
Defines the clang::Expr interface and subclasses for C++ expressions.
#define X(type, name)
Definition: Value.h:143
static const MemRegion * unwrapRValueReferenceIndirection(const MemRegion *MR)
static bool isAnyBaseRegionReported(ProgramStateRef State, const MemRegion *Region)
static ProgramStateRef removeFromState(ProgramStateRef State, const MemRegion *Region)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
LineState State
StringRef getCheckerStringOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Query an option's string value.
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2064
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:2090
bool isStdNamespace() const
Definition: DeclBase.cpp:1317
bool hasAttr() const
Definition: DeclBase.h:584
DeclContext * getDeclContext()
Definition: DeclBase.h:455
bool isIdentifier() const
Predicate functions for querying what type of name this is.
bool isOverloadedOperator() const
Whether this function declaration represents an C++ overloaded operator, e.g., "operator+".
Definition: Decl.h:2806
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition: Decl.cpp:3969
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const LocationContext * getParent() const
It might return null.
const Decl * getDecl() const
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:315
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
std::string getQualifiedNameAsString(bool WithGlobalNsPrefix=false) const
Definition: Decl.cpp:1668
Stmt - This represents one statement.
Definition: Stmt.h:84
The base class of the type hierarchy.
Definition: Type.h:1829
bool isVoidType() const
Definition: Type.h:8347
bool isBooleanType() const
Definition: Type.h:8475
bool isRValueReferenceType() const
Definition: Type.h:8039
bool isVoidPointerType() const
Definition: Type.cpp:665
const SourceManager & getSourceManager() const
Definition: BugReporter.h:737
BugReporterVisitors are used to add custom diagnostics along a path.
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:153
const AnalyzerOptions & getAnalyzerOptions() const
void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const
Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
ExplodedNode * getFirstPred()
const ProgramStateRef & getState() const
const LocationContext * getLocationContext() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:97
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
Definition: MemRegion.cpp:1328
virtual bool isSubRegionOf(const MemRegion *R) const
Check if the region is a subregion of the given region.
Definition: MemRegion.cpp:1381
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Definition: MemRegion.cpp:1354
const RegionTy * getAs() const
Definition: MemRegion.h:1388
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getMostDerivedObjectRegion() const
Recursively retrieve the region of the most derived class instance of regions of C++ base class insta...
Definition: MemRegion.cpp:1374
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Symbolic value.
Definition: SymExpr.h:30
virtual const MemRegion * getOriginRegion() const
Find the region from which this symbol originates.
Definition: SymExpr.h:104
virtual QualType getType() const =0
A class responsible for cleaning up unused symbols.
bool isLiveRegion(const MemRegion *region)
const char *const CXXMoveSemantics
bool isMovedFrom(ProgramStateRef State, const MemRegion *Region)
Returns true if the object is known to have been recently std::moved.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Definition: Store.h:51
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
The JSON file list parser is used to communicate input to InstallAPI.
OverloadedOperatorKind
Enumeration specifying the different kinds of C++ overloaded operators.
Definition: OperatorKinds.h:21
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition: CallGraph.h:223
#define false
Definition: stdbool.h:26