Index: clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -529,12 +529,24 @@ C.addTransition(state); } +/// A value escapes in these possible cases: +/// +/// - binding to something that is not a memory region. +/// - binding to a memregion that does not have stack storage +/// - binding to a variable that has a destructor attached using CleanupAttr +/// +/// We do not currently model what happens when a symbol is +/// assigned to a struct field, so be conservative here and let the symbol go. +/// FIXME: This could definitely be improved upon. static bool shouldEscapeRegion(const MemRegion *R) { + const auto *VR = dyn_cast(R); + if (!R->hasStackStorage() || !VR) + return true; - // We do not currently model what happens when a symbol is - // assigned to a struct field, so be conservative here and let the symbol - // go. TODO: This could definitely be improved upon. - return !R->hasStackStorage() || !isa(R); + const VarDecl *VD = VR->getDecl(); + if (!VD->hasAttr()) + return false; // CleanupAttr attaches destructors, which cause escaping. + return true; } static SmallVector @@ -1145,39 +1157,19 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const { - // Are we storing to something that causes the value to "escape"? - bool escapes = true; - - // A value escapes in three possible cases (this may change): - // - // (1) we are binding to something that is not a memory region. - // (2) we are binding to a memregion that does not have stack storage ProgramStateRef state = C.getState(); - if (auto regionLoc = loc.getAs()) { - escapes = shouldEscapeRegion(regionLoc->getRegion()); - } - - // If we are storing the value into an auto function scope variable annotated - // with (__attribute__((cleanup))), stop tracking the value to avoid leak - // false positives. - if (const auto *LVR = dyn_cast_or_null(loc.getAsRegion())) { - const VarDecl *VD = LVR->getDecl(); - if (VD->hasAttr()) { - escapes = true; - } - } + auto regionLoc = loc.getAs(); + if (!regionLoc) + return; - // If our store can represent the binding and we aren't storing to something - // that doesn't have local storage then just return and have the simulation - // state continue as is. - if (!escapes) - return; + if (shouldEscapeRegion(regionLoc->getRegion())) { - // Otherwise, find all symbols referenced by 'val' that we are tracking - // and stop tracking them. - state = state->scanReachableSymbols(val).getState(); - C.addTransition(state); + // Find all symbols referenced by 'val' that we are tracking + // and stop tracking them. + state = state->scanReachableSymbols(val).getState(); + C.addTransition(state); + } } ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, @@ -1196,14 +1188,14 @@ bool changed = false; RefBindingsTy::Factory &RefBFactory = state->get_context(); + ConstraintManager &CMgr = state->getConstraintManager(); - for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { + for (auto &I : B) { // Check if the symbol is null stop tracking the symbol. - ConstraintManager &CMgr = state->getConstraintManager(); - ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); + ConditionTruthVal AllocFailed = CMgr.isNull(state, I.first); if (AllocFailed.isConstrainedTrue()) { changed = true; - B = RefBFactory.remove(B, I.getKey()); + B = RefBFactory.remove(B, I.first); } } @@ -1424,9 +1416,9 @@ return; } - for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { + for (auto &I : B) { state = handleAutoreleaseCounts(state, Pred, /*Tag=*/nullptr, Ctx, - I->first, I->second); + I.first, I.second); if (!state) return; } @@ -1441,8 +1433,8 @@ B = state->get(); SmallVector Leaked; - for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) - state = handleSymbolDeath(state, I->first, I->second, Leaked); + for (auto &I : B) + state = handleSymbolDeath(state, I.first, I.second, Leaked); processLeaks(state, Leaked, Ctx, Pred); } @@ -1503,9 +1495,9 @@ Out << Sep << NL; - for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { - Out << I->first << " : "; - I->second.print(Out); + for (auto &I : B) { + Out << I.first << " : "; + I.second.print(Out); Out << NL; } }