package bixie.checker.transition_relation; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import org.joogie.cfgPlugin.Util.Dag; import ap.parser.IFormula; import bixie.prover.Prover; import bixie.prover.ProverExpr; import boogie.controlflow.AbstractControlFlowFactory; import boogie.controlflow.BasicBlock; import boogie.controlflow.CfgProcedure; import boogie.controlflow.CfgVariable; import boogie.controlflow.expression.CfgBooleanLiteral; import boogie.controlflow.expression.CfgExpression; import boogie.controlflow.expression.CfgIdentifierExpression; import boogie.controlflow.statement.CfgAssertStatement; import boogie.controlflow.statement.CfgAssignStatement; import boogie.controlflow.statement.CfgAssumeStatement; import boogie.controlflow.statement.CfgHavocStatement; import boogie.controlflow.statement.CfgStatement; /** * @author schaef * TODO: if we plan to do interprocedural analysis, we have * to change the way globals are handled here. */ public class TransitionRelation extends AbstractTransitionRelation { public HashMap<BasicBlock, ProverExpr> blockTransitionReleations = new HashMap<BasicBlock, ProverExpr>(); public HashMap<BasicBlock, ProverExpr> abstractTransitionReleations = new HashMap<BasicBlock, ProverExpr>(); public ProverExpr assertionFlag; protected Dag<IFormula> proverDAG; // protected ProverExpr expetionalReturnFlag = null; //TODO: this is a hack, like the creation //of this variable in the constructor // public ProverExpr getExpetionalReturnFlag() { // return expetionalReturnFlag; // } public Dag<IFormula> getProverDAG() { return proverDAG; } public TransitionRelation(CfgProcedure cfg, AbstractControlFlowFactory cff, Prover p) { super(cfg, cff, p); makePrelude(); this.assertionFlag = prover.mkVariable("MartinsAssertionFlag", prover.getBooleanType()); //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); //encode the forward reachability ProverExpr firstok = block2transitionRelation(cfg.getRootNode(), this.proofObligations); //the proof obligation for root als must contain that the block variable for root is true this.proofObligations.get(cfg.getRootNode()).add(firstok); //bfs through all blocks LinkedList<BasicBlock> todo = new LinkedList<BasicBlock>(); HashSet<BasicBlock> done = new HashSet<BasicBlock>(); todo.add(cfg.getRootNode()); while (!todo.isEmpty()) { BasicBlock current = todo.pop(); done.add(current); for (BasicBlock b : current.getSuccessors()) { if (!done.contains(b) && !todo.contains(b)) { todo.push(b); } } this.addBlock(current); } this.proverDAG = procToPrincessDag(cfg, this.reachabilityVariables ); finalizeAxioms(); } private ProverExpr block2transitionRelation(BasicBlock b, HashMap<BasicBlock, LinkedList<ProverExpr>> proofobligations) { if (reachabilityVariables.containsKey(b)) { return reachabilityVariables.get(b); } ProverExpr post; if (b.getSuccessors().size() == 0 ) { post = this.prover.mkLiteral(true); } else if (b.getSuccessors().size() == 1) { post = block2transitionRelation( b.getSuccessors().toArray(new BasicBlock[1])[0], proofobligations); } else { /* * compute \not (/\ (\not B_succ)) that is\/ ( B_succ) */ ProverExpr[] succs = new ProverExpr[b.getSuccessors().size()]; int i = 0; for (BasicBlock next : b.getSuccessors()) { succs[i++] = block2transitionRelation(next, proofobligations); } post = this.prover.mkOr(succs); } List<ProverExpr> stmts = statements2proverExpression(b.getStatements()); stmts.add(post); ProverExpr[] conj = stmts.toArray(new ProverExpr[stmts.size()]); ProverExpr blockvar = this.prover.mkVariable(b.getLabel() + "_fwd", this.prover.getBooleanType()); reachabilityVariables.put(b, blockvar); LinkedList<ProverExpr> obligations = new LinkedList<ProverExpr>(); obligations.add(this.prover.mkOr(this.prover.mkNot(blockvar), this.prover.mkAnd(conj))); proofobligations.put(b, obligations); return blockvar; } protected ProverExpr mkConjunction(Collection<ProverExpr> conjuncts) { if (conjuncts.size() == 0) { return prover.mkLiteral(true); } if (conjuncts.size() == 1) { return conjuncts.iterator().next(); } return prover.mkAnd(conjuncts.toArray(new ProverExpr[conjuncts.size()])); } public void addBlock(BasicBlock b) { LinkedList<CfgStatement> bStatements = b.getStatements(); // Add the concrete List<ProverExpr> concreteStmts = statements2proverExpression(bStatements); this.blockTransitionReleations.put(b, mkConjunction(concreteStmts)); // Add the abstract LinkedList<CfgStatement> bAbstractStatements = abstractStatements(bStatements); List<ProverExpr> abstractStmts = statements2proverExpression(bAbstractStatements); this.abstractTransitionReleations.put(b, mkConjunction(abstractStmts)); // Add the variable // if (!this.reachabilityVariables.containsKey(b)) { // this.reachabilityVariables.put(b, this.prover.mkVariable(b.getLabel() + "_fwd", this.prover.getBooleanType())); // } } /** * Isolate the abstraction of the statements (for example, just keep the frame statements). */ private LinkedList<CfgStatement> abstractStatements(LinkedList<CfgStatement> bStatements) { LinkedList<CfgStatement> abstractStatements = new LinkedList<CfgStatement>(); for (CfgStatement stmnt : bStatements) { if (stmnt instanceof CfgAssignStatement) { CfgAssignStatement asgn = (CfgAssignStatement) stmnt; CfgIdentifierExpression[] left = asgn.getLeft(); CfgExpression[] right = asgn.getRight(); boolean ok = true; if (left.length == right.length) { for (int i = 0; ok && i < left.length; ++ i) { CfgIdentifierExpression left_i = left[i]; CfgExpression right_i = right[i]; if (right_i instanceof CfgIdentifierExpression) { CfgVariable left_var = left_i.getVariable(); CfgVariable right_var = ((CfgIdentifierExpression)right_i).getVariable(); if (left_var!=right_var) { ok = false; } } else { ok = false; } } } else { ok = false; } if (ok) { abstractStatements.add(stmnt); } } } return abstractStatements; } // public void removeBlock(BasicBlock b) { // this.blockTransitionReleations.remove(b); // this.reachabilityVariables.remove(b); // } /* * (non-Javadoc) * @see bixie.checker.verificationcondition.AbstractTransitionRelation#statements2proverExpression(java.util.List) * * override the original ones to add a flag to all assertions so that we can disable them. */ @Override protected List<ProverExpr> statements2proverExpression(List<CfgStatement> stmts) { LinkedList<ProverExpr> res = new LinkedList<ProverExpr>(); for (CfgStatement s : stmts) { if (s instanceof CfgAssumeStatement && ((CfgAssumeStatement)s).getCondition() instanceof CfgBooleanLiteral && ((CfgBooleanLiteral)((CfgAssumeStatement)s).getCondition()).getValue()==true) { //do nothing continue; } if (s instanceof CfgAssertStatement && ((CfgAssertStatement)s).getCondition() instanceof CfgBooleanLiteral && ((CfgBooleanLiteral)((CfgAssertStatement)s).getCondition()).getValue()==true) { //do nothing continue; } ProverExpr pe = statement2proverExpression(s); this.pe2StmtMap.put(pe, s); res.add(pe); } return res; } /* * (non-Javadoc) * @see bixie.checker.verificationcondition.AbstractTransitionRelation#statements2proverExpression(java.util.List) * * override the original ones to add a flag to all assertions so that we can disable them. */ @Override protected ProverExpr statement2proverExpression(CfgStatement s) { if (s instanceof CfgAssertStatement) { CfgAssertStatement assrt = (CfgAssertStatement) s; /*!!!!! Here we translate 'assert(e)' to 'e\/assertionFlag' so that we can disable all * assertions at once by setting the flag to true. */ return this.prover.mkOr(expression2proverExpression(assrt.getCondition()), this.assertionFlag); // return expression2proverExpression(assrt.getCondition()); } else if (s instanceof CfgAssignStatement) { CfgAssignStatement assgn = (CfgAssignStatement) s; if (assgn.getLeft().length != assgn.getRight().length) { throw new RuntimeException("malformed assignment."); } ProverExpr[] conj = new ProverExpr[assgn.getLeft().length]; for (int i = 0; i < assgn.getLeft().length; i++) { ProverExpr left = expression2proverExpression(assgn.getLeft()[i]); ProverExpr right = expression2proverExpression(assgn.getRight()[i]); conj[i] = this.prover.mkEq(left, right); } return this.prover.mkAnd(conj); } else if (s instanceof CfgAssumeStatement) { CfgAssumeStatement assme = (CfgAssumeStatement) s; return expression2proverExpression(assme.getCondition()); } else if (s instanceof CfgHavocStatement) { // s Log.error("BUG: no havoc should be in the passive program!"); // Havoc is a no-op after SSA, so no need to keep it // in the transition relation return prover.mkLiteral(true); } else { //eg CfgCallStatement throw new RuntimeException("Unknown statement type: " + s.getClass().toString()); } } }