package bixie.checker.transition_relation; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import bixie.prover.Prover; import bixie.prover.ProverExpr; import boogie.controlflow.AbstractControlFlowFactory; import boogie.controlflow.BasicBlock; import boogie.controlflow.CfgProcedure; import boogie.controlflow.expression.CfgExpression; import boogie.controlflow.statement.CfgStatement; import boogie.controlflow.util.HasseDiagram; import boogie.controlflow.util.PartialBlockOrderNode; /** * @author schaef TODO: if we plan to do interprocedural analysis, we have to * change the way globals are handled here. */ public class FaultLocalizationTransitionRelation extends AbstractTransitionRelation { public LinkedList<ProverExpr> obligations = new LinkedList<ProverExpr>(); public HashMap<CfgStatement, BasicBlock> stmtOriginMap = new HashMap<CfgStatement, BasicBlock>(); HasseDiagram hd; public FaultLocalizationTransitionRelation(CfgProcedure cfg, AbstractControlFlowFactory cff, Prover p) { super(cfg, cff, p); makePrelude(); // create the ProverExpr for the precondition ProverExpr[] prec = new ProverExpr[cfg.getRequires().size()]; int i = 0; for (CfgExpression expr : cfg.getRequires()) { prec[i] = this.expression2proverExpression(expr); i++; } this.requires = this.prover.mkAnd(prec); // create the ProverExpr for the precondition ProverExpr[] post = new ProverExpr[cfg.getEnsures().size()]; i = 0; for (CfgExpression expr : cfg.getEnsures()) { post[i] = this.expression2proverExpression(expr); i++; } this.ensures = this.prover.mkAnd(post); this.hd = new HasseDiagram(cfg); computeSliceVC(cfg); this.hd = null; finalizeAxioms(); } private void computeSliceVC(CfgProcedure cfg) { PartialBlockOrderNode pon = hd.findNode(cfg.getRootNode()); LinkedList<BasicBlock> todo = new LinkedList<BasicBlock>(); todo.add(cfg.getRootNode()); HashSet<BasicBlock> mustreach = pon.getElements(); // System.err.println("-------"); // for (BasicBlock b : mustreach) System.err.println(b.getLabel()); // System.err.println("traverse "); while (!todo.isEmpty()) { BasicBlock current = todo.pop(); obligations.addAll(statements2proverExpression(current.getStatements())); for (CfgStatement stmt : current.getStatements()) { this.stmtOriginMap.put(stmt, current); } BasicBlock next = foo(current, mustreach); if (next!=null) { if (mustreach.contains(next)) { todo.add(next); } else { System.err.println("FIXME: don't know what to do with "+next.getLabel()); } } } // System.err.println("traverse done"); } private BasicBlock foo(BasicBlock b, HashSet<BasicBlock> mustpass) { HashSet<BasicBlock> done = new HashSet<BasicBlock>(); LinkedList<BasicBlock> todo = new LinkedList<BasicBlock>(); HashMap<BasicBlock, LinkedList<ProverExpr>> map = new HashMap<BasicBlock, LinkedList<ProverExpr>>(); todo.addAll(b.getSuccessors()); done.add(b); map.put(b, new LinkedList<ProverExpr>()); map.get(b).add(this.prover.mkLiteral(true)); while (!todo.isEmpty()) { BasicBlock current = todo.pop(); boolean allDone = true; LinkedList<LinkedList<ProverExpr>> prefix = new LinkedList<LinkedList<ProverExpr>>(); for (BasicBlock pre : current.getPredecessors()) { if (!done.contains(pre)) { allDone = false; break; } prefix.add(map.get(pre)); } if (!allDone) { todo.add(current); continue; } done.add(current); LinkedList<ProverExpr> conj = new LinkedList<ProverExpr>(); if (prefix.size()>1) { //TODO LinkedList<ProverExpr> shared = prefix.getFirst(); for (LinkedList<ProverExpr> list : prefix) { shared = sharedPrefix(shared, list); } conj.add(this.prover.mkAnd(shared.toArray(new ProverExpr[shared.size()]))); LinkedList<ProverExpr> disj = new LinkedList<ProverExpr>(); for (LinkedList<ProverExpr> list : prefix) { LinkedList<ProverExpr> cutlist = new LinkedList<ProverExpr>(); cutlist.addAll(list); cutlist.removeAll(shared); disj.add(this.prover.mkAnd(cutlist.toArray(new ProverExpr[cutlist.size()]))); } conj.add(this.prover.mkOr(disj.toArray(new ProverExpr[disj.size()]))); } else if (prefix.size()==1) { conj.addAll(prefix.getFirst()); } else { throw new RuntimeException("unexpected"); } if (mustpass.contains(current)) { if (conj.size()==1 && conj.getFirst().equals(this.prover.mkLiteral(true))) { // in that case, the predecessor was already in mustpass so nothing needs to be done. } else { ProverExpr formula = this.prover.mkAnd(conj.toArray(new ProverExpr[conj.size()])); this.obligations.add(formula); } return current; } else { for (CfgStatement stmt : current.getStatements()) { this.stmtOriginMap.put(stmt, current); } conj.addAll(statements2proverExpression(current.getStatements())); map.put(current, conj); for (BasicBlock suc : current.getSuccessors()) { if (!todo.contains(suc) && !done.contains(suc)) { todo.add(suc); } } } } return null; } private LinkedList<ProverExpr> sharedPrefix(LinkedList<ProverExpr> shared, LinkedList<ProverExpr> list) { Iterator<ProverExpr> iterA = shared.iterator(); Iterator<ProverExpr> iterB = list.iterator(); LinkedList<ProverExpr> ret = new LinkedList<ProverExpr>(); while(iterA.hasNext() && iterB.hasNext()) { ProverExpr next = iterA.next(); if (next == iterB.next()) { ret.add(next); } } return ret; } }