private List<ARGState> chooseIfArbitrary( ARGState parent, List<ARGState> pRelevantChildrenOfElement) { if (pRelevantChildrenOfElement.size() <= 1) { return pRelevantChildrenOfElement; } List<ARGState> result = new ArrayList<>(2); for (ARGState candidate : pRelevantChildrenOfElement) { boolean valid = true; if (!result.isEmpty()) { Set<ARGState> candidateParents = ImmutableSet.copyOf(candidate.getParents()); Set<ARGState> candidateChildren = ImmutableSet.copyOf(candidate.getChildren()); for (ARGState chosen : result) { if (parent.getEdgesToChild(chosen).equals(parent.getEdgesToChild(candidate))) { Set<ARGState> chosenParents = ImmutableSet.copyOf(chosen.getParents()); Set<ARGState> chosenChildren = ImmutableSet.copyOf(chosen.getChildren()); if (candidateParents.equals(chosenParents) && candidateChildren.equals(chosenChildren)) { valid = false; break; } } } } if (valid) { result.add(candidate); } } return result; }
private boolean checkAndAddSuccessors( final ARGState pPredecessor, final ReachedSet pReachedSet, final Precision pPrecision, @Nullable List<ARGState> pIncompleteStates) throws InterruptedException, CPAException { stats.getTransferTimer().start(); Collection<ARGState> successors = pPredecessor.getChildren(); logger.log(Level.FINER, "Checking abstract successors", successors); if (!checkSuccessors(pPredecessor, successors, pPrecision)) { stats.getTransferTimer().stop(); if (pIncompleteStates != null) { pIncompleteStates.add(pPredecessor); logger.log( Level.FINER, "State", pPredecessor, "is explored incompletely, will be recorded in the assumption automaton."); return true; } logger.log(Level.WARNING, "State", pPredecessor, "has other successors than", successors); return false; } stats.getTransferTimer().stop(); if (!addSuccessors(successors, pReachedSet, pPrecision)) { return false; } return true; }
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(); }
private boolean combineARGs( List<ARGState> roots, ForwardingReachedSet pReceivedReachedSet, HistoryForwardingReachedSet pForwaredReachedSet) throws InterruptedException, CPAException { Pair<Map<String, Integer>, List<AbstractState>> initStates = identifyCompositeStateTypesAndTheirInitialInstances(roots); Map<String, Integer> stateToPos = initStates.getFirst(); List<AbstractState> initialStates = initStates.getSecond(); try { pReceivedReachedSet.setDelegate(new ReachedSetFactory(config, logger).create()); } catch (InvalidConfigurationException e) { logger.log(Level.SEVERE, "Creating reached set which should contain combined ARG fails."); return false; } shutdown.shutdownIfNecessary(); // combined root ARGState combinedRoot = new ARGState(new CompositeState(initialStates), null); CFANode locPred; ARGState composedState, composedSuccessor; Collection<ARGState> components; List<List<ARGState>> successorsForEdge = new ArrayList<>(initialStates.size()); EdgeSuccessor edgeSuccessorIdentifier = new EdgeSuccessor(); Map<Pair<List<AbstractState>, List<ARGState>>, ARGState> constructedCombinedStates = Maps.newHashMap(); Deque<Pair<List<ARGState>, ARGState>> toVisit = new ArrayDeque<>(); toVisit.add(Pair.of(roots, combinedRoot)); // traverse through ARGs and construct combined ARG // assume that states in initial states are most general, represent top state (except for // automaton CPAs) while (!toVisit.isEmpty()) { shutdown.shutdownIfNecessary(); components = toVisit.peek().getFirst(); composedState = toVisit.poll().getSecond(); // add composed state to reached set pReceivedReachedSet.add(composedState, SingletonPrecision.getInstance()); pReceivedReachedSet.removeOnlyFromWaitlist(composedState); // identify possible successor edges locPred = AbstractStates.extractLocation(composedState); nextEdge: for (CFAEdge succEdge : CFAUtils.allLeavingEdges(locPred)) { shutdown.shutdownIfNecessary(); successorsForEdge.clear(); edgeSuccessorIdentifier.setCFAEdge(succEdge); for (ARGState component : components) { // get the successors of ARG state for this edge succEdge edgeSuccessorIdentifier.setPredecessor(component); successorsForEdge.add( Lists.newArrayList( Iterables.filter(component.getChildren(), edgeSuccessorIdentifier))); // check if stopped because no concrete successors exists, then do not if (successorsForEdge.get(successorsForEdge.size() - 1).isEmpty() && noConcreteSuccessorExist(component, succEdge, pForwaredReachedSet)) { continue nextEdge; } } // construct successors for each identified combination for (Pair<List<AbstractState>, List<ARGState>> combinedSuccessor : computeCartesianProduct(successorsForEdge, stateToPos, initialStates)) { if (constructedCombinedStates.containsKey(combinedSuccessor)) { // handle coverage constructedCombinedStates.get(combinedSuccessor).addParent(composedState); } else { // construct and register composed successor composedSuccessor = new ARGState(new CompositeState(combinedSuccessor.getFirst()), composedState); constructedCombinedStates.put(combinedSuccessor, composedSuccessor); // add successor for further exploration toVisit.add(Pair.of(combinedSuccessor.getSecond(), composedSuccessor)); } } } } return true; }
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; }
public void writeCoverageReport( final PrintStream pStatisticsOutput, final ReachedSet pReached, final CFA pCfa) { if (!enabled) { return; } Multiset<FunctionEntryNode> reachedLocations = getFunctionEntriesFromReached(pReached); Map<String, FileCoverageInformation> infosPerFile = new HashMap<>(); // Add information about existing functions for (FunctionEntryNode entryNode : pCfa.getAllFunctionHeads()) { final FileLocation loc = entryNode.getFileLocation(); if (loc.getStartingLineNumber() == 0) { // dummy location continue; } final String functionName = entryNode.getFunctionName(); final FileCoverageInformation infos = getFileInfoTarget(loc, infosPerFile); final int startingLine = loc.getStartingLineInOrigin(); final int endingLine = loc.getEndingLineInOrigin(); infos.addExistingFunction(functionName, startingLine, endingLine); if (reachedLocations.contains(entryNode)) { infos.addVisitedFunction(entryNode.getFunctionName(), reachedLocations.count(entryNode)); } } // Add information about existing locations for (CFANode node : pCfa.getAllNodes()) { for (int i = 0; i < node.getNumLeavingEdges(); i++) { handleExistedEdge(node.getLeavingEdge(i), infosPerFile); } } Set<CFANode> reachedNodes = from(pReached).transform(EXTRACT_LOCATION).filter(notNull()).toSet(); // Add information about visited locations for (AbstractState state : pReached) { ARGState argState = AbstractStates.extractStateByType(state, ARGState.class); if (argState != null) { for (ARGState child : argState.getChildren()) { if (!child.isCovered()) { List<CFAEdge> edges = argState.getEdgesToChild(child); if (edges.size() > 1) { for (CFAEdge innerEdge : edges) { handleCoveredEdge(innerEdge, infosPerFile); } // BAM produces paths with no edge connection thus the list will be empty } else if (!edges.isEmpty()) { handleCoveredEdge(Iterables.getOnlyElement(edges), infosPerFile); } } } } else { // Simple kind of analysis // Cover all edges from reached nodes // It is less precise, but without ARG it is impossible to know what path we chose CFANode node = AbstractStates.extractLocation(state); for (int i = 0; i < node.getNumLeavingEdges(); i++) { CFAEdge edge = node.getLeavingEdge(i); if (reachedNodes.contains(edge.getSuccessor())) { handleCoveredEdge(edge, infosPerFile); } } } } for (CoverageWriter w : reportWriters) { w.write(infosPerFile, pStatisticsOutput); } }