private AlgorithmStatus run0(ReachedSet reached, Algorithm algorithm) throws InterruptedException, CPAException, CPAEnabledAnalysisPropertyViolationException { logger.log(Level.INFO, "Starting sub-analysis"); shutdownNotifier.shutdownIfNecessary(); AlgorithmStatus status = algorithm.run(reached); shutdownNotifier.shutdownIfNecessary(); logger.log(Level.INFO, "Finished sub-analysis"); return status; }
@Override protected void refineUsingInterpolants( final ARGReachedSet pReached, final InterpolationTree<ValueAnalysisState, ValueAnalysisInterpolant> pInterpolationTree) throws InterruptedException { final boolean predicatePrecisionIsAvailable = isPredicatePrecisionAvailable(pReached); Map<ARGState, List<Precision>> refinementInformation = new HashMap<>(); Collection<ARGState> refinementRoots = pInterpolationTree.obtainRefinementRoots(restartStrategy); for (ARGState root : refinementRoots) { shutdownNotifier.shutdownIfNecessary(); root = relocateRefinementRoot(root, predicatePrecisionIsAvailable); if (refinementRoots.size() == 1 && isSimilarRepeatedRefinement( pInterpolationTree.extractPrecisionIncrement(root).values())) { root = relocateRepeatedRefinementRoot(root); } List<Precision> precisions = new ArrayList<>(2); // merge the value precisions of the subtree, and refine it precisions.add( mergeValuePrecisionsForSubgraph(root, pReached) .withIncrement(pInterpolationTree.extractPrecisionIncrement(root))); // merge the predicate precisions of the subtree, if available if (predicatePrecisionIsAvailable) { precisions.add(mergePredicatePrecisionsForSubgraph(root, pReached)); } refinementInformation.put(root, precisions); } for (Entry<ARGState, List<Precision>> info : refinementInformation.entrySet()) { shutdownNotifier.shutdownIfNecessary(); List<Predicate<? super Precision>> precisionTypes = new ArrayList<>(2); precisionTypes.add(VariableTrackingPrecision.isMatchingCPAClass(ValueAnalysisCPA.class)); if (predicatePrecisionIsAvailable) { precisionTypes.add(Predicates.instanceOf(PredicatePrecision.class)); } pReached.removeSubtree(info.getKey(), info.getValue(), precisionTypes); } }
private List<AbstractState> combineARGStates( final List<ARGState> combiningStates, final Map<String, Integer> pStateToPos, final List<AbstractState> pInitialStates) throws InterruptedException, CPAException { // set every state to the top state (except for automaton states) in case we have no concrete // information List<AbstractState> result = new ArrayList<>(pInitialStates); Iterable<AbstractState> wrapped; int index; // replace top by more concrete information found by exploration (saved in ARGStates) for (ARGState combiner : combiningStates) { shutdown.shutdownIfNecessary(); wrapped = getWrappedStates(combiner); for (AbstractState innerWrapped : wrapped) { shutdown.shutdownIfNecessary(); if (!pStateToPos.containsKey(getName(innerWrapped))) { Preconditions.checkState( innerWrapped instanceof AutomatonState || innerWrapped instanceof AssumptionStorageState, "Found state which is not considered in combined composite state and which is not due to the use of an assumption automaton"); continue; } index = pStateToPos.get(getName(innerWrapped)); if (pInitialStates.get(index) == result.get(index)) { if (result.get(index) instanceof AutomatonState) { result.set( index, automatonARGBuilderSupport.replaceStateByStateInAutomatonOfSameInstance( (AutomatonState) innerWrapped)); } else { result.set(index, innerWrapped); } } else { logger.logOnce( Level.WARNING, "Cannot identify the inner state which is more precise, use the earliest found. Combination may be unsound."); } } } return result; }
@Before public void loadZ3() throws Exception { NativeLibraries.loadLibrary("z3j"); Configuration config = Configuration.defaultConfiguration(); LogManager logger = TestLogManager.getInstance(); mgr = Z3FormulaManager.create(logger, config, ShutdownNotifier.create(), null, 42); ifmgr = (Z3IntegerFormulaManager) mgr.getIntegerFormulaManager(); }
@Override public void run() { int nextPartitionId; while (numPartitionsAcquiredForChecking.incrementAndGet() <= ioHelper.getNumPartitions()) { if (shutdownNotifier.shouldShutdown()) { abortCheckingPreparation(); } if (!checkResult.get()) { break; } try { readAndUnprocessedPartitions.acquire(); } catch (InterruptedException e) { abortCheckingPreparation(); return; } nextPartitionId = nextPartition.getAndIncrement(); if (!checkResult.get()) { break; } if (shutdownNotifier.shouldShutdown()) { abortCheckingPreparation(); } checker.checkPartition(nextPartitionId); mutex.lock(); try { checker.addCertificatePartsToCertificate(certificate); checker.addPartitionElements(partitionElems); checker.addElementsCheckedInOtherPartitions(inOtherPartition); } finally { mutex.unlock(); } checkedPartitions.release(); checker.clearAllSavedPartitioningElements(); } }
protected boolean checkCertificate( ReachedSet pReachedSet, ARGState pRoot, @Nullable List<ARGState> incompleteStates) throws CPAException, InterruptedException { // TODO does not account for strengthen yet (proof check will fail if strengthen is needed to // explain successor states) initChecking(pRoot); logger.log(Level.INFO, "Proof check algorithm started"); ARGState initialState = (ARGState) pReachedSet.popFromWaitlist(); Precision initialPrecision = pReachedSet.getPrecision(initialState); logger.log(Level.FINE, "Checking root state"); if (!checkCovering(initialState, pRoot, initialPrecision)) { return false; } pReachedSet.add(pRoot, initialPrecision); do { if (!prepareNextWaitlistIteration(pReachedSet)) { return false; } while (pReachedSet.hasWaitingState()) { shutdownNotifier.shutdownIfNecessary(); stats.increaseIteration(); ARGState state = (ARGState) pReachedSet.popFromWaitlist(); logger.log(Level.FINE, "Looking at state", state); if (!checkForStatePropertyAndOtherStateActions(state)) { logger.log(Level.INFO, "Property violation at state", state); return false; } if (state.isCovered()) { if (!checkCoveredStates(state, pReachedSet, initialPrecision)) { return false; } } else { if (!checkAndAddSuccessors(state, pReachedSet, initialPrecision, incompleteStates)) { return false; } } } } while (!isCheckComplete()); stats.increaseProofSize(pReachedSet.size() - 1); return isCheckSuccessful(); }
private void buildBalancedOr() throws InterruptedException { BDD result = factory.zero(); // false for (BDD cube : cubes) { if (cube != null) { shutdownNotifier.shutdownIfNecessary(); result.orWith(cube); } } cubes.clear(); cubes.add(result); assert (cubes.size() == 1); }
/** * builds a formula that represents the necessary variable assignments to "merge" the two ssa * maps. That is, for every variable X that has two different ssa indices i and j in the maps, * creates a new formula (X_k = X_i) | (X_k = X_j), where k is a fresh ssa index. Returns the * formula described above, plus a new SSAMap that is the merge of the two. * * @param ssa1 an SSAMap * @param pts1 the PointerTargetSet for ssa1 * @param ssa2 an SSAMap * @param pts2 the PointerTargetSet for ssa1 * @return The new SSAMap and the formulas that need to be added to the path formulas before * disjuncting them. */ MergeResult<SSAMap> mergeSSAMaps( final SSAMap ssa1, final PointerTargetSet pts1, final SSAMap ssa2, final PointerTargetSet pts2) throws InterruptedException { final List<MapsDifference.Entry<String, Integer>> symbolDifferences = new ArrayList<>(); final SSAMap resultSSA = SSAMap.merge(ssa1, ssa2, collectMapsDifferenceTo(symbolDifferences)); BooleanFormula mergeFormula1 = bfmgr.makeTrue(); BooleanFormula mergeFormula2 = bfmgr.makeTrue(); for (final MapsDifference.Entry<String, Integer> symbolDifference : symbolDifferences) { shutdownNotifier.shutdownIfNecessary(); final String symbolName = symbolDifference.getKey(); final CType symbolType = resultSSA.getType(symbolName); final int index1 = symbolDifference.getLeftValue().orElse(1); final int index2 = symbolDifference.getRightValue().orElse(1); assert symbolName != null; if (index1 > index2 && index1 > 1) { // i2:smaller, i1:bigger // => need correction term for i2 BooleanFormula mergeFormula = makeSsaMerger(symbolName, symbolType, index2, index1, pts2); mergeFormula2 = bfmgr.and(mergeFormula2, mergeFormula); } else if (index2 > 1) { assert index1 < index2; // i1:smaller, i2:bigger // => need correction term for i1 BooleanFormula mergeFormula = makeSsaMerger(symbolName, symbolType, index1, index2, pts1); mergeFormula1 = bfmgr.and(mergeFormula1, mergeFormula); } } return new MergeResult<>(resultSSA, mergeFormula1, mergeFormula2, bfmgr.makeTrue()); }
BooleanFormula addMergeAssumptions( final BooleanFormula pFormula, final SSAMap ssa1, final PointerTargetSet pts1, final SSAMap ssa2) throws InterruptedException { final List<MapsDifference.Entry<String, Integer>> symbolDifferences = new ArrayList<>(); final SSAMap resultSSA = SSAMap.merge(ssa1, ssa2, collectMapsDifferenceTo(symbolDifferences)); List<BooleanFormula> mergeFormula = new ArrayList<>(); mergeFormula.add(pFormula); for (final MapsDifference.Entry<String, Integer> symbolDifference : symbolDifferences) { shutdownNotifier.shutdownIfNecessary(); final String symbolName = symbolDifference.getKey(); final CType symbolType = resultSSA.getType(symbolName); final int index1 = symbolDifference.getLeftValue().orElse(1); final int index2 = symbolDifference.getRightValue().orElse(1); assert symbolName != null; if (index1 > index2 && index1 > 1) { // assumption violated // ssa2 is not the merge result of ssa1 and further ssa maps // simplify following PCC coverage check which will likely fail anyway // and return coarsest overapproximation return bfmgr.makeTrue(); } else if (index2 > 1) { assert index1 < index2; // i1:smaller, i2:bigger // => need correction term for i1 for (int i = index1; i < index2; i++) { mergeFormula.add(makeSsaMerger(symbolName, symbolType, i, i + 1, pts1)); } } } return bfmgr.and(mergeFormula); }
private Collection<Pair<List<AbstractState>, List<ARGState>>> computeCartesianProduct( final List<List<ARGState>> pSuccessorsForEdge, final Map<String, Integer> pStateToPos, final List<AbstractState> pInitialStates) throws InterruptedException, CPAException { // compute number of successors int count = 0; for (List<ARGState> successor : pSuccessorsForEdge) { if (successor.size() > 0) { count = count == 0 ? successor.size() : count * successor.size(); } } // no successor in every of the ARGs if (count == 0) { return Collections.emptySet(); } Collection<Pair<List<AbstractState>, List<ARGState>>> result = new ArrayList<>(count); // compute cartesian product int[] indices = new int[pSuccessorsForEdge.size()]; int nextIndex = 0; boolean restart; int lastSize = pSuccessorsForEdge.get(pSuccessorsForEdge.size() - 1).size(); if (lastSize == 0) { lastSize = 1; } while (indices[indices.length - 1] < lastSize) { shutdown.shutdownIfNecessary(); final List<ARGState> argSuccessors = new ArrayList<>(pSuccessorsForEdge.size()); // collect ARG successors for (int index = 0; index < indices.length; index++) { if (pSuccessorsForEdge.get(index).size() > 0) { argSuccessors.add( getUncoveredSuccessor(pSuccessorsForEdge.get(index).get(indices[index]))); } } // combine ARG states to get one cartesian product element, assume top state if no explicit // state information available result.add( Pair.of(combineARGStates(argSuccessors, pStateToPos, pInitialStates), argSuccessors)); // compute indices for elements of next cartesian element indices[nextIndex]++; restart = false; while (indices[nextIndex] >= pSuccessorsForEdge.get(nextIndex).size() && nextIndex < indices.length - 1) { nextIndex++; indices[nextIndex]++; restart = true; } while (restart && nextIndex > 0) { indices[--nextIndex] = 0; } } return result; }
private Pair<Map<String, Integer>, List<AbstractState>> identifyCompositeStateTypesAndTheirInitialInstances(Collection<ARGState> rootNodes) throws InterruptedException, CPAException { logger.log(Level.FINE, "Derive composite state structure of combined ARG"); List<AbstractState> initialState = new ArrayList<>(); Map<String, Integer> stateToPos = new HashMap<>(); List<String> automataStateNames = new ArrayList<>(); String name; int nextId = 0; Iterable<AbstractState> wrapped; logger.log(Level.FINE, "Add non-automaton states"); for (ARGState root : rootNodes) { shutdown.shutdownIfNecessary(); wrapped = getWrappedStates(root); for (AbstractState innerWrapped : wrapped) { shutdown.shutdownIfNecessary(); if (innerWrapped instanceof AssumptionStorageState) { continue; } name = getName(innerWrapped); if (stateToPos.containsKey(name)) { if (!initialState.get(stateToPos.get(name)).equals(innerWrapped)) { logger.log( Level.WARNING, "Abstract state ", innerWrapped.getClass(), " is used by multiple configurations, but cannot check that always start in the same initial state as it is assumed"); } } else { assert (initialState.size() == nextId); if (innerWrapped instanceof AutomatonState) { automataStateNames.add(name); } else { stateToPos.put(name, nextId); initialState.add(innerWrapped); nextId++; } } } } logger.log(Level.FINE, "Add automaton states related to specification"); Collections.sort(automataStateNames); int numRootStates = rootNodes.size(); Set<String> commonAutomataStates = new TreeSet<>(); for (int i = 1, j = 0; i < automataStateNames.size(); i++) { assert (j < i && j >= 0); if (automataStateNames.get(j).equals(automataStateNames.get(i))) { if (j + numRootStates - 1 == i) { // automaton states commonly used commonAutomataStates.add(automataStateNames.get(j)); } } else { j = i; } } // assume root is the root node of the first ARG constructed ARGState root = rootNodes.iterator().next(); if (root.getWrappedState() instanceof AbstractWrapperState) { wrapped = ((AbstractWrapperState) root.getWrappedState()).getWrappedStates(); } else { wrapped = Collections.singleton(root.getWrappedState()); } for (AbstractState innerWrapped : wrapped) { shutdown.shutdownIfNecessary(); name = getName(innerWrapped); if (commonAutomataStates.contains(name)) { assert (initialState.size() == nextId); stateToPos.put(name, nextId); if (!automatonARGBuilderSupport.registerAutomaton((AutomatonState) innerWrapped)) { logger.log( Level.SEVERE, "Property specification, given by automata specification, is ambigous."); throw new CPAException( "Ambigious property specification, automata specification contains automata with same name or same state names"); } initialState.add( automatonARGBuilderSupport.replaceStateByStateInAutomatonOfSameInstance( (AutomatonState) innerWrapped)); nextId++; } } return Pair.of(stateToPos, initialState); }
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); }
private ARGState relocateRefinementRoot( final ARGState pRefinementRoot, final boolean predicatePrecisionIsAvailable) throws InterruptedException { // no relocation needed if only running value analysis, // because there, this does slightly degrade performance // when running VA+PA, merging/covering and refinements // of both CPAs could lead to the state, where in two // subsequent refinements, two identical error paths // were found, through different parts of the ARG // So now, when running VA+PA, the refinement root // is set to the lowest common ancestor of those states // that are covered by the states in the subtree of the // original refinement root if (!predicatePrecisionIsAvailable) { return pRefinementRoot; } // no relocation needed if restart at top if (restartStrategy == RestartStrategy.ROOT) { return pRefinementRoot; } Set<ARGState> descendants = pRefinementRoot.getSubgraph(); Set<ARGState> coveredStates = new HashSet<>(); shutdownNotifier.shutdownIfNecessary(); for (ARGState descendant : descendants) { coveredStates.addAll(descendant.getCoveredByThis()); } coveredStates.add(pRefinementRoot); // no relocation needed if set of descendants is closed under coverage if (descendants.containsAll(coveredStates)) { return pRefinementRoot; } Map<ARGState, ARGState> predecessorRelation = Maps.newHashMap(); SetMultimap<ARGState, ARGState> successorRelation = LinkedHashMultimap.create(); Deque<ARGState> todo = new ArrayDeque<>(coveredStates); ARGState coverageTreeRoot = null; // build the coverage tree, bottom-up, starting from the covered states while (!todo.isEmpty()) { shutdownNotifier.shutdownIfNecessary(); final ARGState currentState = todo.removeFirst(); if (currentState.getParents().iterator().hasNext()) { ARGState parentState = currentState.getParents().iterator().next(); todo.add(parentState); predecessorRelation.put(currentState, parentState); successorRelation.put(parentState, currentState); } else if (coverageTreeRoot == null) { coverageTreeRoot = currentState; } } // starting from the root of the coverage tree, // the new refinement root is either the first node // having two or more children, or the original // refinement root, what ever comes first shutdownNotifier.shutdownIfNecessary(); ARGState newRefinementRoot = coverageTreeRoot; while (successorRelation.get(newRefinementRoot).size() == 1 && newRefinementRoot != pRefinementRoot) { newRefinementRoot = Iterables.getOnlyElement(successorRelation.get(newRefinementRoot)); } rootRelocations.inc(); return newRefinementRoot; }