private Collection<Edge> getRelevantChildrenOfState( ARGState currentElement, Stack<FunctionBody> functionStack, Set<ARGState> elementsOnPath) { // find the next elements to add to the waitlist List<ARGState> relevantChildrenOfElement = from(currentElement.getChildren()).filter(in(elementsOnPath)).toList(); relevantChildrenOfElement = chooseIfArbitrary(currentElement, relevantChildrenOfElement); // if there is only one child on the path if (relevantChildrenOfElement.size() == 1) { // get the next ARG state, create a new edge using the same stack and add it to the waitlist ARGState elem = Iterables.getOnlyElement(relevantChildrenOfElement); CFAEdge e = currentElement.getEdgeToChild(elem); Edge newEdge = new Edge(elem, currentElement, e, functionStack); return Collections.singleton(newEdge); } else if (relevantChildrenOfElement.size() > 1) { // if there are more than one relevant child, then this is a condition // we need to update the stack assert relevantChildrenOfElement.size() == 2; Collection<Edge> result = new ArrayList<>(2); int ind = 0; for (ARGState elem : relevantChildrenOfElement) { Stack<FunctionBody> newStack = cloneStack(functionStack); CFAEdge e = currentElement.getEdgeToChild(elem); FunctionBody currentFunction = newStack.peek(); assert e instanceof CAssumeEdge; CAssumeEdge assumeEdge = (CAssumeEdge) e; boolean truthAssumption = assumeEdge.getTruthAssumption(); String cond = ""; if (ind == 0) { cond = "if "; } else if (ind == 1) { cond = "else if "; } else { throw new AssertionError(); } ind++; if (truthAssumption) { cond += "(" + assumeEdge.getExpression().toASTString() + ")"; } else { cond += "(!(" + assumeEdge.getExpression().toASTString() + "))"; } // create a new block starting with this condition currentFunction.enterBlock(currentElement.getStateId(), assumeEdge, cond); Edge newEdge = new Edge(elem, currentElement, e, newStack); result.add(newEdge); } return result; } return Collections.emptyList(); }
@Override public ARGPath getNextPathForInterpolation() { ARGState current = sources.remove(0); assert current.isTarget() : "current element is not a target"; ARGPathBuilder errorPathBuilder = ARGPath.reverseBuilder(); errorPathBuilder.add( current, FluentIterable.from(AbstractStates.getOutgoingEdges(current)).first().orNull()); while (predecessorRelation.get(current) != null) { ARGState parent = predecessorRelation.get(current); if (stateHasFalseInterpolant(parent)) { logger.log( Level.FINEST, "interpolant on path, namely for state ", parent.getStateId(), " is already false, so return empty path"); return EMPTY_PATH; } if (predecessorRelation.get(parent) != null) { errorPathBuilder.add(parent, parent.getEdgeToChild(current)); } current = parent; } return errorPathBuilder.build(current); }
@Override public ARGPath getNextPathForInterpolation() { ARGPathBuilder errorPathBuilder = ARGPath.builder(); ARGState current = sources.pop(); if (!isValidInterpolationRoot(predecessorRelation.get(current))) { logger.log( Level.FINEST, "interpolant of predecessor of ", current.getStateId(), " is already false, so return empty path"); return EMPTY_PATH; } // if the current state is not the root, it is a child of a branch , however, the path should // not start with the // child, but with the branching node (children are stored on the stack because this needs // less book-keeping) if (current != root) { errorPathBuilder.add( predecessorRelation.get(current), predecessorRelation.get(current).getEdgeToChild(current)); } while (successorRelation.get(current).iterator().hasNext()) { Iterator<ARGState> children = successorRelation.get(current).iterator(); ARGState child = children.next(); errorPathBuilder.add(current, current.getEdgeToChild(child)); // push all other children of the current state, if any, onto the stack for later // interpolations int size = 1; while (children.hasNext()) { size++; ARGState sibling = children.next(); logger.log( Level.FINEST, "\tpush new root ", sibling.getStateId(), " onto stack for parent ", predecessorRelation.get(sibling).getStateId()); sources.push(sibling); } assert (size <= 2); current = child; } return errorPathBuilder.build(current); }
@Override public boolean apply(ARGState pChild) { return pChild != null && predecessor.getEdgeToChild(pChild) == edge; }
private List<BooleanFormula> computeBlockFormulas(final ARGState pRoot) throws CPATransferException, InterruptedException { final Map<ARGState, ARGState> callStacks = new HashMap<>(); // contains states and their next higher callstate final Map<ARGState, PathFormula> finishedFormulas = new HashMap<>(); final List<BooleanFormula> abstractionFormulas = new ArrayList<>(); final Deque<ARGState> waitlist = new ArrayDeque<>(); // initialize assert pRoot.getParents().isEmpty() : "rootState must be the first state of the program"; callStacks.put(pRoot, null); // main-start has no callstack finishedFormulas.put(pRoot, pfmgr.makeEmptyPathFormula()); waitlist.addAll(pRoot.getChildren()); // iterate over all elements in the ARG with BFS while (!waitlist.isEmpty()) { final ARGState currentState = waitlist.pollFirst(); if (finishedFormulas.containsKey(currentState)) { continue; // already handled } if (!finishedFormulas.keySet().containsAll(currentState.getParents())) { // parent not handled yet, re-queue current element and wait for all parents waitlist.addLast(currentState); continue; } // collect formulas for current location final List<PathFormula> currentFormulas = new ArrayList<>(currentState.getParents().size()); final List<ARGState> currentStacks = new ArrayList<>(currentState.getParents().size()); for (ARGState parentElement : currentState.getParents()) { PathFormula parentFormula = finishedFormulas.get(parentElement); final CFAEdge edge = parentElement.getEdgeToChild(currentState); assert edge != null : "ARG is invalid: parent has no edge to child"; final ARGState prevCallState; // we enter a function, so lets add the previous state to the stack if (edge.getEdgeType() == CFAEdgeType.FunctionCallEdge) { prevCallState = parentElement; } else if (edge.getEdgeType() == CFAEdgeType.FunctionReturnEdge) { // we leave a function, so rebuild return-state before assigning the return-value. // rebuild states with info from previous state assert callStacks.containsKey(parentElement); final ARGState callState = callStacks.get(parentElement); assert extractLocation(callState).getLeavingSummaryEdge().getSuccessor() == extractLocation(currentState) : "callstack does not match entry of current function-exit."; assert callState != null || currentState.getChildren().isEmpty() : "returning from empty callstack is only possible at program-exit"; prevCallState = callStacks.get(callState); parentFormula = rebuildStateAfterFunctionCall( parentFormula, finishedFormulas.get(callState), (FunctionExitNode) extractLocation(parentElement)); } else { assert callStacks.containsKey(parentElement); // check for null is not enough prevCallState = callStacks.get(parentElement); } final PathFormula currentFormula = pfmgr.makeAnd(parentFormula, edge); currentFormulas.add(currentFormula); currentStacks.add(prevCallState); } assert currentFormulas.size() >= 1 : "each state except root must have parents"; assert currentStacks.size() == currentFormulas.size() : "number of callstacks must match predecessors"; // merging after functioncall with different callstates is ugly. // this is also guaranteed by the abstraction-locations at function-entries // (--> no merge of states with different latest abstractions). assert Sets.newHashSet(currentStacks).size() <= 1 : "function with multiple entry-states not supported"; callStacks.put(currentState, currentStacks.get(0)); PathFormula currentFormula; final PredicateAbstractState predicateElement = extractStateByType(currentState, PredicateAbstractState.class); if (predicateElement.isAbstractionState()) { // abstraction element is the start of a new part of the ARG assert waitlist.isEmpty() : "todo should be empty, because of the special ARG structure"; assert currentState.getParents().size() == 1 : "there should be only one parent, because of the special ARG structure"; // finishedFormulas.clear(); // free some memory // TODO disabled, we need to keep callStates for later usage // start new block with empty formula currentFormula = getOnlyElement(currentFormulas); abstractionFormulas.add(currentFormula.getFormula()); currentFormula = pfmgr.makeEmptyPathFormula(currentFormula); } else { // merge the formulas Iterator<PathFormula> it = currentFormulas.iterator(); currentFormula = it.next(); while (it.hasNext()) { currentFormula = pfmgr.makeOr(currentFormula, it.next()); } } assert !finishedFormulas.containsKey(currentState) : "a state should only be finished once"; finishedFormulas.put(currentState, currentFormula); waitlist.addAll(currentState.getChildren()); } return abstractionFormulas; }