/** * translate boogie statement to prover expression * * @param s * @return */ protected ProverExpr statement2ProverExpr(Statement s) { if (s instanceof AssignStatement) { AssignStatement st = (AssignStatement) s; if (st.getLeft() instanceof SimpleHeapAccess || st.getLeft() instanceof ArrayReadExpression) { return arrayWrite2ProverExpr(st.getLeft(), expression2ProverExpr(st.getRight())); } else { return theoremProver.mkEq( expression2ProverExpr(st.getLeft()), expression2ProverExpr(st.getRight())); } } else if (s instanceof AssumeStatement) { AssumeStatement st = (AssumeStatement) s; return guardExpression2ProverExpr(st.getExpression()); } else if (s instanceof AssertStatement) { AssertStatement st = (AssertStatement) s; return guardExpression2ProverExpr(st.getExpression()); } else if (s instanceof InvokeStatement) { InvokeStatement st = (InvokeStatement) s; if (st.getReturnTargets().size() > 1) { Log.error("A method with too many return parameters! Should have been removed in SSA"); return null; } ProverFun fun = procedure2ProverExpr(st.getInvokedProcedure()); Log.error( "This should not happen as calls are removed by SSA: " + fun.toString()); // TODO: proper error handling? // This can never happen. LinkedList<ProverExpr> args = new LinkedList<ProverExpr>(); for (Expression e : st.getArguments()) { args.add(expression2ProverExpr(e)); } ProverExpr ret = fun.mkExpr((ProverExpr[]) args.toArray(new ProverExpr[args.size()])); if (st.getReturnTargets().size() > 0) { ProverExpr lhs = expression2ProverExpr(st.getReturnTargets().get(0)); if (st.getReturnTargets().get(0) instanceof SimpleHeapAccess || st.getReturnTargets().get(0) instanceof ArrayReadExpression) { ret = arrayWrite2ProverExpr(st.getReturnTargets().get(0), ret); // ((NAryExpression)lhs).addArgument(ret); // ret = VCExpressionGenerator.binOp(TmpConstants.Eq, // ((NAryExpression)lhs).getArgument(0),lhs); } else { ret = theoremProver.mkEq(lhs, ret); } } return ret; } else if (s instanceof ExpressionStatement) { ExpressionStatement es = (ExpressionStatement) s; return expression2ProverExpr(es.getExpression()); } else { Log.error("Unmatched Statement " + s.toString()); return null; } }
/** * Translates a guard in an axiom to a prover expression * * @param exp * @return */ private ProverExpr guardExpression2ProverExpr(Expression exp) { if (exp instanceof BinOpExpression) { /* * TODO: this case should only occur for inlined axioms. The current * type system is a bit messed up as it does not really allow * boolean types in the Boogie program. If we do a major revision, * we should definitely take care of this */ return expression2ProverExpr(exp); } else if (exp instanceof IteExpression) { return expression2ProverExpr(exp); } else { return theoremProver.mkEq(expression2ProverExpr(exp), theoremProver.mkLiteral(1)); } }
/** * @param arrexp * @param rhs * @return */ private ProverExpr arrayWrite2ProverExpr(Expression arrexp, ProverExpr rhs) { if (arrexp instanceof SimpleHeapAccess || arrexp instanceof ArrayReadExpression) { /* * This is needed here only for one purpose: a[x] = 5 in Boogie is * translated to a__i[x__j] = 5 in SSA-Boogie but in the VC we have * to write (= a__i (store a__(i-1) x__j 5), so we need to be able * to access the previous incarnation of array typed variables * Probably, we should settle this already during SSA and introduce * uninterpreted procedures for store and select */ Expression base; LinkedList<Expression> args = new LinkedList<Expression>(); if (arrexp instanceof SimpleHeapAccess) { SimpleHeapAccess exp = (SimpleHeapAccess) arrexp; base = exp.getHeapVariable(); args.add(exp.getBaseExpression()); args.add(exp.getFieldExpression()); } else { ArrayReadExpression exp = (ArrayReadExpression) arrexp; base = exp.getBaseExpression(); args.add(exp.getIndexExpression()); } ProverExpr newbase = expression2ProverExpr(base); ProverExpr lhs = arrayExpression2ProverExpr(base, args, rhs, new HashMap<Variable, ProverExpr>()); return theoremProver.mkEq(newbase, lhs); } Log.error("CRAAAAAAAAAASH"); return null; }
/** * Checks the formula * * @return Result of the prover */ protected ProverResult checkSat() { // build query info QueryInfo qi = new QueryInfo(); qi.setTime(0); qi.setSize(numberOfConjuncts); methodInfo.getQueries().add(qi); StopWatch sw = StopWatch.getInstanceAndStart(); ProverResult res = ProverResult.Error; // check formula if (z3_output) { z3_stream.append("(check-sat)"); // not needed actually // call Z3 via JNI and map result String formula = z3_stream.toString(); Log.info(formula); int result = z3.check(formula); if (-1 == result) res = ProverResult.Unsat; else if (1 == result) res = ProverResult.Sat; } else { res = theoremProver.checkSat(true); } // measure time qi.setTime(sw.stop()); // log time Log.info( String.format(" Query #%d: %s", methodInfo.getQueries().size(), qi.getFormattedTime())); return res; }
private ProverFun procedure2ProverExpr(BoogieProcedure proc) { HashMap<Variable, ProverExpr> localbound = new HashMap<Variable, ProverExpr>(); if (!usedFunctions.containsKey(proc)) { LinkedList<ProverType> args = new LinkedList<ProverType>(); int idx = 0; for (Variable v : proc.getParameterList()) { ProverExpr arg = theoremProver.mkBoundVariable(idx++, type2ProverSort(v.getType())); args.add(arg.getType()); localbound.put(v, arg); } ProverFun vcf = null; ProverType[] arr = args.toArray(new ProverType[args.size()]); if (proc.isPure() && proc.getRootBlock() != null && proc.getRootBlock().getStatements().size() == 1) { // TODO: this is a hack: // we assume that this case only occurs for prelude functions // which have only one statement // this will not work in any other case Statement stmt = proc.getRootBlock().getStatements().get(0); ProverExpr b = null; if (stmt instanceof ExpressionStatement) { ExpressionStatement es = (ExpressionStatement) stmt; b = expression2ProverExpr(es.getExpression(), localbound); } else { throw new RuntimeException("procedure2ProverExpr failed"); } vcf = theoremProver.mkDefinedFunction(getProverFriendlyName(proc.getName()), arr, b); } else { vcf = theoremProver.mkUnintFunction( getProverFriendlyName(proc.getName()), arr, type2ProverSort(proc.getReturnVariable().getType())); // TODO: uninterpreted functions? } usedFunctions.put(proc, vcf); } return usedFunctions.get(proc); }
/** * @param base * @param indices * @param rhs is null if we have Select operation, otherwise it is the value E on the right hand * side of an assignment a[x]=E. * @param boundvars * @return This is needed here only for one purpose: a[x] = 5 in Boogie is translated to * a__i[x__j] = 5 in SSA-Boogie but in the VC we have to write (= a__i (store a__(i-1) x__j * 5), so we need to be able to access the previous incarnation of array typed variables * Probably, we should settle this already during SSA and introduce uninterpreted procedures * for store and select. */ private ProverExpr arrayExpression2ProverExpr( Expression base, LinkedList<Expression> indices, ProverExpr rhs, HashMap<Variable, ProverExpr> boundvars) { LinkedList<ProverExpr> args = new LinkedList<ProverExpr>(); if (rhs != null) { if (base instanceof SSAVariable) { SSAVariable var = (SSAVariable) base; SSAVariable tmp = null; for (Variable v : proc.getVarIncarnationMap().get(((SSAVariable) base).getOriginalVar())) { if (v instanceof SSAVariable) { if (((SSAVariable) v).getIncarnation() == ((SSAVariable) base).getIncarnation() - 1) { tmp = (SSAVariable) v; break; } } } if (tmp == null) { tmp = new SSAVariable(var.getOriginalVar(), var.getIncarnation() - 1); proc.getVarIncarnationMap().get(((SSAVariable) base).getOriginalVar()).addFirst(tmp); } base = tmp; } else { Log.error( "org.joogie.vcgen.VCGeneration.arrayaccess2VCExpression: this case has not been considered ... Joogie will crash!"); } } ProverExpr arr = expression2ProverExpr(base, boundvars); for (Expression idx : indices) { args.add(expression2ProverExpr(idx, boundvars)); } if (rhs != null) return theoremProver.mkStore( arr, (ProverExpr[]) (args.toArray(new ProverExpr[args.size()])), rhs); else return theoremProver.mkSelect( arr, (ProverExpr[]) (args.toArray(new ProverExpr[args.size()]))); }
/** send an axiom to the prover */ protected void addAssertion(ProverExpr pexp) { /* * if (z3_firstquery) { z3_stream.append(z3_printSMT2Declarations()); * z3_firstquery = false; } z3_stream.append(z3_proverExpr2SMT2(pexp)); * System.err.println(z3_stream.toString()); */ theoremProver.addAssertion(pexp); /* * if (z3_output) { if (z3_firstquery) { * z3_stream.append(z3_printSMT2Declarations()); z3_firstquery = false; * } z3_stream.append(z3_proverExpr2SMT2(pexp)); } */ }
/** * Translates a BoogieType to a Prover Type * * @param t * @return */ private ProverType type2ProverSort(BoogieType t) { if (t.getName().compareTo("int") == 0) { return theoremProver.getIntType(); } else if (t.getName().compareTo("bool") == 0) { return theoremProver.getBooleanType(); } else if (t.getName().compareTo("$stringsizetype") == 0) { ProverType[] argTypes = {theoremProver.getIntType()}; return theoremProver.getArrayType(argTypes, theoremProver.getIntType()); } else if (t instanceof BoogieFieldType) { return theoremProver.getIntType(); } else if (t instanceof BoogieArrayType) { ProverType[] argTypes = {theoremProver.getIntType()}; return theoremProver.getArrayType( argTypes, type2ProverSort(((BoogieArrayType) t).getNestedType())); } else if (t instanceof HeapType) { ProverType[] argTypes = {theoremProver.getIntType(), theoremProver.getIntType()}; return theoremProver.getArrayType(argTypes, theoremProver.getIntType()); } else if (t instanceof BoogieObjectType) { return theoremProver.getIntType(); } // TODO: not tested! return theoremProver.getIntType(); }
/** * generates a prover expression from an expression e * * @param e * @param boundvars * @return */ private ProverExpr expression2ProverExpr(Expression e, HashMap<Variable, ProverExpr> boundvars) { try { if (e instanceof ArrayReadExpression) { ArrayReadExpression exp = (ArrayReadExpression) e; return arrayExpression2ProverExpr( exp.getBaseExpression(), new LinkedList<Expression>(Arrays.asList(new Expression[] {exp.getIndexExpression()})), null, boundvars); } else if (e instanceof InvokeExpression) { InvokeExpression exp = (InvokeExpression) e; ProverFun fun = procedure2ProverExpr(exp.getInvokedProcedure()); LinkedList<ProverExpr> args = new LinkedList<ProverExpr>(); for (Expression e2 : exp.getArguments()) { args.add(expression2ProverExpr(e2, boundvars)); } return fun.mkExpr((ProverExpr[]) args.toArray(new ProverExpr[args.size()])); } else if (e instanceof SimpleHeapAccess) { SimpleHeapAccess exp = (SimpleHeapAccess) e; return arrayExpression2ProverExpr( exp.getHeapVariable(), new LinkedList<Expression>( Arrays.asList( new Expression[] {exp.getBaseExpression(), exp.getFieldExpression()})), null, boundvars); } else if (e instanceof TypeExpression) { TypeExpression exp = (TypeExpression) e; return expression2ProverExpr(exp.getTypeVariable(), boundvars); } else if (e instanceof Variable) { Variable exp = (Variable) e; if (boundvars.containsKey(exp)) { return boundvars.get(exp); } if (!usedVariable.containsKey(exp)) { ProverExpr pe = theoremProver.mkVariable( getProverFriendlyName(exp.getName()), type2ProverSort(exp.getType())); usedVariable.put(exp, pe); } return usedVariable.get(exp); } else if (e instanceof UboundedIntConstant) { UboundedIntConstant exp = (UboundedIntConstant) e; return theoremProver.mkLiteral(BigInteger.valueOf(exp.getValue())); } else if (e instanceof Constant) { Log.error("DEBUG-ERROR, there should not be any constant but Integers! VC will be wrong!"); return expression2ProverExpr(BoogieProgram.v().getNullReference(), boundvars); } else if (e instanceof QuantifiedExpression) { // TODO: right now, Quantifiers can only be used in Axioms QuantifiedExpression qe = (QuantifiedExpression) e; HashMap<Variable, ProverExpr> bvars = new HashMap<Variable, ProverExpr>(boundvars); // LinkedList<ProverExpr> localBound = new // LinkedList<ProverExpr>(); int idx = 0; for (Variable v : qe.getBoundVariables()) { ProverExpr boundvar = theoremProver.mkBoundVariable(idx++, type2ProverSort(v.getType())); bvars.put(v, boundvar); // localBound.add(boundvar); } ProverExpr boundExp = expression2ProverExpr(qe.getExpression(), bvars); if (qe.getQuantifier() == Quantifier.ForAll) { return theoremProver.mkAll(boundExp, theoremProver.getBooleanType()); } else { return theoremProver.mkEx(boundExp, theoremProver.getBooleanType()); } } else if (e instanceof BinOpExpression) { BinOpExpression be = (BinOpExpression) e; ProverExpr left = (expression2ProverExpr(be.getLhs(), boundvars)); ProverExpr right = (expression2ProverExpr(be.getRhs(), boundvars)); switch (be.getOp()) { case Eq: { return theoremProver.mkEq(left, right); } case Lt: { return theoremProver.mkLt(left, right); } case Le: { return theoremProver.mkLeq(left, right); } case Gt: { return theoremProver.mkGt(left, right); } case Ge: { return theoremProver.mkGeq(left, right); } case Neq: { return theoremProver.mkNot(theoremProver.mkEq(left, right)); } case Implies: { return theoremProver.mkOr(theoremProver.mkNot(left), right); } case LAnd: { return theoremProver.mkAnd(left, right); } case LOr: { return theoremProver.mkOr(left, right); } case Plus: { return theoremProver.mkPlus(left, right); } case Minus: { return theoremProver.mkMinus(left, right); } case Mul: { return theoremProver.mkMult(left, right); } default: { throw new RuntimeException("Unmatched binop: " + be.getOp().toString()); // TODO: a proper exception might be nice. // However, this case can only occur if we screw up the // implementation } } } else if (e instanceof IteExpression) { IteExpression ite = (IteExpression) e; ProverExpr condE = expression2ProverExpr(ite.getCond(), boundvars); ProverExpr thenE = expression2ProverExpr(ite.getThen(), boundvars); ProverExpr elseE = expression2ProverExpr(ite.getElse(), boundvars); return theoremProver.mkIte(condE, thenE, elseE); } else { Log.error("Unmatched Expression " + e.toString()); return null; } } catch (Exception exc) { Log.error("expression2ProverExpr failed: " + exc.toString()); Log.error("Called on expression: " + e.toString()); if (e instanceof BinOpExpression) { BinOpExpression boe = (BinOpExpression) e; Log.error(boe.getLhs().getType().toString() + " and " + boe.getRhs().getType()); } return null; } }
protected ProverExpr makeHelperVar(String name) { z3_helperVars.add(name); return theoremProver.mkVariable(name, theoremProver.getBooleanType()); }
/** pop the top frame from the prover stack */ protected void popProverStack() { theoremProver.pop(); if (z3_output) { z3_stream.append("(pop)"); } }
/** push a new frame on the prover stack */ protected void pushProverStack() { theoremProver.push(); if (z3_output) { z3_stream.append("(push)"); } }