void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { if (!SymReaper.hasDeadSymbols()) return; const GRState *state = C.getState(); RegionStateTy RS = state->get<RegionState>(); RegionStateTy::Factory &F = state->get_context<RegionState>(); for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { if (SymReaper.isDead(I->first)) { if (I->second.isAllocated()) { if (ExplodedNode *N = C.generateNode()) { if (!BT_Leak) BT_Leak.reset(new BuiltinBug("Memory leak", "Allocated memory never released. Potential memory leak.")); // FIXME: where it is allocated. BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); C.EmitReport(R); } } // Remove the dead symbol from the map. RS = F.remove(RS, I->first); } } C.generateNode(state->set<RegionState>(RS)); }
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { // TODO: Clean up the state. for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { SymbolRef Sym = *I; ProgramStateRef state = C.getState(); const StreamState *SS = state->get<StreamMap>(Sym); // TODO: Shouldn't we have a continue here? if (!SS) return; if (SS->isOpened()) { ExplodedNode *N = C.generateSink(); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); C.emitReport(R); } } } }
void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { ProgramStateRef State = C.getState(); DynamicTypeMapImpl TypeMap = State->get<DynamicTypeMap>(); for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end(); I != E; ++I) { if (!SR.isLiveRegion(I->first)) { State = State->remove<DynamicTypeMap>(I->first); } } if (!SR.hasDeadSymbols()) { C.addTransition(State); return; } MostSpecializedTypeArgsMapTy TyArgMap = State->get<MostSpecializedTypeArgsMap>(); for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(), E = TyArgMap.end(); I != E; ++I) { if (SR.isDead(I->first)) { State = State->remove<MostSpecializedTypeArgsMap>(I->first); } } C.addTransition(State); }
/// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. ProgramStateRef BasicConstraintManager::removeDeadBindings(ProgramStateRef state, SymbolReaper& SymReaper) { ConstEqTy CE = state->get<ConstEq>(); ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>(); for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) { SymbolRef sym = I.getKey(); if (SymReaper.maybeDead(sym)) CE = CEFactory.remove(CE, sym); } state = state->set<ConstEq>(CE); ConstNotEqTy CNE = state->get<ConstNotEq>(); ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>(); for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) { SymbolRef sym = I.getKey(); if (SymReaper.maybeDead(sym)) CNE = CNEFactory.remove(CNE, sym); } return state->set<ConstNotEq>(CNE); }
void IteratorChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { // Cleanup auto State = C.getState(); auto RegionMap = State->get<IteratorRegionMap>(); for (const auto Reg : RegionMap) { if (!SR.isLiveRegion(Reg.first)) { State = State->remove<IteratorRegionMap>(Reg.first); } } auto SymbolMap = State->get<IteratorSymbolMap>(); for (const auto Sym : SymbolMap) { if (!SR.isLive(Sym.first)) { State = State->remove<IteratorSymbolMap>(Sym.first); } } auto ContMap = State->get<ContainerMap>(); for (const auto Cont : ContMap) { if (!SR.isLiveRegion(Cont.first)) { State = State->remove<ContainerMap>(Cont.first); } } auto ComparisonMap = State->get<IteratorComparisonMap>(); for (const auto Comp : ComparisonMap) { if (!SR.isLive(Comp.first)) { State = State->remove<IteratorComparisonMap>(Comp.first); } } }
Environment EnvironmentManager::RemoveDeadBindings(Environment Env, const Stmt *S, SymbolReaper &SymReaper, const GRState *ST, llvm::SmallVectorImpl<const MemRegion*> &DRoots) { CFG &C = *Env.getAnalysisContext().getCFG(); // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(&Env.getAnalysisContext()); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const Stmt *BlkExpr = I.getKey(); // Not a block-level expression? if (!C.isBlkExpr(BlkExpr)) continue; const SVal &X = I.getData(); if (SymReaper.isLive(S, BlkExpr)) { // Copy the binding to the new map. NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa<loc::MemRegionVal>(X)) { const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); DRoots.push_back(R); // Mark the super region of the RX as live. // e.g.: int x; char *y = (char*) &x; if (*y) ... // 'y' => element region. 'x' is its super region. // We only add one level super region for now. // FIXME: maybe multiple level of super regions should be added. if (const SubRegion *SR = dyn_cast<SubRegion>(R)) DRoots.push_back(SR->getSuperRegion()); } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); ST->scanReachableSymbols(X, cb); continue; } // Otherwise the expression is dead with a couple exceptions. // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the // beginning of itself, but we need its UndefinedVal to determine its // SVal. if (X.isUndef() && cast<UndefinedVal>(X).getData()) NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); } return NewEnv; }
// removeDeadBindings: // - Remove subexpression bindings. // - Remove dead block expression bindings. // - Keep live block expression bindings: // - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. Environment EnvironmentManager::removeDeadBindings(Environment Env, SymbolReaper &SymReaper, ProgramStateRef ST) { // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); MarkLiveCallback CB(SymReaper); ScanReachableSymbols RSScaner(ST, CB); llvm::ImmutableMapRef<EnvironmentEntry,SVal> EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), F.getTreeFactory()); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const EnvironmentEntry &BlkExpr = I.getKey(); const SVal &X = I.getData(); if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { // Copy the binding to the new map. EBMapRef = EBMapRef.add(BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>()) SymReaper.markLive(R->getRegion()); // Mark all symbols in the block expr's value live. RSScaner.scan(X); continue; } else { SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); } } NewEnv.ExprBindings = EBMapRef.asImmutableMap(); return NewEnv; }
void MoveChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>(); for (TrackedRegionMapTy::value_type E : TrackedRegions) { const MemRegion *Region = E.first; bool IsRegDead = !SymReaper.isLiveRegion(Region); // Remove the dead regions from the region map. if (IsRegDead) { State = State->remove<TrackedRegionMap>(Region); } } C.addTransition(State); }
static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) { MR = MR->getBaseRegion(); if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) return Reaper.isLive(SR->getSymbol()); if (const VarRegion *VR = dyn_cast<VarRegion>(MR)) return Reaper.isLive(VR); // FIXME: This is a gross over-approximation. What we really need is a way to // tell if anything still refers to this region. Unlike SymbolicRegions, // AllocaRegions don't have associated symbols, though, so we don't actually // have a way to track their liveness. if (isa<AllocaRegion>(MR)) return true; if (isa<CXXThisRegion>(MR)) return true; if (isa<MemSpaceRegion>(MR)) return true; return false; }
/// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. ProgramStateRef RangeConstraintManager::removeDeadBindings(ProgramStateRef state, SymbolReaper& SymReaper) { ConstraintRangeTy CR = state->get<ConstraintRange>(); ConstraintRangeTy::Factory& CRFactory = state->get_context<ConstraintRange>(); for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) { SymbolRef sym = I.getKey(); if (SymReaper.maybeDead(sym)) CR = CRFactory.remove(CR, sym); } return state->set<ConstraintRange>(CR); }
void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); RawPtrMapTy RPM = State->get<RawPtrMap>(); for (const auto Entry : RPM) { if (!SymReaper.isLiveRegion(Entry.first)) { // Due to incomplete destructor support, some dead regions might // remain in the program state map. Clean them up. State = State->remove<RawPtrMap>(Entry.first); } if (const PtrSet *OldSet = State->get<RawPtrMap>(Entry.first)) { PtrSet CleanedUpSet = *OldSet; for (const auto Symbol : Entry.second) { if (!SymReaper.isLive(Symbol)) CleanedUpSet = F.remove(CleanedUpSet, Symbol); } State = CleanedUpSet.isEmpty() ? State->remove<RawPtrMap>(Entry.first) : State->set<RawPtrMap>(Entry.first, CleanedUpSet); } } C.addTransition(State); }
void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { // TODO: Clean up the state. for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { SymbolRef Sym = *I; ProgramStateRef state = C.getState(); const StreamState *SS = state->get<StreamMap>(Sym); if (!SS) continue; if (SS->isOpened()) { ExplodedNode *N = C.generateErrorNode(); if (N) { if (!BT_ResourceLeak) BT_ResourceLeak.reset(new BuiltinBug( this, "Resource Leak", "Opened File never closed. Potential Resource leak.")); C.emitReport(llvm::make_unique<BugReport>( *BT_ResourceLeak, BT_ResourceLeak->getDescription(), N)); } } } }
void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Remove the dead symbols from the collection count map. ContainerCountMapTy Tracked = State->get<ContainerCountMap>(); for (ContainerCountMapTy::iterator I = Tracked.begin(), E = Tracked.end(); I != E; ++I) { SymbolRef Sym = I->first; if (SymReaper.isDead(Sym)) State = State->remove<ContainerCountMap>(Sym); } C.addTransition(State); }
/// Cleaning up the program state. void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { if (!SR.hasDeadSymbols()) return; ProgramStateRef State = C.getState(); NullabilityMapTy Nullabilities = State->get<NullabilityMap>(); for (NullabilityMapTy::iterator I = Nullabilities.begin(), E = Nullabilities.end(); I != E; ++I) { const auto *Region = I->first->getAs<SymbolicRegion>(); assert(Region && "Non-symbolic region is tracked."); if (SR.isDead(Region->getSymbol())) { State = State->remove<NullabilityMap>(I->first); } } // When one of the nonnull arguments are constrained to be null, nullability // preconditions are violated. It is not enough to check this only when we // actually report an error, because at that time interesting symbols might be // reaped. if (checkPreconditionViolation(State, C.getPredecessor(), C)) return; C.addTransition(State); }
void MPIChecker::checkMissingWaits(SymbolReaper &SymReaper, CheckerContext &Ctx) const { if (!SymReaper.hasDeadSymbols()) return; ProgramStateRef State = Ctx.getState(); const auto &Requests = State->get<RequestMap>(); if (Requests.isEmpty()) return; static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait"); ExplodedNode *ErrorNode{nullptr}; auto ReqMap = State->get<RequestMap>(); for (const auto &Req : ReqMap) { if (!SymReaper.isLiveRegion(Req.first)) { if (Req.second.CurrentState == Request::State::Nonblocking) { if (!ErrorNode) { ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag); State = ErrorNode->getState(); } BReporter.reportMissingWait(Req.second, Req.first, ErrorNode, Ctx.getBugReporter()); } State = State->remove<RequestMap>(Req.first); } } // Transition to update the state regarding removed requests. if (!ErrorNode) { Ctx.addTransition(State); } else { Ctx.addTransition(State, ErrorNode); } }
/// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. ProgramStateRef RangeConstraintManager::removeDeadBindings(ProgramStateRef State, SymbolReaper &SymReaper) { bool Changed = false; ConstraintRangeTy CR = State->get<ConstraintRange>(); ConstraintRangeTy::Factory &CRFactory = State->get_context<ConstraintRange>(); for (ConstraintRangeTy::iterator I = CR.begin(), E = CR.end(); I != E; ++I) { SymbolRef Sym = I.getKey(); if (SymReaper.maybeDead(Sym)) { Changed = true; CR = CRFactory.remove(CR, Sym); } } return Changed ? State->set<ConstraintRange>(CR) : State; }
void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); // TODO: Clean LockMap when a mutex region dies. DestroyRetValTy TrackedSymbols = State->get<DestroyRetVal>(); for (DestroyRetValTy::iterator I = TrackedSymbols.begin(), E = TrackedSymbols.end(); I != E; ++I) { const SymbolRef Sym = I->second; const MemRegion *lockR = I->first; bool IsSymDead = SymReaper.isDead(Sym); // Remove the dead symbol from the return value symbols map. if (IsSymDead) State = resolvePossiblyDestroyedMutex(State, lockR, &Sym); } C.addTransition(State); }
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { ProgramStateRef State = C.getState(); AllocatedDataTy ASet = State->get<AllocatedData>(); if (ASet.isEmpty()) return; bool Changed = false; AllocationPairVec Errors; for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { if (SR.isLive(I->first)) continue; Changed = true; State = State->remove<AllocatedData>(I->first); // If the allocated symbol is null or if the allocation call might have // returned an error, do not report. ConstraintManager &CMgr = State->getConstraintManager(); ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey()); if (AllocFailed.isConstrainedTrue() || definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) continue; Errors.push_back(std::make_pair(I->first, &I->second)); } if (!Changed) { // Generate the new, cleaned up state. C.addTransition(State); return; } static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : DeadSymbolsLeak"); ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); // Generate the error reports. for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); } // Generate the new, cleaned up state. C.addTransition(State, N); }
// Use not for leaks but useful to remove our stored symbols void iOSAppSecInsecureKeyChainStorageChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef pProgState = C.getState() ; StreamMapTy TrackedStreams = pProgState ->get<StreamMap>() ; for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I != E; ++I) { SymbolRef pSymbol = I ->first ; // Remove the dead symbol from the streams map. if ( SymReaper.isDead( pSymbol ) ) { pProgState = pProgState -> remove<StreamMap>( pSymbol ) ; } } C.addTransition( pProgState ) ; }
void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I != E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym); // Collect leaked symbols. if (isLeaked(Sym, I->second, IsSymDead, State)) LeakedStreams.push_back(Sym); // Remove the dead symbol from the streams map. if (IsSymDead) State = State->remove<StreamMap>(Sym); } ExplodedNode *N = C.addTransition(State); reportLeaks(LeakedStreams, C, N); }
ProgramStateRef ProgramStateManager::removeDeadBindings(ProgramStateRef state, const StackFrameContext *LCtx, SymbolReaper& SymReaper) { // This code essentially performs a "mark-and-sweep" of the VariableBindings. // The roots are any Block-level exprs and Decls that our liveness algorithm // tells us are live. We then see what Decls they may reference, and keep // those around. This code more than likely can be made faster, and the // frequency of which this method is called should be experimented with // for optimum performance. ProgramState NewState = *state; NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state); // Clean up the store. StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx, SymReaper); NewState.setStore(newStore); SymReaper.setReapedStore(newStore); return getPersistentState(NewState); }
void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { const ProgramState *State = C.getState(); AllocatedSetTy ASet = State->get<AllocatedData>(); if (ASet.isEmpty()) return; bool Changed = false; AllocationPairVec Errors; for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { if (SR.isLive(I->first)) continue; Changed = true; State = State->remove<AllocatedData>(I->first); // If the allocated symbol is null or if the allocation call might have // returned an error, do not report. if (State->getSymVal(I->first) || definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) continue; Errors.push_back(std::make_pair(I->first, &I->second)); } if (!Changed) return; // Generate the new, cleaned up state. ExplodedNode *N = C.addTransition(State); if (!N) return; // Generate the error reports. for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N)); } }
// removeDeadBindings: // - Remove subexpression bindings. // - Remove dead block expression bindings. // - Keep live block expression bindings: // - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. Environment EnvironmentManager::removeDeadBindings(Environment Env, SymbolReaper &SymReaper, const ProgramState *ST) { // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations; MarkLiveCallback CB(SymReaper); ScanReachableSymbols RSScaner(ST, CB); llvm::ImmutableMapRef<EnvironmentEntry,SVal> EBMapRef(NewEnv.ExprBindings.getRootWithoutRetain(), F.getTreeFactory()); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const EnvironmentEntry &BlkExpr = I.getKey(); // For recorded locations (used when evaluating loads and stores), we // consider them live only when their associated normal expression is // also live. // NOTE: This assumes that loads/stores that evaluated to UnknownVal // still have an entry in the map. if (IsLocation(BlkExpr)) { deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); continue; } const SVal &X = I.getData(); if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) { // Copy the binding to the new map. EBMapRef = EBMapRef.add(BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa<loc::MemRegionVal>(X)) { const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion(); SymReaper.markLive(R); } // Mark all symbols in the block expr's value live. RSScaner.scan(X); continue; } // Otherwise the expression is dead with a couple exceptions. // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the // beginning of itself, but we need its UndefinedVal to determine its // SVal. if (X.isUndef() && cast<UndefinedVal>(X).getData()) EBMapRef = EBMapRef.add(BlkExpr, X); } // Go through he deferred locations and add them to the new environment if // the correspond Stmt* is in the map as well. for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { const EnvironmentEntry &En = I->first; const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1); if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext()))) EBMapRef = EBMapRef.add(En, I->second); } NewEnv.ExprBindings = EBMapRef.asImmutableMap(); return NewEnv; }
Environment EnvironmentManager::RemoveDeadBindings(Environment Env, SymbolReaper &SymReaper, const GRState *ST, llvm::SmallVectorImpl<const MemRegion*> &DRoots) { CFG &C = *SymReaper.getLocationContext()->getCFG(); // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const Stmt *BlkExpr = I.getKey(); const SVal &X = I.getData(); // Block-level expressions in callers are assumed always live. if (isBlockExprInCallers(BlkExpr, SymReaper.getLocationContext())) { NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); if (isa<loc::MemRegionVal>(X)) { const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); DRoots.push_back(R); } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); ST->scanReachableSymbols(X, cb); continue; } // Not a block-level expression? if (!C.isBlkExpr(BlkExpr)) continue; if (SymReaper.isLive(BlkExpr)) { // Copy the binding to the new map. NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa<loc::MemRegionVal>(X)) { const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); DRoots.push_back(R); } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); ST->scanReachableSymbols(X, cb); continue; } // Otherwise the expression is dead with a couple exceptions. // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the // beginning of itself, but we need its UndefinedVal to determine its // SVal. if (X.isUndef() && cast<UndefinedVal>(X).getData()) NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); } return NewEnv; }
Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { BindingsTy B = GetBindings(store); typedef SVal::symbol_iterator symbol_iterator; // Iterate over the variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { if (const VarRegion *VR = dyn_cast<VarRegion>(I.getKey())) { if (SymReaper.isLive(Loc, VR)) RegionRoots.push_back(VR); else continue; } else if (isa<ObjCIvarRegion>(I.getKey())) { RegionRoots.push_back(I.getKey()); } else continue; // Mark the bindings in the data as live. SVal X = I.getData(); for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) SymReaper.markLive(*SI); } // Scan for live variables and live symbols. llvm::SmallPtrSet<const MemRegion*, 10> Marked; while (!RegionRoots.empty()) { const MemRegion* MR = RegionRoots.back(); RegionRoots.pop_back(); while (MR) { if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(MR)) { SymReaper.markLive(SymR->getSymbol()); break; } else if (isa<VarRegion>(MR) || isa<ObjCIvarRegion>(MR)) { if (Marked.count(MR)) break; Marked.insert(MR); SVal X = Retrieve(store, loc::MemRegionVal(MR)); // FIXME: We need to handle symbols nested in region definitions. for (symbol_iterator SI=X.symbol_begin(),SE=X.symbol_end(); SI!=SE; ++SI) SymReaper.markLive(*SI); if (!isa<loc::MemRegionVal>(X)) break; const loc::MemRegionVal& LVD = cast<loc::MemRegionVal>(X); RegionRoots.push_back(LVD.getRegion()); break; } else if (const SubRegion* R = dyn_cast<SubRegion>(MR)) MR = R->getSuperRegion(); else break; } } // Remove dead variable bindings. for (BindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) { const MemRegion* R = I.getKey(); if (!Marked.count(R)) { store = Remove(store, ValMgr.makeLoc(R)); SVal X = I.getData(); for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI) SymReaper.maybeDead(*SI); } } return store; }
// removeDeadBindings: // - Remove subexpression bindings. // - Remove dead block expression bindings. // - Keep live block expression bindings: // - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. Environment EnvironmentManager::removeDeadBindings(Environment Env, SymbolReaper &SymReaper, const GRState *ST, llvm::SmallVectorImpl<const MemRegion*> &DRoots) { CFG &C = *SymReaper.getLocationContext()->getCFG(); // We construct a new Environment object entirely, as this is cheaper than // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); llvm::SmallVector<std::pair<const Stmt*, SVal>, 10> deferredLocations; // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const Stmt *BlkExpr = I.getKey(); // For recorded locations (used when evaluating loads and stores), we // consider them live only when their associated normal expression is // also live. // NOTE: This assumes that loads/stores that evaluated to UnknownVal // still have an entry in the map. if (IsLocation(BlkExpr)) { deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); continue; } const SVal &X = I.getData(); // Block-level expressions in callers are assumed always live. if (isBlockExprInCallers(BlkExpr, SymReaper.getLocationContext())) { NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); if (isa<loc::MemRegionVal>(X)) { const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); DRoots.push_back(R); } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); ST->scanReachableSymbols(X, cb); continue; } // Not a block-level expression? if (!C.isBlkExpr(BlkExpr)) continue; if (SymReaper.isLive(BlkExpr)) { // Copy the binding to the new map. NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); // If the block expr's value is a memory region, then mark that region. if (isa<loc::MemRegionVal>(X)) { const MemRegion* R = cast<loc::MemRegionVal>(X).getRegion(); DRoots.push_back(R); } // Mark all symbols in the block expr's value live. MarkLiveCallback cb(SymReaper); ST->scanReachableSymbols(X, cb); continue; } // Otherwise the expression is dead with a couple exceptions. // Do not misclean LogicalExpr or ConditionalOperator. It is dead at the // beginning of itself, but we need its UndefinedVal to determine its // SVal. if (X.isUndef() && cast<UndefinedVal>(X).getData()) NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, BlkExpr, X); } // Go through he deferred locations and add them to the new environment if // the correspond Stmt* is in the map as well. for (llvm::SmallVectorImpl<std::pair<const Stmt*, SVal> >::iterator I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1); if (NewEnv.ExprBindings.lookup(S)) NewEnv.ExprBindings = F.add(NewEnv.ExprBindings, I->first, I->second); } return NewEnv; }