public void Run() { Implementation impl; var rd = ""; while (true) { if (!impls.TryTake(out impl)) { break; } while (!resources.TryTake(out rd)) { Thread.Sleep(100); } sem.WaitOne(); var wd = Path.Combine(rd, impl.Name); // create new directory for each entrypoint Directory.CreateDirectory(wd); // create new directory for each entrypoint RemoteExec.CleanDirectory(wd); var pruneFile = Path.Combine(wd, "pruneSlice.bpl"); Program newprogram; // lock because Parsing a program is not thread-safe lock (fslock) { BoogieUtil.PrintProgram(program, pruneFile); // dump original program (so that each entrypoint has its own copy of program) newprogram = BoogieUtil.ReadAndOnlyResolve(pruneFile); // entrypoint's copy of the program } // slice the program by entrypoints Program shallowP = pruneDeepProcs(newprogram, ref edges, impl.Name, approximationDepth, implNames); BoogieUtil.pruneProcs(shallowP, shallowP.TopLevelDeclarations.OfType <Procedure>() .Where(proc => BoogieUtil.checkAttrExists("entrypoint", proc.Attributes)) .Select(proc => proc.Name) .FirstOrDefault()); File.Delete(pruneFile); lock (fslock) { BoogieUtil.PrintProgram(shallowP, pruneFile); // dump sliced program } sem.Release(); if (Driver.createEntryPointBplsOnly) { Console.WriteLine("Skipping AVN run for {0} given /createEntrypointBplsOnly", impl.Name); resources.Add(rd); continue; } if (!remotedirs.Contains(rd)) { Console.WriteLine("Running entrypoint {0} locally {{", impl.Name); if (deadlineReached) { return; } // spawn the job -- local var output = RemoteExec.run(wd, avnPath, string.Format("\"{0}\" {1}", pruneFile, avnArgs)); lock (fslock) { // delete temp files if (!keepFiles) { var files = System.IO.Directory.GetFiles(wd, "*.bpl"); foreach (var f in files) { System.IO.File.Delete(f); } } using (StreamWriter sw = new StreamWriter(Path.Combine(wd, "stdout.txt"))) output.Iter(s => sw.WriteLine("{0}", s)); } Console.WriteLine("Running entrypoint {0} locally }}", impl.Name); } else { // spawn the job -- remote if (psexecPath == null) { throw new FileNotFoundException("Cannot find PSEXEC!"); } // find the name of the machine from the remote folder name var machine = ""; var remoteroot = RemoteExec.GetRemoteFolder(rd, out machine); Console.WriteLine("Running entrypoint {0} on {1} {{", impl.Name, machine); // psexec machine -w remoteroot\impl remoteroot\fastavn\fastavn.exe remoteroot args wd = Path.Combine(remoteroot, impl.Name); var cmd = string.Format("{0} -w {1} {2} {3} {4}", machine, wd, Path.Combine(remoteroot, "fastavn", "AngelicVerifierNull.exe"), "pruneSlice.bpl", avnArgs); //Console.WriteLine("PSEXEC Running: {0}", cmd); if (deadlineReached) { return; } var output = RemoteExec.run(Directory.GetCurrentDirectory(), psexecPath, cmd); lock (fslock) { // delete temp files var td = Path.Combine(rd, impl.Name); if (debug) { Console.WriteLine("Getting files in directory: {0}", td); } var files = System.IO.Directory.GetFiles(td, "*.bpl"); foreach (var f in files) { if (debug) { Console.WriteLine("Deleting {0}", f); } System.IO.File.Delete(f); } // copy the results back var ld = Path.Combine(Directory.GetCurrentDirectory(), impl.Name); Directory.CreateDirectory(ld); RemoteExec.CleanDirectory(ld); RemoteExec.CopyFolder(rd, Directory.GetCurrentDirectory(), impl.Name, true); using (StreamWriter sw = new StreamWriter(Path.Combine(ld, "stdout.txt"))) output.Iter(s => sw.WriteLine("{0}", s)); } Console.WriteLine("Running entrypoint {0} on {1} }}", impl.Name, machine); } lock (fslock) { // collect and merge bugs var bugs = collectBugs(Path.Combine(Directory.GetCurrentDirectory(), impl.Name, bugReportFileName)); bugs.Iter(b => { if (!mergedBugs.ContainsKey(b)) { mergedBugs[b] = 0; } mergedBugs[b] += 1; }); Utils.Print(string.Format("Bugs found so far: {0}", mergedBugs.Count)); resources.Add(rd); } } }
static void Main(string[] args) { Console.CancelKeyPress += Console_CancelKeyPress; if (args.Length < 1) { Console.WriteLine("Usage: FastAVN file.bpl"); return; } if (args.Any(s => s == "/break")) { System.Diagnostics.Debugger.Launch(); } if (args.Any(s => s == "/keepFiles")) { Driver.keepFiles = true; } args.Where(s => s.StartsWith("/aopt:")) .Iter(s => avnArgs += " /" + s.Substring("/aopt:".Length) + " "); args.Where(s => s.StartsWith("/hopt:")) .Iter(s => avHarnessInstrArgs += " /" + s.Substring("/hopt:".Length) + " "); if (args.Any(s => s == "/createEntrypointBplsOnly")) { Driver.createEntryPointBplsOnly = true; } if (args.Any(s => s == "/mergeEntrypointBugsOnly")) { Driver.mergeEntryPointBugsOnly = true; } // user definded verbose level args.Where(s => s.StartsWith("/verbose:")) .Iter(s => verbose = int.Parse(s.Substring("/verbose:".Length))); // depth k used by implementation pruning args.Where(s => s.StartsWith("/depth:")) .Iter(s => approximationDepth = int.Parse(s.Substring("/depth:".Length))); args.Where(s => s.StartsWith("/numThreads:")) .Iter(s => numThreads = int.Parse(s.Substring("/numThreads:".Length))); // Get config for remote execution args.Where(s => s.StartsWith("/config:")) .Iter(s => config = FastAvnConfig.DeSerialize(s.Substring("/config:".Length))); args.Where(s => s.StartsWith("/killAfter:")) .Iter(s => deadline = int.Parse(s.Substring("/killAfter:".Length))); // default args avnArgs += " /dumpResults:" + bugReportFileName + " "; avnArgs += " /EE:onlySlicAssumes+ /EE:ignoreAllAssumes- "; // Find AVN executable avnPath = findExe("AngelicVerifierNull.exe"); avHarnessInstrPath = findExe("AvHarnessInstrumentation.exe"); psexecPath = findExe("psexec.exe"); Debug.Assert(avnPath != null && avHarnessInstrPath != null); try { Stats.resume("fastavn"); if (Driver.mergeEntryPointBugsOnly) { // collate bugs lock (fslock) { printingOutput = true; if (Directory.Exists(bug_folder)) { Utils.Print(string.Format("WARNING!! Removing {0} folder", bug_folder)); Directory.Delete(Path.Combine(Directory.GetCurrentDirectory(), bug_folder), true); } HashSet <string> epNames = new HashSet <string>(Directory.GetDirectories(@".")); epNames = new HashSet <string>(epNames.Select(s => Path.GetFileName(s))); printBugs(ref mergedBugs, epNames.Count); mergeBugs(epNames); } return; } // Get input program Utils.Print(String.Format("----- Run FastAVN on {0} with k={1} ------", args[0], approximationDepth), Utils.PRINT_TAG.AV_OUTPUT); // initialize corral and boogie for fastAVN InitializeCorralandBoogie(); // Run harness instrumentation var resultfile = Path.Combine(Directory.GetCurrentDirectory(), "hinst.bpl"); var hinstOut = RemoteExec.run(Directory.GetCurrentDirectory(), avHarnessInstrPath, string.Format("{0} \"{1}\" {2}", args[0], resultfile, avHarnessInstrArgs)); hinstOut.Iter(s => Console.WriteLine("[hinst] {0}", s)); if (!File.Exists(resultfile)) { throw new Exception("Error running harness instrumentation"); } var prog = BoogieUtil.ReadAndOnlyResolve(resultfile); // Do a run on instrumented program, filter out entrypoints var entrypoints = new HashSet <string>(); var entrypoint_impl = prog.TopLevelDeclarations.OfType <Implementation>() .Where(impl => QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "entrypoint")) .FirstOrDefault(); Debug.Assert(entrypoint_impl != null); // other entrypoints can never reach an assertion, don't run AVN on them foreach (Block b in entrypoint_impl.Blocks) { b.Cmds.OfType <CallCmd>() .Where(cc => QKeyValue.FindBoolAttribute(cc.Attributes, AvUtil.AvnAnnotations.AvhEntryPointAttr)) .Iter(cc => entrypoints.Add(cc.callee)); } // do reachability analysis on procedures // prune deep (depth > K) implementations: treat as angelic sliceAndRunAVN(prog, approximationDepth, entrypoints); Stats.stop("fastavn"); Stats.printStats(); } catch (Exception e) { //stacktrace containts source locations, confuses regressions that looks for AV_OUTPUT Utils.Print(String.Format("FastAVN failed with: {0}", e.Message), Utils.PRINT_TAG.AV_OUTPUT); Utils.Print(String.Format("FastAVN failed with: {0}", e.Message + e.StackTrace), Utils.PRINT_TAG.AV_DEBUG); } }
/// <summary> /// Run AVN binary on sliced programs /// </summary> /// <param name="prog">Original program</param> /// <param name="approximationDepth">Depth k beyond which angelic approximation is applied</param> private static void sliceAndRunAVN(Program prog, int approximationDepth, HashSet <string> epNames) { edges = buildCallGraph(prog); // Create a list of resources var worklist = new ConcurrentBag <string>(); for (int i = 0; i < numThreads; i++) { worklist.Add(Directory.GetCurrentDirectory()); } if (config != null) { foreach (var r in config.RemoteRoots) { remotedirs.Add(r.dir); for (int i = 0; i < r.Threads; i++) { worklist.Add(r.dir); } } } worklist = Shuffle(worklist); // Install FASTAVN foreach (var rd in remotedirs) { Console.WriteLine("Installing on {0}", rd); Directory.CreateDirectory(Path.Combine(rd, "fastavn")); RemoteExec.CopyFolder(Path.GetDirectoryName(avnPath), Path.Combine(rd, "fastavn"), true); } // max threads var threadsToSpawn = worklist.Count; // semaphore for limiting at most numThreads threads running at one time on local machine var sem = new Semaphore(numThreads, numThreads); // entrypoints var entrypoints = new ConcurrentBag <Implementation>(prog.TopLevelDeclarations.OfType <Implementation>() .Where(impl => epNames.Contains(impl.Name))); // deadline if (deadline > 0) { deadline = deadline - (int)((DateTime.Now - startingTime).TotalSeconds + 0.5); if (deadline < 0) { deadline = 1; } } if (deadline > 100) { var timeouttask = new System.Threading.Tasks.Task(() => { System.Threading.Thread.Sleep((deadline - 100) * 1000); Console.WriteLine("FastAvn deadline reached; consolidating results"); deadlineReached = true; KillSpawnedProcesses(); // Sleep for 2 seconds System.Threading.Thread.Sleep(2 * 1000); // collate bugs lock (fslock) { if (printingOutput) { return; } printingOutput = true; printBugs(ref mergedBugs, epNames.Count); mergeBugs(epNames); } // Kill self Process.GetCurrentProcess().Kill(); }); timeouttask.Start(); } else if (deadline != 0) { Console.WriteLine("Ignoring small deadline of {0} seconds", deadline); } var threads = new List <Thread>(); for (int i = 0; i < threadsToSpawn; i++) { var w = new Worker(prog, entrypoints, worklist, sem); threads.Add(new Thread(new ThreadStart(w.Run))); } threads.Iter(t => t.Start()); threads.Iter(t => t.Join()); if (Driver.createEntryPointBplsOnly) { Console.WriteLine("Early exit due to /createEntryPointBplsOnly"); return; } lock (fslock) { if (printingOutput) { return; } printingOutput = true; printBugs(ref mergedBugs, epNames.Count); mergeBugs(epNames); } }