package bixie.checker;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import typechecker.TypeChecker;
import bixie.Options;
import bixie.checker.inconsistency_checker.AbstractChecker;
import bixie.checker.inconsistency_checker.CdcChecker;
import bixie.checker.inconsistency_checker.CombinedChecker;
import bixie.checker.inconsistency_checker.GreedyCfgChecker;
import bixie.checker.report.Report;
import bixie.checker.reportprinter.ReportPrinter;
import bixie.util.Log;
import bixie.util.aspects.Loggable;
import boogie.ProgramFactory;
import boogie.controlflow.AbstractControlFlowFactory;
import boogie.controlflow.CfgProcedure;
import boogie.controlflow.DefaultControlFlowFactory;
/**
* @author schaef
*
*/
public class ProgramAnalysis {
private static long timeouts = 0L;
public static void runFullProgramAnalysis(ProgramFactory pf,
ReportPrinter rp) {
GlobalsCache.v().setProgramFactory(pf);
TypeChecker tc = new TypeChecker(pf.getASTRoot());
// build the control-flow graphs
DefaultControlFlowFactory cff = new DefaultControlFlowFactory(
pf.getASTRoot(), tc);
Long checkTime = System.currentTimeMillis();
for (CfgProcedure p : cff.getProcedureCFGs()) {
if (p.getRootNode() == null)
continue;
try {
Report report = analyzeProcedure(p, cff);
if (report != null ) {
report.runFaultLocalization(); // do the interpolation based fault
// localization here to avoid timeouts.
// if (Options.v().stopTime) {
rp.printReport(report);
}
} catch (Exception e) {
e.printStackTrace();
break;
}
}
checkTime = System.currentTimeMillis() - checkTime;
Log.info("Total time: " + ((float) checkTime) / 1000f + "s");
Log.info("Total Timeouts after " + bixie.Options.v().getTimeout() + "sec: "
+ timeouts + " of "+ cff.getProcedureCFGs().size());
GlobalsCache.resetInstance();
}
private static AbstractChecker getChecker(AbstractControlFlowFactory cff,
CfgProcedure p) {
AbstractChecker checker = null;
switch (Options.v().getSelectedChecker()) {
case 1: {
checker = new GreedyCfgChecker(cff, p);
break;
}
case 2: {
checker = new CdcChecker(cff, p);
break;
}
default: {
checker = new CombinedChecker(cff, p);
break;
}
}
return checker;
}
@Loggable
private static Report analyzeProcedure(CfgProcedure p,
AbstractControlFlowFactory cff) {
if (bixie.Options.v().getDebugMode()) {
Log.info("Checking: " + p.getProcedureName());
}
// create an executor to kill the verification with a timeout if
// necessary
ExecutorService executor = Executors.newSingleThreadExecutor();
AbstractChecker checkerThread = getChecker(cff, p);
final Future<?> future = executor.submit(checkerThread);
boolean exception = false;
try {
// start thread and wait xx seconds. If timeout is set to 0, wait
// until it terminates.
if (bixie.Options.v().getTimeout() > 0) {
future.get(bixie.Options.v().getTimeout(), TimeUnit.SECONDS);
} else {
future.get();
}
Log.debug("Finished method " + p.getProcedureName());
} catch (TimeoutException e) {
// set timeout to method info
// methodInfo.setTimeout(true);
timeouts++;
Log.info("Timeout reached for method " + p.getProcedureName());
exception = true;
} catch (OutOfMemoryError e) {
Log.info("Out of memory for " + p.getProcedureName());
exception = true;
} catch (Exception e) {
e.printStackTrace();
exception = true;
} finally {
// cancel thread if not done
if (!future.isDone()) {
future.cancel(true);
}
// shutdown prover
checkerThread.shutDownProver();
// shutdown executor
executor.shutdown();
}
Report report = checkerThread.getReport();
if (exception)
return null;
return report;
}
}