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
26using namespace clang;
27using namespace ento;
28
29namespace {
30struct RegionState {
31private:
32 enum Kind { Moved, Reported } K;
33 RegionState(Kind InK) : K(InK) {}
34
35public:
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
47namespace {
48class MoveChecker
49 : public Checker<check::PreCall, check::PostCall,
50 check::DeadSymbols, check::RegionChanges> {
51public:
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
64private:
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,
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
189public:
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
203private:
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
229REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, RegionState)
230
231// Define the inter-checker API.
232namespace clang {
233namespace ento {
234namespace move {
235bool isMovedFrom(ProgramStateRef State, const MemRegion *Region) {
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
275MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
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;
282 ProgramStateRef State = N->getState();
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
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
333const 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) {
341 ProgramStateRef State = N->getState();
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
350void 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
391ExplodedNode *MoveChecker::tryToReportBug(const MemRegion *Region,
392 const CXXRecordDecl *RD,
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
439void 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
494bool 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
510bool 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.
529bool 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
544bool 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
550MoveChecker::ObjectKind
551MoveChecker::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
573void 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
600void 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
682void 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
698ProgramStateRef 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)
725 State = removeFromState(State, Region->getBaseRegion());
726 }
727
728 return State;
729}
730
731void 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}
748void ento::registerMoveChecker(CheckerManager &mgr) {
749 MoveChecker *chk = mgr.registerChecker<MoveChecker>();
750 chk->setAggressiveness(
751 mgr.getAnalyzerOptions().getCheckerStringOption(chk, "WarnOn"), mgr);
752}
753
754bool ento::shouldRegisterMoveChecker(const CheckerManager &mgr) {
755 return true;
756}
Expr * E
Defines the clang::Expr interface and subclasses for C++ expressions.
#define X(type, name)
Definition: Value.h:143
static bool isAnyBaseRegionReported(ProgramStateRef State, const MemRegion *Region)
static ProgramStateRef removeFromState(ProgramStateRef State, const MemRegion *Region)
static const MemRegion * unwrapRValueReferenceIndirection(const MemRegion *MR)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
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
DeclContext * getDeclContext()
Definition: DeclBase.h:455
bool hasAttr() const
Definition: DeclBase.h:584
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:2805
OverloadedOperatorKind getOverloadedOperator() const
getOverloadedOperator - Which C++ overloaded operator this function represents, if any.
Definition: Decl.cpp:3965
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 Decl * getDecl() const
const LocationContext * getParent() const
It might return null.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
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
std::string getQualifiedNameAsString() 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:8319
bool isBooleanType() const
Definition: Type.h:8447
bool isRValueReferenceType() const
Definition: Type.h:8029
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
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
Definition: Checker.h:496
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const
Emits an error through a DiagnosticsEngine about an invalid user supplied checker option value.
const ProgramStateRef & getState() const
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
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:207
#define false
Definition: stdbool.h:26