/**
*
*/
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;
// }
}