private static void ComputeCallGraph(Program program) { program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => { Succ.Add(impl.Name, new HashSet <Implementation>()); Pred.Add(impl.Name, new HashSet <Implementation>()); }); var name2Impl = BoogieUtil.nameImplMapping(program); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { foreach (var blk in impl.Blocks) { foreach (var cmd in blk.Cmds.OfType <CallCmd>()) { if (!Succ.ContainsKey(cmd.callee)) { continue; } Succ[impl.Name].Add(name2Impl[cmd.callee]); Pred[cmd.callee].Add(impl); } } } }
private static void initialize(Program program, ErrorTrace trace, string filename) { // Initialization fileName = filename == null ? "null" : filename; nameImplMap = BoogieUtil.nameImplMapping(program); events = new List <Event>(); threadStacks = new Dictionary <int, List <WorkItem> >(); tidCounter = 0; varNamesChanged = false; varNameMap = new Dictionary <string, string>(); var globals = BoogieUtil.GetGlobalVariables(program); globals.Iter(g => varNameMap.Add(g.Name + "__0", g.Name)); }
public RestrictToTrace(Program p, InsertionTrans t) { inp = p; usedNames = new Dictionary <string, int>(); nameToImpl = BoogieUtil.nameImplMapping(inp); nameToProc = BoogieUtil.nameProcMapping(inp); calledProcsNoImpl = new HashSet <string>(); output = new Program(); tinfo = t; newFixedContextProcs = new HashSet <int>(); addRaiseExceptionProcDecl = false; concretizeConstantToCall = new Dictionary <string, int>(); uvalueToConstants = new Dictionary <string, HashSet <Constant> >(); }
public AbstractHoudini(Program program) { this.program = program; this.impl2VC = new Dictionary <string, VCExpr>(); this.impl2EndStateVars = new Dictionary <string, List <VCExpr> >(); this.impl2CalleeSummaries = new Dictionary <string, List <Tuple <string, VCExprNAry> > >(); this.impl2Summary = new Dictionary <string, ISummaryElement>(); this.name2Impl = BoogieUtil.nameImplMapping(program); this.vcgen = new VCGen(program, CommandLineOptions.Clo.ProverLogFilePath, CommandLineOptions.Clo.ProverLogFileAppend, new List <Checker>()); this.prover = ProverInterface.CreateProver(program, CommandLineOptions.Clo.ProverLogFilePath, CommandLineOptions.Clo.ProverLogFileAppend, CommandLineOptions.Clo.TimeLimit); this.reporter = new AbstractHoudiniErrorReporter(); var impls = new List <Implementation>( program.TopLevelDeclarations.OfType <Implementation>()); // Create all VCs impls .Iter(attachEnsures); impls .Iter(GenVC); }
public override CBAProgram runCBAPass(CBAProgram p) { procsOnEP = new HashSet <string>(); var nameImplMap = BoogieUtil.nameImplMapping(p); // Set of all procedures (with an implementation) var allProcs = new HashSet <string>(); foreach (var tp in nameImplMap) { allProcs.Add(tp.Key); } var verifier = getVerifier(); // Run verification, gather traces verifier.run(input); // Set verification result success = verifier.success; traces = verifier.traces; // Now, compute the error projection if (verifier.success) { ErrorProjection = allProcs; return(null); } // Look at all procedures that lie on the error trace foreach (var trace in verifier.traces) { procsOnEP.UnionWith(trace.getProcs()); } Log.WriteLine(Log.Normal, string.Format("EP: Got {0} traces and {1} procs", verifier.traces.Count, procsOnEP.Count)); // Just make sure that we inlcude main here (probably not necessary) procsOnEP.Add(p.mainProcName); // Have we already covered all of the program? if (procsOnEP.Equals(allProcs)) { ErrorProjection = new HashSet <string>(); return(null); } // Iterate and try to force the verifier to return paths in // different procedures var done = false; do { var moreProcs = iterateComputation(input as PersistentCBAProgram, HashSetExtras <string> .Difference(allProcs, procsOnEP)); if (moreProcs.Count == 0) { done = true; } else { procsOnEP.UnionWith(moreProcs); if (procsOnEP.Equals(allProcs)) { done = true; } } } while (!done); ErrorProjection = HashSetExtras <string> .Difference(allProcs, procsOnEP); return(null); }
private PersistentCBAProgram instrument(PersistentCBAProgram pprogram, HashSet <string> candidates) { Debug.Assert(candidates.Count != 0); labelProcMap = new Dictionary <string, string>(); var program = pprogram.getProgram(); var nameImplMap = BoogieUtil.nameImplMapping(program); // Each candidate gets its own variable var procVars = new Dictionary <string, Variable>(); foreach (var str in candidates) { procVars.Add(str, new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "ep_var_" + str, Microsoft.Boogie.Type.Bool))); program.AddTopLevelDeclaration(procVars[str]); } // Add the new variables to each procedures' modifies clause foreach (var decl in program.TopLevelDeclarations) { if (decl is Implementation) { var impl = decl as Implementation; foreach (var str in candidates) { impl.Proc.Modifies.Add(new IdentifierExpr(Token.NoToken, procVars[str])); } } } // Instrument program foreach (var str in candidates) { var impl = nameImplMap[str]; var ncmds = new List <Cmd>(); ncmds.Add(BoogieAstFactory.MkVarEqConst(procVars[str], false)); ncmds.AddRange(impl.Blocks[0].Cmds); impl.Blocks[0].Cmds = ncmds; } // Instrument main. // -- Assign true to the new variables // -- Change the assert // (We assume that main only has one assert) var mainImpl = nameImplMap[pprogram.mainProcName]; var newCmds = new List <Cmd>(); foreach (var str in candidates) { newCmds.Add(BoogieAstFactory.MkVarEqConst(procVars[str], true)); } newCmds.AddRange(mainImpl.Blocks[0].Cmds); mainImpl.Blocks[0].Cmds = newCmds; // Find the assert Block blkWithAssert = null; AssertCmd assertCmd = null; bool found = false; foreach (var blk in mainImpl.Blocks) { found = false; foreach (var cmd in blk.Cmds) { if (cmd is AssertCmd) { assertCmd = cmd as AssertCmd; found = true; break; } } if (found) { blkWithAssert = blk; break; } } Debug.Assert(blkWithAssert != null); // Construct the new blocks var newLabs = new Dictionary <string, string>(); var restLab = getNewLabel(); foreach (var str in candidates) { newLabs.Add(str, getNewLabel()); var tcmds = new List <Cmd>(); tcmds.Add(new AssertCmd(Token.NoToken, Expr.Or(Expr.Ident(procVars[str]), assertCmd.Expr))); mainImpl.Blocks.Add(new Block(Token.NoToken, newLabs[str], tcmds, BoogieAstFactory.MkGotoCmd(restLab))); } // change blkWithAssert to include only commands upto the assert // Add the rest of commands to a new block found = false; newCmds = new List <Cmd>(); var newBlk = new Block(Token.NoToken, restLab, new List <Cmd>(), blkWithAssert.TransferCmd); foreach (Cmd cmd in blkWithAssert.Cmds) { if (cmd is AssertCmd) { found = true; continue; } if (!found) { newCmds.Add(cmd); } else { newBlk.Cmds.Add(cmd); } } blkWithAssert.Cmds = newCmds; var targets = new List <String>(newLabs.Values.ToArray()); blkWithAssert.TransferCmd = new GotoCmd(Token.NoToken, targets); mainImpl.Blocks.Add(newBlk); var ret = new PersistentCBAProgram(program, pprogram.mainProcName, pprogram.contextBound); //ret.writeToFile("ep_instrumented.bpl"); return(ret); }
public override CBAProgram runCBAPass(CBAProgram program) { var nameImplMap = BoogieUtil.nameImplMapping(program); // Construct call graph, compute SCCs var graph = new Graph <string>(); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { impl.Blocks.Iter(block => block.Cmds.OfType <CallCmd>().Iter(cmd => graph.AddEdge(impl.Name, cmd.callee))); } graph.AddSource(program.mainProcName); var preds = new Adjacency <string>(st => graph.Predecessors(st)); var succs = new Adjacency <string>(st => graph.Successors(st)); var sccs = new StronglyConnectedComponents <string>(graph.Nodes, preds, succs); sccs.Compute(); //var dotFileCnt = 1; // For each SCC, compute backedges foreach (var scc in sccs) { if (scc.Count == 1) { var onlyProc = scc.First(); if (nameImplMap.ContainsKey(onlyProc) && QKeyValue.FindBoolAttribute(nameImplMap[onlyProc].Attributes, "LoopProcedure")) { continue; } if (graph.Successors(onlyProc).All(callee => callee != onlyProc)) { continue; } } Console.Write("Considering SCC: "); scc.Iter(s => Console.Write("{0} ", s)); Console.WriteLine(); foundRecursion = true; // pick source var sccProcs = new HashSet <string>(scc); var src = scc.FirstOrDefault(proc => graph.Predecessors(proc).Any(pred => !sccProcs.Contains(pred))); if (src == null) { src = scc.First(); } var grey = new HashSet <string>(); var black = new HashSet <string>(); grey.Add(src); backedges = new HashSet <Tuple <string, string> >(); dfsTreeParent = new Dictionary <string, string>(); someCycles = new List <HashSet <string> >(); dfs(graph, src, sccProcs, grey, black); InferWhatToCut(graph, scc); // create copies var procCopies = new Dictionary <Tuple <string, int>, Procedure>(); var implCopies = new Dictionary <Tuple <string, int>, Implementation>(); foreach (var name in scc) { var impl = nameImplMap[name]; program.RemoveTopLevelDeclaration(impl); program.RemoveTopLevelDeclaration(impl.Proc); for (int i = 0; i < CommandLineOptions.Clo.RecursionBound; i++) { var dup = new FixedDuplicator(true); var nimpl = dup.VisitImplementation(impl); var nproc = dup.VisitProcedure(impl.Proc); nimpl.Name += string.Format("#{0}", i); nproc.Name += string.Format("#{0}", i); nimpl.Proc = nproc; program.AddTopLevelDeclaration(nimpl); program.AddTopLevelDeclaration(nproc); procCopies.Add(Tuple.Create(impl.Name, i), nproc); implCopies.Add(Tuple.Create(impl.Name, i), nimpl); } } // redirect calls foreach (var name in scc) { foreach (var pred in graph.Predecessors(name)) { if (sccProcs.Contains(pred)) { continue; } var pimpl = nameImplMap[pred]; foreach (var blk in pimpl.Blocks) { var newcmds = new List <Cmd>(); foreach (var cmd in blk.Cmds) { var ccmd = cmd as CallCmd; if (ccmd == null || !sccProcs.Contains(ccmd.callee)) { newcmds.Add(cmd); continue; } newcmds.Add( new CallCmd(ccmd.tok, ccmd.callee + string.Format("#{0}", CommandLineOptions.Clo.RecursionBound - 1), ccmd.Ins, ccmd.Outs, ccmd.Attributes, ccmd.IsAsync)); } blk.Cmds = newcmds; } } for (int i = 0; i < CommandLineOptions.Clo.RecursionBound; i++) { var impl = implCopies[Tuple.Create(name, i)]; foreach (var blk in impl.Blocks) { var newcmds = new List <Cmd>(); foreach (var cmd in blk.Cmds) { var ccmd = cmd as CallCmd; if (ccmd == null || !sccProcs.Contains(ccmd.callee)) { newcmds.Add(cmd); continue; } var cnt = i; if (CutEdge(name, ccmd.callee)) { cnt--; } if (cnt < 0) { newcmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); } else { newcmds.Add(new CallCmd(ccmd.tok, ccmd.callee + string.Format("#{0}", cnt), ccmd.Ins, ccmd.Outs, ccmd.Attributes, ccmd.IsAsync)); } } blk.Cmds = newcmds; } } } } return(program); }
public override CBAProgram runCBAPass(CBAProgram program) { // Add blanks blanksInfo = AddBlanks(program); // Remove unreachable procedures BoogieUtil.pruneProcs(program, program.mainProcName); if (!Options.TraceSlicing) { // Remove source line annotations sourceInfo = cba.PrintSdvPath.DeleteSourceInfo(program); } else { sourceInfo = null; } // Remove print info //printInfo = cba.PrintSdvPath.DeletePrintCmds(program); // Compress compressBlocks.VisitProgram(program); // name Ebasic NameEnvironmentConstraints(program); // Instrument assertions int tokenId = 0; origMainName = program.mainProcName; CBAProgram ret = null; if (!Options.DeepAsserts) { // Do error-bit instrumentation var impls = BoogieUtil.nameImplMapping(program); var pwa = cba.SequentialInstrumentation.procsWithAsserts(program); foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { var instrumented = new List <Block>(); foreach (var blk in impl.Blocks) { var currCmds = new List <Cmd>(); var currLabel = blk.Label; assertInstrInfo.addTrans(impl.Name, blk.Label, blk.Label); var incnt = -1; foreach (Cmd cmd in blk.Cmds) { incnt++; // instrument assert if (cmd is AssertCmd && !BoogieUtil.isAssertTrue(cmd)) { currCmds.Add(BoogieAstFactory.MkVarEqExpr(assertsPassed, (cmd as AssertCmd).Expr)); var token = new AssertToken(tokenId); originalAssertions.Add(token, cmd as AssertCmd); tokenLocation.Add(token, Tuple.Create(impl.Name, currLabel)); procToTokens.InitAndAdd(impl.Name, token); addedTrans(impl.Name, blk.Label, incnt, cmd, currLabel, currCmds); currLabel = addInstr(instrumented, currCmds, currLabel, tokenId); tokenId++; currCmds = new List <Cmd>(); continue; } // procedure call if (cmd is CallCmd && pwa.Contains((cmd as CallCmd).callee)) { currCmds.Add(cmd); addedTrans(impl.Name, blk.Label, incnt, cmd, currLabel, currCmds); currLabel = addInstr(instrumented, currCmds, currLabel, -1); currCmds = new List <Cmd>(); continue; } currCmds.Add(cmd); addedTrans(impl.Name, blk.Label, incnt, cmd, currLabel, currCmds); } instrumented.Add(new Block(Token.NoToken, currLabel, currCmds, blk.TransferCmd)); } impl.Blocks = instrumented; } program.AddTopLevelDeclaration(assertsPassed); var newMain = addMain(program); BoogieUtil.DoModSetAnalysis(program); // Set inline attribute // free requires assertsPassed == true; foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { impl.Proc.Requires.Add(new Requires(true, Expr.Ident(assertsPassed))); } // convert free ensures e to: // free ensures assertsPassed == false || e foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>() .Where(impl => pwa.Contains(impl.Name))) { foreach (Ensures ens in impl.Proc.Ensures) { ens.Condition = Expr.Or(Expr.Not(Expr.Ident(assertsPassed)), ens.Condition); } } currProg = program; ret = new CBAProgram(program, newMain, 0); } else { // Use Deep-assert instrumentation da = new cba.DeepAssertRewrite(); // First, tag assertions with tokens foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { foreach (var blk in impl.Blocks) { foreach (var cmd in blk.Cmds.OfType <AssertCmd>()) { if (BoogieUtil.isAssertTrue(cmd)) { continue; } var token = new AssertToken(tokenId); cmd.Attributes = new QKeyValue(Token.NoToken, "avn", new List <object> { Expr.Literal(tokenId) }, cmd.Attributes); originalAssertions.Add(token, cmd); tokenLocation.Add(token, Tuple.Create(impl.Name, blk.Label)); procToTokens.InitAndAdd(impl.Name, token); tokenId++; } } } // Second, do the rewrite var t1 = new PersistentProgram(program, program.mainProcName, program.contextBound); var t2 = da.run(t1); var daprog = t2.getCBAProgram(); // Third, revisit the assertions and remember their location // in the output program. This is a bit of a hack. The "tokenLocation" // of a token is the pair (p1,b1) where p1 is the procedure the assertion // originally came from and b1 is the block in the new main that contains // that assertion. var main = BoogieUtil.findProcedureImpl(daprog.TopLevelDeclarations, daprog.mainProcName); foreach (var block in main.Blocks) { foreach (var cmd in block.Cmds.OfType <AssertCmd>()) { var tok = QKeyValue.FindIntAttribute(cmd.Attributes, "avn", -1); if (tok < 0) { continue; } var token = new AssertToken(tok); Debug.Assert(tokenLocation.ContainsKey(token)); var oldloc = tokenLocation[token]; tokenLocation[token] = Tuple.Create(oldloc.Item1, block.Label); } } currProg = daprog; ret = daprog; } return(ret); }
public override CBAProgram runCBAPass(CBAProgram p) { // Run verification, gather traces var verifier = getVerifier(); verifier.run(input); // Set verification result success = verifier.success; traces = verifier.traces; // Now compute coverage, provided error was not reached if (!verifier.success) { return(null); } // Gather procedure names var nameImplMap = BoogieUtil.nameImplMapping(p); var allProcs = new HashSet <string>(); foreach (var tp in nameImplMap) { allProcs.Add(tp.Key); } procsNotCovered = new HashSet <string>(); procsNotCovered.UnionWith(allProcs); procsNotCovered.Remove(p.mainProcName); // Iterate and gather procedures that can be reached int oldProverLimit = CommandLineOptions.Clo.ProverCCLimit; var done = false; do { // Set the number of traces returned by boogie in one shot CommandLineOptions.Clo.ProverCCLimit = procsNotCovered.Count(); var covered = iterateComputation(input as PersistentCBAProgram, procsNotCovered); if (covered.Count == 0) { done = true; } else { procsNotCovered = HashSetExtras <string> .Difference(procsNotCovered, covered); if (!procsNotCovered.Any()) { done = true; } } } while (!done); CommandLineOptions.Clo.ProverCCLimit = oldProverLimit; return(null); }
// Short-circuit the chain of returns produced by raiseException public void optimizeRaiseExceptionInstrumentation(CBAProgram program) { var procMap = BoogieUtil.nameImplMapping(program); var mainImpl = procMap[program.mainProcName]; var labelBlockMap = BoogieUtil.labelBlockMapping(mainImpl); // For each block, check if the first statement is "assume raiseException" foreach (var blk in mainImpl.Blocks) { if (blk.Cmds.Count == 0) { continue; } var cmd = blk.Cmds[0]; if (!(cmd is AssumeCmd)) { continue; } var expr = (cmd as AssumeCmd).Expr; if (expr is IdentifierExpr) { var v = (expr as IdentifierExpr).Decl; if (v.Name != "raiseException") { continue; } } else { continue; } // Yup, its "assume raiseException" -- follow the chain of gotos through empty blocks var lab = getSingleSucc(blk.TransferCmd); if (lab == null) { continue; } var b = labelBlockMap[lab]; var chainLen = 0; /* Heuristic, possibly unsound: some blocks have a single statement that contains * an assignment for the return value. Note that once raiseException has been raised, * no return value is needed. */ while (b.Cmds.Count <= 1) { var next = getSingleSucc(b.TransferCmd); if (next == null) { break; } lab = next; b = labelBlockMap[lab]; chainLen++; } blk.TransferCmd = BoogieAstFactory.MkGotoCmd(lab); if (chainLen != 0) { Log.WriteLine(Log.Debug, "raiseException chain shortened by " + chainLen.ToString()); } } }
private ErrorTrace mapBackTraceInline(ErrorTrace trace) { Debug.Assert(trace.isIntra()); Program inputProg = inlineInput.getProgram(); var nameImplMap = BoogieUtil.nameImplMapping(inputProg); var traceLabels = trace.getBlockLabels(); var stack = new List <WorkItemR>(); Implementation startImpl = getImpl(trace.procName, nameImplMap); Debug.Assert(traceLabels[0] == startImpl.Blocks[0].Label); var curr = new WorkItemR(startImpl, traceLabels[0]); // This variable keeps our current position in traceLabels int ecount = 0; // This variable keeps our current position in traceLabels[ecount].Cmds int icount = 0; var ret = new ErrorTrace(trace.procName); ret.addBlock(new ErrorTraceBlock(traceLabels[0])); // We will walk over the input program, trying to cover the same path as // trace, knowing that trace represents an inlined path while (true) { // Reached the end of the path? if (ecount == traceLabels.Count) { break; } //Console.WriteLine(curr.impl.Name + ": " + curr.label); // Reached the end of the current block? if (curr.count == curr.block.Cmds.Count) { ecount++; icount = 0; if (ecount == traceLabels.Count) { break; } // Move onto the next block TransferCmd tc = curr.block.TransferCmd; if (tc is ReturnCmd) { ret.addReturn(); if (stack.Count == 0) { // We're done Debug.Assert(ecount == traceLabels.Count); break; } curr = stack[0]; stack.RemoveAt(0); // An inlined procedure ends with "Return" label Debug.Assert(inlinedLabelMatches("Return", traceLabels[ecount])); ecount++; icount = 0; Debug.Assert(traceLabels[ecount].Contains(curr.block.Label)); continue; } if (tc is GotoCmd) { List <String> targets = (tc as GotoCmd).labelNames; string target = matchInlinedLabelNames(targets, traceLabels[ecount]); curr = new WorkItemR(curr.impl, target); ret.addBlock(new ErrorTraceBlock(curr.label)); continue; } // Unknown transfer command Debug.Assert(false); } // We have to continue in the same block Cmd c = curr.block.Cmds[curr.count]; curr.count++; if (!(c is CallCmd)) { ret.addInstr(new IntraInstr(getInfo(trace, ecount, icount))); icount++; continue; } // We're at a procedure call CallCmd cc = c as CallCmd; // If this is a call to a procedure without implementation, then skip if (!nameImplMap.ContainsKey(cc.Proc.Name)) { ret.addInstr(new CallInstr(cc.Proc.Name, null, false, getInfo(trace, ecount, icount))); icount++; continue; } Implementation callee = getImpl(cc.Proc.Name, nameImplMap); string label = callee.Blocks[0].Label; // The first label in a inlined procedure is always called Entry ecount++; Debug.Assert(inlinedLabelMatches("Entry", traceLabels[ecount])); ecount++; icount = 0; Debug.Assert(inlinedLabelMatches(label, traceLabels[ecount])); WorkItemR next = new WorkItemR(callee, label); stack.Insert(0, curr); curr = next; ret.addCall(callee.Name); ret.addBlock(new ErrorTraceBlock(curr.label)); } return(ret); }