/** * */ package jayhorn.checker; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.base.Verify; import jayhorn.Log; import jayhorn.Options; import jayhorn.hornify.HornEncoderContext; import jayhorn.hornify.HornPredicate; import jayhorn.hornify.Hornify; import jayhorn.hornify.encoder.S2H; import jayhorn.solver.Prover; import jayhorn.solver.ProverExpr; import jayhorn.solver.ProverFactory; import jayhorn.solver.ProverHornClause; import jayhorn.solver.ProverResult; import jayhorn.utils.GhostRegister; import jayhorn.utils.HeapCounterTransformer; import jayhorn.utils.Stats; import soottocfg.cfg.Program; import soottocfg.cfg.method.Method; import soottocfg.cfg.type.IntType; import soottocfg.cfg.variable.Variable; /** * @author teme */ public class SpacerChecker extends Checker{ private ProverFactory factory; private Prover prover; public SpacerChecker(ProverFactory factory) { this.factory = factory; } // Collect all the results private Map<ProverExpr, ProverResult> results = new HashMap<ProverExpr, ProverResult>(); private List<ProverHornClause> allClauses = new LinkedList<ProverHornClause>(); public Prover getProver(){ return prover; } public boolean checkProgram(Program program) { Preconditions.checkNotNull(program.getEntryPoint(), "The program has no entry points and thus is trivially verified."); GhostRegister.reset(); if (soottocfg.Options.v().memPrecision() >= 2) { GhostRegister.v().ghostVariableMap.put("pushID", IntType.instance()); } if (Options.v().useCallIDs) { Log.info("Inserting call IDs ... "); Verify.verify(false, "Don't run this for now!"); // CallingContextTransformer cct = new CallingContextTransformer(); // cct.transform(program); } HeapCounterTransformer hct = new HeapCounterTransformer(); hct.transform(program); if (Options.v().printCFG) { System.out.println(program); } Log.info("Hornify ... "); Hornify hf = new Hornify(factory); Stopwatch toHornTimer = Stopwatch.createStarted(); HornEncoderContext hornContext = hf.toHorn(program); Stats.stats().add("CfgToHorn", String.valueOf(toHornTimer.stop())); prover = hf.getProver(); //tsClauses = S2H.sh().getTransitionRelationClause(); //propertyClauses = S2H.sh().getPropertyClause(); allClauses.addAll(hf.clauses); ProverResult result = ProverResult.Unknown; try { final Method entryPoint = program.getEntryPoint(); Log.info("Running from entry point: " + entryPoint.getMethodName()); final HornPredicate entryPred = hornContext.getMethodContract(entryPoint).precondition; final ProverExpr entryAtom = entryPred.instPredicate(new HashMap<Variable, ProverExpr>()); final ProverHornClause entryClause = prover.mkHornClause(entryAtom, new ProverExpr[0], prover.mkLiteral(true)); allClauses.add(entryClause); for (ProverHornClause clause : allClauses){ prover.addRule(clause); } // Bounds Check // if (Options.v().getHeapLimit() > -1) { // HeapBoundsCheck bc = new HeapBoundsCheck(prover); // Log.info("Adding Heap Bounds Check"); // final ProverHornClause boundClause = bc.addMainHeapCheck(Options.v().getHeapLimit()); // prover.addRule(boundClause); // result = prover.query(bc.mainHeapExpr()); // String propLine = "HeapBound"; // if (result == ProverResult.Unsat) { // Stats.stats().add(propLine, "OK"); // } else if (result == ProverResult.Sat) { // Stats.stats().add(propLine, "KO"); // } else { // Stats.stats().add(propLine, "ERROR"); // } // } Log.info("Checking properties"); Stopwatch satTimer = Stopwatch.createStarted(); if (S2H.sh().getErrorState().isEmpty()){ Stats.stats().add("Warning", "No assertions found."); return true; } for (Map.Entry<ProverExpr, Integer> props : S2H.sh().getErrorState().entrySet()) { ProverExpr prop = props.getKey(); result = prover.query(prop); String propLine = "Property@Line"+props.getValue(); if (result == ProverResult.Unsat) { Stats.stats().add(propLine, "SAFE"); } else if (result == ProverResult.Sat){ Stats.stats().add(propLine, "UNSAFE"); if (Options.v().cex){ cex(); } } else { Stats.stats().add(propLine, "ERROR"); } results.put(prop, result); } if (Options.v().getPrintHorn()) { //System.out.println(hf.writeHorn()); prover.printRules(); } Stats.stats().add("CheckSatTime", String.valueOf(satTimer.stop())); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } finally { prover.shutdown(); } for (ProverResult res : results.values()) { if (res == ProverResult.Sat){ return false; }else if(res != ProverResult.Unsat){ throw new RuntimeException("Verification failed with prover code " + result); } } return true; } private void cex(){ //System.out.println(prover.getGroundSatAnswer()); } // private void removeUnreachableMethods(Program program) { // Set<Method> reachable = reachableMethod(program.getEntryPoint()); // Set<Method> toRemove = new HashSet<Method>(); // for (Method m : program.getMethods()) { // if (!reachable.contains(m)) { // toRemove.add(m); // Log.info("\tRemoving unreachable method: "+m.getMethodName()); // } // } // program.removeMethods(toRemove); //// System.err.println(program); // } // private Set<Method> reachableMethod(Method main) { // Set<Method> reachable = new HashSet<Method>(); // List<Method> todo = new LinkedList<Method>(); // todo.add(main); // while (!todo.isEmpty()) { // Method m = todo.remove(0); // reachable.add(m); // for (Method n : calledMethods(m)) { // if (!reachable.contains(n) && !todo.contains(n)) { // todo.add(n); // } // } // } // return reachable; // } // private List<Method> calledMethods(Method m) { // List<Method> res = new LinkedList<Method>(); // for (CfgBlock b : m.vertexSet()) { // for (Statement s : b.getStatements()) { // if (s instanceof CallStatement) { // CallStatement cs = (CallStatement) s; // res.add(cs.getCallTarget()); // } // } // } // return res; // } }