/** * */ package bixie.checker.inconsistency_checker; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import bixie.Options; import bixie.checker.report.Report; import bixie.checker.transition_relation.AbstractTransitionRelation; import bixie.prover.Prover; import bixie.prover.ProverExpr; import bixie.prover.ProverFactory; import bixie.transformation.CallUnwinding; import bixie.transformation.SingleStaticAssignment; import bixie.transformation.loopunwinding.AbstractLoopUnwinding; import boogie.controlflow.AbstractControlFlowFactory; import boogie.controlflow.BasicBlock; import boogie.controlflow.CfgAxiom; import boogie.controlflow.CfgProcedure; /** * @author schaef * */ public abstract class AbstractChecker implements Runnable { protected AbstractControlFlowFactory cff; protected CfgProcedure procedure; private Report report = null; protected Set<BasicBlock> feasibleBlocks = new LinkedHashSet<BasicBlock>(); protected Prover prover = null; /** * */ public AbstractChecker(AbstractControlFlowFactory cff, CfgProcedure p) { this.cff = cff; this.procedure = p; } public abstract Report runAnalysis(Prover prover); public Report getReport() { return this.report; } protected void transformIntoPassiveProgram() { this.procedure.pruneUnreachableBlocks(); CallUnwinding cunwind = new CallUnwinding(); cunwind.unwindCalls(this.procedure); AbstractLoopUnwinding.unwindeLoops(this.procedure); this.procedure.pruneUnreachableBlocks(); SingleStaticAssignment ssa = new SingleStaticAssignment(); ssa.computeSSA(this.procedure); this.procedure.pruneUnreachableBlocks(); } @Override public void run() { transformIntoPassiveProgram(); ProverFactory pf = new bixie.prover.princess.PrincessProverFactory(); try { if (Options.v().getProverLogPrefix()!=null && !Options.v().getProverLogPrefix().isEmpty()) { this.prover = pf.spawnWithLog(Options.v().getProverLogPrefix()); } else { this.prover = pf.spawn(); } this.report = runAnalysis(this.prover); } catch (Throwable e) { throw e; } finally { shutDownProver(); } } public void shutDownProver() { if (null == this.prover) return; this.prover.shutdown(); this.prover = null; } protected void pushTransitionRelation(Prover prover, AbstractTransitionRelation tr) { // now assert all proof obligations for (Entry<CfgAxiom, ProverExpr> entry : tr.getPreludeAxioms() .entrySet()) { prover.addAssertion(entry.getValue()); } prover.addAssertion(tr.getRequires()); for (Entry<BasicBlock, LinkedList<ProverExpr>> entry : tr .getProofObligations().entrySet()) { for (ProverExpr assertion : entry.getValue()) { prover.addAssertion(assertion); } } } /** * Creates an inverted version of the tr.getReachabilityVariables map * that only includes the subset of blocks in includedBlocks. * @param tr the transition relation of a procedure. * @param includedBlocks the blocks that are to be included in the result. * @return A map from each block in includedBlocks to its reachability variable. */ protected Map<ProverExpr, BasicBlock> createdInvertedReachabilityVariableMap(AbstractTransitionRelation tr, Set<BasicBlock> includedBlocks) { Map<ProverExpr, BasicBlock> uncoveredBlocks = new LinkedHashMap<ProverExpr, BasicBlock>(); for (Entry<BasicBlock, ProverExpr> entry : tr .getReachabilityVariables().entrySet()) { if (includedBlocks.contains(entry.getKey())) { // ignore the blocks that we are not interested in uncoveredBlocks.put(entry.getValue(), entry.getKey()); } } return uncoveredBlocks; } /** * takes a set of blocks and groups them into subgraphs that are directly connected. * The key is the entry to that subgraph and the value is the set of all blocks * in the graph. * @param blocks the set of blocks that should be grouped. * @return map from a block A to the subgraph G where A is the entry. */ protected Map<BasicBlock, Set<BasicBlock>> groupBlocks(Set<BasicBlock> blocks) { //find all blocks in 'blocks' that do not have a predecessor //in 'blocks' LinkedList<BasicBlock> entries = new LinkedList<BasicBlock>(); for (BasicBlock b : blocks) { boolean has_pre = false; for (BasicBlock pre : b.getPredecessors()) { if (blocks.contains(pre)) { has_pre = true; break; } } if (!has_pre) entries.add(b); } Map<BasicBlock, Set<BasicBlock>> res = new TreeMap<BasicBlock, Set<BasicBlock>>(); for (BasicBlock b : entries) { LinkedList<BasicBlock> todo = new LinkedList<BasicBlock>(); Set<BasicBlock> done = new LinkedHashSet<BasicBlock>(); Set<BasicBlock> subgraph = new LinkedHashSet<BasicBlock>(); todo.add(b); while (!todo.isEmpty()) { BasicBlock c = todo.pop(); if (blocks.contains(c)) { subgraph.add(c); } for (BasicBlock suc : c.getSuccessors()) { if (blocks.contains(suc) && !todo.contains(suc) && !done.contains(suc)) { todo.add(suc); } } } res.put(b, subgraph); } return res; } /* protected void toDot(String filename, Collection<BasicBlock> allBlocks, Collection<BasicBlock> blueBlocks, Collection<BasicBlock> redBlocks) { try (PrintWriter pw = new PrintWriter(new OutputStreamWriter( new FileOutputStream(filename), "UTF-8"))) { pw.println("digraph dot {"); for (BasicBlock block : blueBlocks) { // Special blocks if (redBlocks.contains(block)) { pw.println("\"" + block.getLabel() + "\" [style=filled, color=red, fillcolor=blue, label=\"" + block.getLabel() + "\"]"); } else { pw.println("\"" + block.getLabel() + "\" [style=filled, fillcolor=blue, label=\"" + block.getLabel() + "\"]"); } } for (BasicBlock block : redBlocks) { // Special blocks if (!blueBlocks.contains(block)) { pw.println("\"" + block.getLabel() + "\" [color=red, label=\"" + block.getLabel() + "\"]"); } } for (BasicBlock block : allBlocks) { // Regular blocks if (!blueBlocks.contains(block) && !redBlocks.contains(block)) { pw.println("\"" + block.getLabel() + "\" [label=\"" + block.getLabel() + "\"]"); } } for (BasicBlock block : allBlocks) { for (BasicBlock succ : block.getSuccessors()) { if (allBlocks.contains(succ)) { pw.println("\"" + block.getLabel() + "\"" + " -> " + "\"" + succ.getLabel() + "\""); } } } pw.println("}"); pw.close(); } catch (IOException e) { e.printStackTrace(); } } */ }