/// <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); }
/// <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 FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > Analyze <MyDomain>( IMoveNextOnePassAnalysis <Local, Parameter, Method, Field, Property, Type, Expression, Attribute, Assembly, MyDomain, Variable> analysis, StateGenerator <MyDomain> bv) { // Use a pre-analysis to collect information regarding the state machine. MoveNextStateAnalyzer preAnalyzer = new MoveNextStateAnalyzer(); StateMachineInformation <Local> stateInfo = preAnalyzer.AnalyzeMoveNext("MoveNext", driver); // If we are not able if (stateInfo.OrderedVisibleStates == null || stateInfo.OrderedVisibleStates.Count() == 0) { throw new ArgumentException("Argument error with MoveNext method: Cannot analyze the state machine."); } // Fix point computation: fixpoint of the iterator analysis is a mapping: answers. bool fixedpointReached = false; MyDomain d = default(MyDomain), oldd = default(MyDomain); FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > answers = FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > .Empty; MyDomain invariantCandidate = default(MyDomain); Converter <Variable, int> key = driver.KeyNumber; 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 == null || invariantCandidate.Equals(default(MyDomain))) { d = analysis.GetInitialValue(key); } else { d = analysis.MutableVersion(invariantCandidate); } // Call the underlying analysis for one pass Set <APC> cutOffPCs = GetStateEntriesOtherThan(stateInfo, state); driver.CreateForwardForIterator(analysis, bv, cutOffPCs)(d); // 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 IFunctionalMap <Variable, FList <Variable> > mapping = GetFieldMapping(driver); var fakeEdge = new Pair <APC, APC>(driver.CFG.NormalExit, driver.CFG.Entry); MyDomain returnState = analysis.ReturnState; MyDomain newState = analysis.ParallelAssign(fakeEdge, mapping, returnState); bool changed = false; if (invariantCandidate != null && !invariantCandidate.Equals(default(MyDomain))) { oldd = invariantCandidate; // TODO: use a more sophisticated widenning strategy. bool toWiden = (pass > 2) ? true : false; d = analysis.Join(fakeEdge, newState, oldd, out changed, toWiden); if (changed) { invariantCandidate = d; } } else { changed = true; invariantCandidate = newState; } if (changed) { fixedpointReached = false; } // Fill the result table with the most recent fixpoint information. answers = (FunctionalMap <int, IMethodAnalysisFixPoint <Variable> >)answers.Add(state, analysis.ExtractResult()); analysis = analysis.Duplicate(); } pass++; } return(answers); }