@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); }
private void refineRelevantPredicatesComputer(List<ARGState> pPath, ARGReachedSet pReached) { UnmodifiableReachedSet reached = pReached.asReachedSet(); Precision oldPrecision = reached.getPrecision(reached.getLastState()); PredicatePrecision oldPredicatePrecision = Precisions.extractPrecisionByType(oldPrecision, PredicatePrecision.class); BlockPartitioning partitioning = predicateCpa.getPartitioning(); Deque<Block> openBlocks = new ArrayDeque<>(); openBlocks.push(partitioning.getMainBlock()); for (ARGState pathElement : pPath) { CFANode currentNode = AbstractStates.extractLocation(pathElement); Integer currentNodeInstance = getPredicateState(pathElement).getAbstractionLocationsOnPath().get(currentNode); if (partitioning.isCallNode(currentNode)) { openBlocks.push(partitioning.getBlockForCallNode(currentNode)); } Collection<AbstractionPredicate> localPreds = oldPredicatePrecision.getPredicates(currentNode, currentNodeInstance); for (Block block : openBlocks) { for (AbstractionPredicate pred : localPreds) { relevantPredicatesComputer.considerPredicateAsRelevant(block, pred); } } while (openBlocks.peek().isReturnNode(currentNode)) { openBlocks.pop(); } } }
boolean areAbstractSuccessors( AbstractState pElement, CFAEdge pCfaEdge, Collection<? extends AbstractState> pSuccessors, ProofChecker wrappedProofChecker) throws CPATransferException, InterruptedException { ARGState element = (ARGState) pElement; assert Iterables.elementsEqual(element.getChildren(), pSuccessors); AbstractState wrappedState = element.getWrappedState(); Multimap<CFAEdge, AbstractState> wrappedSuccessors = HashMultimap.create(); for (AbstractState absElement : pSuccessors) { ARGState successorElem = (ARGState) absElement; wrappedSuccessors.put(element.getEdgeToChild(successorElem), successorElem.getWrappedState()); } if (pCfaEdge != null) { return wrappedProofChecker.areAbstractSuccessors( wrappedState, pCfaEdge, wrappedSuccessors.get(pCfaEdge)); } CFANode loc = AbstractStates.extractLocation(element); for (CFAEdge edge : leavingEdges(loc)) { if (!wrappedProofChecker.areAbstractSuccessors( wrappedState, edge, wrappedSuccessors.get(edge))) { return false; } } return true; }
/** * This method chooses a new refinement root, in a bottom-up fashion along the error path. It * either picks the next state on the path sharing the same CFA location, or the (only) child of * the ARG root, what ever comes first. * * @param currentRoot the current refinement root * @return the relocated refinement root */ private ARGState relocateRepeatedRefinementRoot(final ARGState currentRoot) { repeatedRefinements.inc(); int currentRootNumber = AbstractStates.extractLocation(currentRoot).getNodeNumber(); ARGPath path = ARGUtils.getOnePathTo(currentRoot); for (ARGState currentState : path.asStatesList().reverse()) { // skip identity, because a new root has to be found if (currentState == currentRoot) { continue; } if (currentRootNumber == AbstractStates.extractLocation(currentState).getNodeNumber()) { return currentState; } } return Iterables.getOnlyElement(path.getFirstState().getChildren()); }
/** * This method exports the current representation in dot format to the given file. * * @param file file the file to write to */ public void exportToDot(PathTemplate file, int refinementCounter) { StringBuilder result = new StringBuilder().append("digraph tree {" + "\n"); for (Map.Entry<ARGState, ARGState> current : successorRelation.entries()) { if (interpolants.containsKey(current.getKey())) { StringBuilder sb = new StringBuilder(); sb.append("itp is " + interpolants.get(current.getKey())); result.append( current.getKey().getStateId() + " [label=\"" + (current.getKey().getStateId() + " / " + AbstractStates.extractLocation(current.getKey())) + " has itp " + (sb.toString()) + "\"]" + "\n"); result.append( current.getKey().getStateId() + " -> " + current.getValue().getStateId() + "\n"); // + " [label=\"" + // current.getKey().getEdgeToChild(current.getValue()).getRawStatement().replace("\n", "") + "\"]\n"); } else { result.append( current.getKey().getStateId() + " [label=\"" + current.getKey().getStateId() + " has itp NA\"]" + "\n"); result.append( current.getKey().getStateId() + " -> " + current.getValue().getStateId() + "\n"); // + " [label=\"" + // current.getKey().getEdgeToChild(current.getValue()).getRawStatement().replace("\n", "") + "\"]\n"); } if (current.getValue().isTarget()) { result.append( current.getValue().getStateId() + " [style=filled, fillcolor=\"red\"]" + "\n"); } assert (!current.getKey().isTarget()); } result.append("}"); try { MoreFiles.writeFile( file.getPath(refinementCounter, interpolationCounter), Charset.defaultCharset(), result); } catch (IOException e) { logger.logUserException(Level.WARNING, e, "Could not write interpolation tree to file"); } }
/** * This method extracts the precision increment for the given refinement root. It does so by * collection all non-trivial interpolants in the subtree of the given refinement root. * * @return the precision increment for the given refinement root */ public Multimap<CFANode, MemoryLocation> extractPrecisionIncrement(ARGState pRefinementRoot) { Multimap<CFANode, MemoryLocation> increment = HashMultimap.create(); Deque<ARGState> todo = new ArrayDeque<>(Collections.singleton(predecessorRelation.get(pRefinementRoot))); while (!todo.isEmpty()) { final ARGState currentState = todo.removeFirst(); if (stateHasNonTrivialInterpolant(currentState) && !currentState.isTarget()) { I itp = interpolants.get(currentState); for (MemoryLocation memoryLocation : itp.getMemoryLocations()) { increment.put(AbstractStates.extractLocation(currentState), memoryLocation); } } if (!stateHasFalseInterpolant(currentState)) { todo.addAll(successorRelation.get(currentState)); } } return increment; }
private boolean noConcreteSuccessorExist( final ARGState pPredecessor, final CFAEdge pSuccEdge, HistoryForwardingReachedSet pForwaredReachedSet) { // check if analysis stopped exploration due e.g. time limit for (ReachedSet reached : pForwaredReachedSet.getAllReachedSetsUsedAsDelegates()) { if (reached.getWaitlist().contains(pPredecessor)) { return false; } } // check if analysis stopped exploration due to true state in automaton --> concrete successors // may exist for (AbstractState state : AbstractStates.asIterable(pPredecessor)) { if (state instanceof AutomatonState && ((AutomatonState) state).getOwningAutomatonName().equals("AssumptionAutomaton")) { if (AutomatonStateARGCombiningHelper.endsInAssumptionTrueState( (AutomatonState) state, pSuccEdge)) { return false; } } } return true; }
@Override public AlgorithmStatus run(ReachedSet pReached) throws CPAException, InterruptedException { checkArgument( pReached instanceof ForwardingReachedSet, "RestartAlgorithm needs ForwardingReachedSet"); ForwardingReachedSet reached = (ForwardingReachedSet) pReached; CFANode mainFunction = AbstractStates.extractLocation(pReached.getFirstState()); assert mainFunction != null : "Location information needed"; AlgorithmStatus status = AlgorithmStatus.UNSOUND_AND_PRECISE; try { ReachedSetFactory reachedSetFactory = new ReachedSetFactory(globalConfig); // predicate analysis logger.log(Level.FINE, "Creating CPA for PredicateAnalysis"); Configuration singleConfig1 = getConfigFromFile(configFiles.get(0)); ConfigurableProgramAnalysis cpa1 = getCPA(reachedSetFactory, singleConfig1); Algorithm algorithm1 = getAlgorithm(shutdownNotifier, singleConfig1, logger, cpa1); ReachedSet reached1 = createInitialReachedSetForRestart(cpa1, mainFunction, singleConfig1, logger); reached.setDelegate(reached1); stats.noOfAlgorithmsUsed++; stats.totalTime.start(); status = run0(reached1, algorithm1); // stats.printIntermediateStatistics(System.out, Result.UNKNOWN, reached); // disabled, // because table-generator can not distinguish 1st and 2nd statistics. stats.resetSubStatistics(); // predicate bit-precise analysis logger.log(Level.FINE, "Creating CPA for PredicateAnalysis-Bitprecise"); Configuration singleConfig2 = getConfigFromFile(configFiles.get(1)); ConfigurableProgramAnalysis cpa2 = getCPA(reachedSetFactory, singleConfig2); { // this is the important step: re-use the reached-set ARGReplayCPA argReplay = CPAs.retrieveCPA(cpa2, ARGReplayCPA.class); checkNotNull(argReplay, "ARGReplay-CPA is needed for second analysis"); argReplay.setARGAndCPA(reached1, cpa1); } Algorithm algorithm2 = getAlgorithm(shutdownNotifier, singleConfig2, logger, cpa2); ReachedSet reached2 = createInitialReachedSetForRestart(cpa2, mainFunction, singleConfig2, logger); reached.setDelegate(reached2); stats.noOfAlgorithmsUsed++; stats.totalTime.start(); status = run0(reached2, algorithm2); stats.printIntermediateStatistics(System.out, Result.UNKNOWN, reached); stats.resetSubStatistics(); } catch (InvalidConfigurationException e) { logger.logUserException( Level.WARNING, e, "Exiting analysis because the configuration file is invalid"); } catch (IOException e) { logger.logUserException( Level.WARNING, e, "Exiting analysis because the configuration file could not be read"); } finally { // TODO close CPAs and algorithms } return status; }
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; }
@Override public AlgorithmStatus run(ReachedSet pReachedSet) throws CPAException, InterruptedException, CPAEnabledAnalysisPropertyViolationException { checkArgument( pReachedSet instanceof ForwardingReachedSet, "PartialARGsCombiner needs ForwardingReachedSet"); HistoryForwardingReachedSet reached = new HistoryForwardingReachedSet(pReachedSet); logger.log(Level.INFO, "Start inner algorithm to analyze program(s)"); AlgorithmStatus status = AlgorithmStatus.UNSOUND_AND_PRECISE; stats.analysisTime.start(); try { status = restartAlgorithm.run(reached); } finally { stats.analysisTime.stop(); } if (status.isSound()) { shutdown.shutdownIfNecessary(); logger.log(Level.INFO, "Program(s) soundly analyzed, start combining ARGs."); stats.argCombineTime.start(); try { Collection<ReachedSet> usedReachedSets = reached.getAllReachedSetsUsedAsDelegates(); if (usedReachedSets.size() <= 1) { logger.log(Level.INFO, "Only a single ARG is considered. Do not need to combine ARGs"); if (usedReachedSets.size() == 1) { ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate()); } return status; } if (from(reached.getDelegate()).anyMatch((IS_TARGET_STATE))) { logger.log(Level.INFO, "Error found, do not combine ARGs."); ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate()); return status; } logger.log(Level.FINE, "Extract root nodes of ARGs"); List<ARGState> rootNodes = new ArrayList<>(usedReachedSets.size()); for (ReachedSet usedReached : usedReachedSets) { checkArgument( usedReached.getFirstState() instanceof ARGState, "Require that all restart configurations use ARGCPA as top level CPA."); checkArgument( AbstractStates.extractLocation(usedReached.getFirstState()) != null, "Require that all restart configurations consider a location aware state"); for (AbstractState errorState : from(usedReached).filter((IS_TARGET_STATE))) { logger.log( Level.INFO, "Error state found in reached set ", usedReached, "but not by last configuration. Error state must be infeasible."); logger.log(Level.FINE, "Remove infeasible error state", errorState); ((ARGState) errorState).removeFromARG(); } rootNodes.add((ARGState) usedReached.getFirstState()); } shutdown.shutdownIfNecessary(); if (!combineARGs(rootNodes, (ForwardingReachedSet) pReachedSet, reached)) { logger.log(Level.SEVERE, "Combination of ARGs failed."); return status.withSound(false); } } finally { stats.argCombineTime.stop(); } logger.log(Level.INFO, "Finished combination of ARGS"); } else { logger.log( Level.INFO, "Program analysis is already unsound.", "Do not continue with combination of unsound results"); // set reached set to last used by restart algorithm if (reached.getDelegate() != pReachedSet) { ((ForwardingReachedSet) pReachedSet).setDelegate(reached.getDelegate()); } return status.withSound(false); } return status.withSound(true); }
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); } }