void MoveChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { const auto *AFC = dyn_cast<AnyFunctionCall>(&Call); if (!AFC) return; ProgramStateRef State = C.getState(); const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(AFC->getDecl()); if (!MethodDecl) return; // Check if an object became moved-from. // Object can become moved from after a call to move assignment operator or // move constructor . const auto *ConstructorDecl = dyn_cast<CXXConstructorDecl>(MethodDecl); if (ConstructorDecl && !ConstructorDecl->isMoveConstructor()) return; if (!ConstructorDecl && !MethodDecl->isMoveAssignmentOperator()) return; const auto ArgRegion = AFC->getArgSVal(0).getAsRegion(); if (!ArgRegion) return; // Skip moving the object to itself. const auto *CC = dyn_cast_or_null<CXXConstructorCall>(&Call); if (CC && CC->getCXXThisVal().getAsRegion() == ArgRegion) return; if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC)) if (IC->getCXXThisVal().getAsRegion() == ArgRegion) return; const MemRegion *BaseRegion = ArgRegion->getBaseRegion(); // Skip temp objects because of their short lifetime. if (BaseRegion->getAs<CXXTempObjectRegion>() || AFC->getArgExpr(0)->isRValue()) return; // If it has already been reported do not need to modify the state. if (State->get<TrackedRegionMap>(ArgRegion)) return; const CXXRecordDecl *RD = MethodDecl->getParent(); ObjectKind OK = classifyObject(ArgRegion, RD); if (shouldBeTracked(OK)) { // Mark object as moved-from. State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved()); C.addTransition(State); return; } assert(!C.isDifferent() && "Should not have made transitions on this path!"); }
void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region, const CXXRecordDecl *RD, MisuseKind MK, CheckerContext &C) const { assert(!C.isDifferent() && "No transitions should have been made by now"); const RegionState *RS = State->get<TrackedRegionMap>(Region); ObjectKind OK = classifyObject(Region, RD); // Just in case: if it's not a smart pointer but it does have operator *, // we shouldn't call the bug a dereference. if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr) MK = MK_FunCall; if (!RS || !shouldWarnAbout(OK, MK) || isInMoveSafeContext(C.getLocationContext())) { // Finalize changes made by the caller. C.addTransition(State); return; } // Don't report it in case if any base region is already reported. // But still generate a sink in case of UB. // And still finalize changes made by the caller. if (isAnyBaseRegionReported(State, Region)) { if (misuseCausesCrash(MK)) { C.generateSink(State, C.getPredecessor()); } else { C.addTransition(State); } return; } ExplodedNode *N = reportBug(Region, RD, C, MK); // If the program has already crashed on this path, don't bother. if (N->isSink()) return; State = State->set<TrackedRegionMap>(Region, RegionState::getReported()); C.addTransition(State, N); }