MyDomain GetReturnState <MyDomain>(IFixpointInfo <APC, MyDomain> fixpoint, IAbstractAnalysis <Local, Parameter, Method, Field, Property, Type, Expression, Attribute, Assembly, MyDomain, Variable> analysis, int state, out bool isBottom, MyDomain defaultValue) { MyDomain returnState = defaultValue; var fakeEdge = new Pair <APC, APC>(driver.CFG.NormalExit, driver.CFG.Entry); if (stateInfo.StateReturnPoints == null || !stateInfo.StateReturnPoints.ContainsKey(state)) { isBottom = true; } else { bool first = true; isBottom = true; foreach (APC returnPoint in stateInfo.StateReturnPoints[state]) { MyDomain tmp; if (fixpoint.PostState(returnPoint, out tmp) && !analysis.IsBottom(returnPoint, tmp)) { isBottom = false; var edge = new Pair <APC, APC>(returnPoint, driver.CFG.Entry.Post()); IFunctionalMap <Variable, FList <Variable> > mapping = GetFieldMapping(driver, returnPoint, driver.CFG.Entry.Post()); MyDomain newState = analysis.EdgeConversion(fakeEdge.One, fakeEdge.Two, true, mapping, tmp); bool ignore; if (first) { returnState = newState; first = false; } else { returnState = analysis.Join(edge, newState, returnState, out ignore, false); } } } } return(returnState); }
/// <summary> /// Given an underlying analysis and generator for a bottom value, this method computes a mapping between a state of /// the iterator and fixpoint information computed by the underlying analysis for the slice that corresponds to that /// state. /// /// The analysis runs the underlying analyzer on state 0, the initial state, first. The state from the return point /// of this state will be the current value of the invariant candidate. /// Then for every continuing state (the state from which a new item is generated for the ienumerable result), we map /// the current invariant candidate and map it to the entry of the method, and run the underlying analysis for that /// state. Running the underlying analysis for a particular state requires a set of program points, which are the entry /// points of other slices. The underlying analysis will mark those program points as unreachable. The exit abstract /// state will become the current invariant candidate. This process finishes when a fixedpoint is reached. /// </summary> /// <typeparam name="MyDomain">The domain of the underlying analysis.</typeparam> /// <param name="analysis">The underlying analysis.</param> /// <param name="bv">A delegate that generates a bottom value for MyDomain.</param> /// <returns></returns> public IFactQuery <BoxedExpression, Variable> Analyze <MyDomain>( IAbstractAnalysis <Local, Parameter, Method, Field, Property, Type, Expression, Attribute, Assembly, MyDomain, Variable> analysis ) { // Fix point computation: fixpoint of the iterator analysis is a mapping: answers. if (stateInfo == null) { return(null); } bool fixedpointReached = false; MyDomain d = default(MyDomain), oldd = default(MyDomain); var answers = (IFunctionalMap <int, IFixpointInfo <APC, MyDomain> >)FunctionalMap <int, IFixpointInfo <APC, MyDomain> > .Empty; Dictionary <int, MyDomain> invariantCandidate = new Dictionary <int, MyDomain>(); int pass = 0; while (!fixedpointReached) { fixedpointReached = true; // Going through every state of the state machine, if the final states changes at least once // then fixpoint is not reached. foreach (int state in stateInfo.OrderedVisibleStates) { // The initial state is only analyzed once. if (state < 0) { continue; } if (state == 0 && pass > 0) { continue; } // Initial value for one pass, either TOP, if we analyze it for the first time // or the invariantCandidate. if (!invariantCandidate.ContainsKey(state)) { invariantCandidate[state] = d = analysis.GetTopValue(); } else { d = analysis.MutableVersion(invariantCandidate[state]); } // Call the underlying analysis for one pass Set <APC> cutOffPCs = GetStateEntriesOtherThan(stateInfo, state); var fixpoint = driver.CreateForwardForIterator(analysis, () => analysis.GetBottomValue(), cutOffPCs)(d); // Fill the result table with the most recent fixpoint information. answers = answers.Add(state, fixpoint); // Getting the state from the return point of the most recent pass, map it // to the entry point, and join it with the current invariant candidate bool changed = false; var fakeEdge = new Pair <APC, APC>(driver.CFG.NormalExit, driver.CFG.Entry); foreach (int possibleNextState in stateInfo.OrderedVisibleStates) { bool isBottom; MyDomain newInvariantState = GetReturnState(fixpoint, analysis, possibleNextState, out isBottom, analysis.GetTopValue()); if (invariantCandidate.ContainsKey(possibleNextState)) { oldd = invariantCandidate[possibleNextState]; // TODO: use a more sophisticated widenning strategy. bool toWiden = (pass > 2) ? true : false; if (isBottom) { d = oldd; } else { d = analysis.Join(fakeEdge, newInvariantState, oldd, out changed, toWiden); } if (changed) { invariantCandidate[possibleNextState] = d; } } else { if (!isBottom) { changed = true; invariantCandidate[possibleNextState] = newInvariantState; } } if (changed) { fixedpointReached = false; } } } pass++; } var result = new DisjunctionFactQuery <Variable>(this.driver.ValueLayer.Decoder.IsUnreachable); answers.Visit((statekey, fixpoint) => { result.Add(analysis.FactQuery(fixpoint)); return(VisitStatus.ContinueVisit); }); return(result); }