internal Explorer( ExplorationContext explorationContext, IContextFactory smtContextFactory, StartingNodeInfo startingNode, IEntryPointRecognizer finalNodeRecognizer, ISymbolicHeapFactory heapFactory, Action <ExplorationResult> resultCallback) { // TODO: Solve this marginal case directly in the ExplorationContext Contract.Requires(!finalNodeRecognizer.IsFinalNode(startingNode.Node)); this.context = explorationContext; this.startingNode = startingNode; this.finalNodeRecognizer = finalNodeRecognizer; this.heapFactory = heapFactory; this.resultCallback = resultCallback; this.smtContextHandler = new SmtContextHandler(smtContextFactory); var rootPath = new Path( ImmutableArray <Path> .Empty, 0, this.startingNode.Node, ImmutableArray <FlowEdge> .Empty); var rootState = new ExplorationState( rootPath, CallSiteStack.Empty, this.smtContextHandler.CreateEmptySolver(rootPath, this.startingNode, heapFactory)); this.AddState(rootState); }
private static CallSiteStack GetNewCallSiteStack(ExplorationState currentState, FlowEdge edge) { CallSiteStack callSiteStack; if (edge.From is ReturnFlowNode) { Contract.Assert(edge is OuterFlowEdge); Contract.Assert(((OuterFlowEdge)edge).Kind == OuterFlowEdgeKind.Return); callSiteStack = currentState.CallSiteStack.Push((CallFlowNode)edge.To); } else if (edge.To is EnterFlowNode) { Contract.Assert(edge is OuterFlowEdge); Contract.Assert(((OuterFlowEdge)edge).Kind == OuterFlowEdgeKind.MethodCall); callSiteStack = currentState.CallSiteStack.IsEmpty ? currentState.CallSiteStack : currentState.CallSiteStack.Pop(); } else { callSiteStack = currentState.CallSiteStack; } return(callSiteStack); }
public void Merge(ExplorationState state, SmtSolverHandler solverHandler) { Contract.Requires(state != null); Contract.Requires(solverHandler != null); Contract.Requires(state.Path.Node == this.Path.Node); Contract.Requires(state.CallSiteStack.Equals(this.CallSiteStack)); this.Path = new Path( this.Path.Preceeding.AddRange(state.Path.Preceeding), Math.Max(this.Path.Depth, state.Path.Depth), this.Path.Node, this.Path.LeadingEdges.AddRange(state.Path.LeadingEdges)); this.SolverHandler = solverHandler; }
// TODO: Divide into submethods to make more readable internal async Task <bool> ExploreAsync(CancellationToken cancelToken) { for ( var currentState = this.ExplorationHeuristic.PickNextState(); currentState != null; currentState = this.ExplorationHeuristic.PickNextState()) { // TODO: Consider reusing the state instead of discarding this.RemoveState(currentState); IReadOnlyList <FlowEdge> edges; var currentNode = currentState.Path.Node; var graphProvider = this.context.FlowGraphProvider; if (currentNode is EnterFlowNode) { if (currentState.CallSiteStack == CallSiteStack.Empty) { edges = await graphProvider.GetCallEdgesToAsync((EnterFlowNode)currentNode); } else { // The execution is constrained by the call site on the stack var edge = graphProvider.GetCallEdge( currentState.CallSiteStack.CallSite, (EnterFlowNode)currentNode); edges = edge.ToSingular(); } } else if ((currentNode as CallFlowNode)?.Location.CanBeExplored == true && !(currentState.Path.Preceeding.FirstOrDefault()?.Node is EnterFlowNode)) { // If we can model the call and we haven't returned from that method yet edges = await graphProvider.GetReturnEdgesToAsync((CallFlowNode)currentNode); } else { edges = currentNode.IngoingEdges; } var toSolve = new List <ExplorationState>(); int i = 0; foreach (bool doBranch in this.ExplorationHeuristic.DoBranch(currentState, edges)) { var edge = edges[i]; if (doBranch && this.IsEdgeAllowed(edge)) { var branchedPath = new Path( ImmutableArray.Create(currentState.Path), currentState.Path.Depth + 1, edge.From, ImmutableArray.Create(edge)); CallSiteStack callSiteStack = GetNewCallSiteStack(currentState, edge); var branchedState = new ExplorationState( branchedPath, callSiteStack, currentState.SolverHandler); bool wasMerged = false; foreach (var mergeCandidate in this.statesOnLocations[branchedState.Path.Node].ToArray()) { if (this.MergingHeuristic.DoMerge(branchedState, mergeCandidate)) { SmtSolverHandler solverHandler; if (branchedState.SolverHandler != mergeCandidate.SolverHandler) { solverHandler = this.SmtHeuristic.SelectMergedSolverHandler( branchedState, mergeCandidate); } else { solverHandler = branchedState.SolverHandler; } mergeCandidate.Merge(branchedState, solverHandler); wasMerged = true; break; } } if (!wasMerged) { this.AddState(branchedState); } if (this.IsFinalState(branchedState) || this.SmtHeuristic.DoSolve(branchedState)) { toSolve.Add(branchedState); } } else { this.IsUnderapproximated = true; } i++; } if (toSolve.Count > 0) { int j = 0; foreach (bool doReuse in this.SmtHeuristic.DoReuse(currentState.SolverHandler, toSolve)) { if (!doReuse) { toSolve[j].SolverHandler = currentState.SolverHandler.Clone(); } j++; } foreach (var branchedState in toSolve) { var resultKind = branchedState.SolverHandler.Solve(branchedState.Path); SolverCallCount++; if (resultKind != ExplorationResultKind.Reachable || this.IsFinalState(branchedState)) { this.RemoveState(branchedState); var result = branchedState.SolverHandler.LastResult; this.resultCallback(result); } } } // Check the cancellation before picking next node if (cancelToken.IsCancellationRequested) { // It is an expected behaviour with well defined result, there is no need to throw an exception break; } } // If there are any exploration states left, the results are not exhaustive return(this.States.Count == 0); }
private void RemoveState(ExplorationState state) { this.States.Remove(state); this.statesOnLocations[state.Path.Node].Remove(state); }
private void AddState(ExplorationState state) { this.States.Add(state); this.statesOnLocations[state.Path.Node].Add(state); }
private bool IsFinalState(ExplorationState branchedState) { return(branchedState.CallSiteStack == CallSiteStack.Empty && this.finalNodeRecognizer.IsFinalNode(branchedState.Path.Node)); }