/** * Processes an edge of the CFA and will write code to the output function body. * * @param childElement the state after the given edge * @param edge the edge to process * @param functionStack the current callstack */ void processEdge(ARGState childElement, CFAEdge edge, Stack<FunctionBody> functionStack) { FunctionBody currentFunction = functionStack.peek(); if (childElement.isTarget()) { currentFunction.write(getTargetState()); } // handle the edge if (edge instanceof CFunctionCallEdge) { // if this is a function call edge we need to create a new state and push // it to the topmost stack to represent the function // create function and put in onto stack String freshFunctionName = startFunction(childElement, functionStack, edge.getPredecessor()); // write summary edge to the caller site (with the new unique function name) currentFunction.write(processFunctionCall(edge, freshFunctionName)); } else if (edge instanceof CFunctionReturnEdge) { functionStack.pop(); } else { currentFunction.write(processSimpleEdge(edge, currentFunction.getCurrentBlock())); } }
private void handleCoveredEdge( final CFAEdge pEdge, final Map<String, FileCoverageInformation> pCollectors) { FileLocation loc = pEdge.getFileLocation(); if (loc.getStartingLineNumber() == 0) { return; } if (pEdge instanceof ADeclarationEdge && (((ADeclarationEdge) pEdge).getDeclaration() instanceof AFunctionDeclaration)) { return; } final FileCoverageInformation collector = getFileInfoTarget(loc, pCollectors); if (pEdge instanceof AssumeEdge) { collector.addVisitedAssume((AssumeEdge) pEdge); } collector.addVisitedLine(pEdge.getLineNumber()); }
private void handleExistedEdge( final CFAEdge pEdge, final Map<String, FileCoverageInformation> pCollectors) { final FileLocation loc = pEdge.getFileLocation(); if (loc.getStartingLineNumber() == 0) { // dummy location return; } if (pEdge instanceof ADeclarationEdge && (((ADeclarationEdge) pEdge).getDeclaration() instanceof AFunctionDeclaration)) { // Function declarations span the complete body, this is not desired. return; } final FileCoverageInformation collector = getFileInfoTarget(loc, pCollectors); if (pEdge instanceof AssumeEdge) { collector.addExistingAssume((AssumeEdge) pEdge); } collector.addExistingLine(pEdge.getLineNumber()); }
protected String processSimpleEdge(CFAEdge pCFAEdge, BasicBlock currentBlock) { switch (pCFAEdge.getEdgeType()) { case BlankEdge: case StatementEdge: case ReturnStatementEdge: return pCFAEdge.getCode(); case AssumeEdge: { CAssumeEdge lAssumeEdge = (CAssumeEdge) pCFAEdge; return ("__CPROVER_assume(" + lAssumeEdge.getCode() + ");"); // return ("if(! (" + lAssumptionString + ")) { return (0); }"); } case DeclarationEdge: { CDeclarationEdge lDeclarationEdge = (CDeclarationEdge) pCFAEdge; if (lDeclarationEdge.getDeclaration().isGlobal()) { mGlobalDefinitionsList.add(lDeclarationEdge.getCode()); return ""; } // avoid having the same declaration edge twice in one basic block if (currentBlock.hasDeclaration(lDeclarationEdge)) { return ""; } else { currentBlock.addDeclaration(lDeclarationEdge); return lDeclarationEdge.getCode(); } } default: throw new AssertionError( "Unexpected edge " + pCFAEdge + " of type " + pCFAEdge.getEdgeType()); } }
@Override public AvoidanceReportingState getAbstractSuccessor(AbstractState pElement, CFAEdge pEdge) { UniqueAssignmentsInPathConditionState current = (UniqueAssignmentsInPathConditionState) pElement; maxNumberOfAssignments = Math.max(maxNumberOfAssignments, current.getMaximum()); if (scope == Scope.STATE || (scope == Scope.PATH && pEdge.getEdgeType() == CFAEdgeType.AssumeEdge)) { return new UniqueAssignmentsInPathConditionState( current.maximum, HashMultimap.create(current.mapping)); } else { return current; } }
@Override public AvoidanceReportingState getAbstractSuccessor(AbstractState pState, CFAEdge pEdge) { RepetitionsInPathConditionState current = (RepetitionsInPathConditionState) pState; if (pEdge.getEdgeType() != CFAEdgeType.AssumeEdge) { return current; } if (current.thresholdReached) { return current; } int assumeEdgesInPath = current.assumeEdgesInPath + 1; boolean thresholdReached = (threshold >= 0) && (assumeEdgesInPath >= threshold); maxAssumeEdgesInPath = Math.max(assumeEdgesInPath, maxAssumeEdgesInPath); return new RepetitionsInPathConditionState(assumeEdgesInPath, thresholdReached); }
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; }
/** * Returns the <code>AutomatonStates</code> that follow this State in the ControlAutomatonCPA. If * the passed <code>AutomatonExpressionArguments</code> are not sufficient to determine the * following state this method returns a <code>AutomatonUnknownState</code> that contains this as * previous State. The strengthen method of the <code>AutomatonUnknownState</code> should be used * once enough Information is available to determine the correct following State. * * <p>If the state is a NonDet-State multiple following states may be returned. If the only * following state is BOTTOM an empty set is returned. * * @throws CPATransferException */ private Collection<AutomatonState> getFollowStates( AutomatonState state, List<AbstractState> otherElements, CFAEdge edge, boolean failOnUnknownMatch) throws CPATransferException { Preconditions.checkArgument(!(state instanceof AutomatonUnknownState)); if (state == cpa.getBottomState()) { return Collections.emptySet(); } if (collectTokenInformation) { SourceLocationMapper.getKnownToEdge(edge); } if (state.getInternalState().getTransitions().isEmpty()) { // shortcut return Collections.singleton(state); } Collection<AutomatonState> lSuccessors = Sets.newHashSetWithExpectedSize(2); AutomatonExpressionArguments exprArgs = new AutomatonExpressionArguments(state, state.getVars(), otherElements, edge, logger); boolean edgeMatched = false; int failedMatches = 0; boolean nonDetState = state.getInternalState().isNonDetState(); // these transitions cannot be evaluated until last, because they might have sideeffects on // other CPAs (dont want to execute them twice) // the transitionVariables have to be cached (produced during the match operation) // the list holds a Transition and the TransitionVariables generated during its match List<Pair<AutomatonTransition, Map<Integer, String>>> transitionsToBeTaken = new ArrayList<>(2); for (AutomatonTransition t : state.getInternalState().getTransitions()) { exprArgs.clearTransitionVariables(); matchTime.start(); ResultValue<Boolean> match = t.match(exprArgs); matchTime.stop(); // System.out.println("----------------------"); // System.out.println(t.getTrigger()); // System.out.println(t.getFollowState().getName()); // System.out.println(edge.getPredecessor().getNodeNumber()); // System.out.println(edge.getCode()); // System.out.println(match.getValue()); if (match.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition condition could not be evaluated: " + match.getFailureMessage()); } // if one transition cannot be evaluated the evaluation must be postponed until enough // information is available return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else { if (match.getValue()) { edgeMatched = true; assertionsTime.start(); ResultValue<Boolean> assertionsHold = t.assertionsHold(exprArgs); assertionsTime.stop(); if (assertionsHold.canNotEvaluate()) { if (failOnUnknownMatch) { throw new CPATransferException( "Automaton transition assertions could not be evaluated: " + assertionsHold.getFailureMessage()); } // cannot yet be evaluated return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } else if (assertionsHold.getValue()) { if (!t.canExecuteActionsOn(exprArgs)) { if (failOnUnknownMatch) { throw new CPATransferException("Automaton transition action could not be executed"); } // cannot yet execute, goto UnknownState return Collections.<AutomatonState>singleton(new AutomatonUnknownState(state)); } // delay execution as described above Map<Integer, String> transitionVariables = ImmutableMap.copyOf(exprArgs.getTransitionVariables()); transitionsToBeTaken.add(Pair.of(t, transitionVariables)); } else { // matching transitions, but unfulfilled assertions: goto error state AutomatonState errorState = AutomatonState.automatonStateFactory( Collections.<String, AutomatonVariable>emptyMap(), AutomatonInternalState.ERROR, cpa, 0, 0, ""); logger.log( Level.INFO, "Automaton going to ErrorState on edge \"" + edge.getDescription() + "\""); lSuccessors.add(errorState); } if (!nonDetState) { // not a nondet State, break on the first matching edge break; } } else { // do nothing if the edge did not match failedMatches++; } } } if (edgeMatched) { // execute Transitions for (Pair<AutomatonTransition, Map<Integer, String>> pair : transitionsToBeTaken) { // this transition will be taken. copy the variables AutomatonTransition t = pair.getFirst(); Map<Integer, String> transitionVariables = pair.getSecond(); actionTime.start(); Map<String, AutomatonVariable> newVars = deepCloneVars(state.getVars()); exprArgs.setAutomatonVariables(newVars); exprArgs.putTransitionVariables(transitionVariables); t.executeActions(exprArgs); actionTime.stop(); String violatedPropertyDescription = null; if (t.getFollowState().isTarget()) { violatedPropertyDescription = t.getViolatedPropertyDescription(exprArgs); } AutomatonState lSuccessor = AutomatonState.automatonStateFactory( newVars, t.getFollowState(), cpa, t.getAssumptions(), state.getMatches() + 1, state.getFailedMatches(), violatedPropertyDescription); if (!(lSuccessor instanceof AutomatonState.BOTTOM)) { lSuccessors.add(lSuccessor); } else { // add nothing } } return lSuccessors; } else { // stay in same state, no transitions to be executed here (no transition matched) AutomatonState stateNewCounters = AutomatonState.automatonStateFactory( state.getVars(), state.getInternalState(), cpa, state.getMatches(), state.getFailedMatches() + failedMatches, null); if (collectTokenInformation) { stateNewCounters.addNoMatchTokens(state.getTokensSinceLastMatch()); if (edge.getEdgeType() != CFAEdgeType.DeclarationEdge) { stateNewCounters.addNoMatchTokens( SourceLocationMapper.getAbsoluteTokensFromCFAEdge(edge, true)); } } return Collections.singleton(stateNewCounters); } }
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); } }