public override CBAProgram runCBAPass(CBAProgram p) { p.Typecheck(); p.TopLevelDeclarations.OfType <Procedure>().Iter(proc => procsWithoutBody.Add(proc.Name)); p.TopLevelDeclarations.OfType <Implementation>().Iter(impl => procsWithoutBody.Remove(impl.Name)); // remove malloc //procsWithoutBody.RemoveWhere(str => str.Contains("malloc")); // Make sure that procs without a body don't modify globals foreach (var proc in p.TopLevelDeclarations.OfType <Procedure>().Where(proc => procsWithoutBody.Contains(proc.Name))) { if (proc.Modifies.Count > 0 && !BoogieUtil.checkAttrExists("allocator", proc.Attributes)) { throw new InvalidInput("Produce Bug Witness: Procedure " + proc.Name + " modifies globals"); } } // Add the boogie_si_record_int procedure var inpVarInt = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", Microsoft.Boogie.Type.Int), true); var inpVarBool = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", Microsoft.Boogie.Type.Bool), true); var reProcInt = new Procedure(Token.NoToken, recordProcNameInt, new List <TypeVariable>(), new List <Variable> { inpVarInt }, new List <Variable>(), new List <Requires>(), new List <IdentifierExpr>(), new List <Ensures>()); var reProcBool = new Procedure(Token.NoToken, recordProcNameBool, new List <TypeVariable>(), new List <Variable> { inpVarBool }, new List <Variable>(), new List <Requires>(), new List <IdentifierExpr>(), new List <Ensures>()); // Add procedures for initialization of local variables foreach (var impl in p.TopLevelDeclarations.OfType <Implementation>()) { var ncmds = new List <Cmd>(); foreach (var loc in (impl.LocVars.Concat(impl.OutParams))) { var cc = new CallCmd(Token.NoToken, GetInitLocalsProc(loc.TypedIdent.Type).Name, new List <Expr>(), new List <IdentifierExpr>(new IdentifierExpr[] { Expr.Ident(loc) })); cc.Attributes = new QKeyValue(Token.NoToken, RestrictToTrace.ConcretizeConstantNameAttr, new List <object> { LocalVarInitValueAttr }, cc.Attributes); cc.Proc = GetInitLocalsProc(loc.TypedIdent.Type); ncmds.Add(cc); } ncmds.AddRange(impl.Blocks[0].Cmds); impl.Blocks[0].Cmds = ncmds; } typeToInitLocalsProc.Values.Iter(pr => procsWithoutBody.Add(pr.Name)); typeToInitLocalsProc.Values.Iter(pr => p.AddTopLevelDeclaration(pr)); // save the current program var fd = new FixedDuplicator(true); var modInpProg = fd.VisitProgram(p); // Instrument to record stuff p.TopLevelDeclarations.OfType <Implementation>().Iter(impl => impl.Blocks.Iter(b => instrument(b))); // Name clash if this assert fails Debug.Assert(BoogieUtil.findProcedureDecl(p.TopLevelDeclarations, recordProcNameInt) == null); Debug.Assert(BoogieUtil.findProcedureDecl(p.TopLevelDeclarations, recordProcNameBool) == null); foreach (var rp in typeToRecordProc.Values) { Debug.Assert(BoogieUtil.findProcedureDecl(p.TopLevelDeclarations, rp.Name) == null); } p.AddTopLevelDeclaration(reProcInt); p.AddTopLevelDeclaration(reProcBool); p.AddTopLevelDeclarations(typeToRecordProc.Values); var tmainimpl = BoogieUtil.findProcedureImpl(p.TopLevelDeclarations, p.mainProcName); if (!QKeyValue.FindBoolAttribute(tmainimpl.Attributes, "entrypoint")) { tmainimpl.AddAttribute("entrypoint"); } var program = new PersistentCBAProgram(p, p.mainProcName, 0); //program.writeToFile("beforeverify.bpl"); var vp = new VerificationPass(true); vp.run(program); success = vp.success; if (success) { return(null); } var trace = mapBackTraceRecord(vp.trace); RestrictToTrace.addConcretization = true; RestrictToTrace.addConcretizationAsConstants = true; var tinfo = new InsertionTrans(); var rt = new RestrictToTrace(modInpProg, tinfo); rt.addTrace(trace); RestrictToTrace.addConcretization = false; RestrictToTrace.addConcretizationAsConstants = false; var rtprog = rt.getProgram(); // Build a map of where the alloc constants are from allocConstants = rt.concretizeConstantToCall; // Add symbolic constants for angelic map havocs var newDecls = new List <Constant>(); rtprog.TopLevelDeclarations.OfType <Implementation>().Iter(impl => impl.Blocks.Iter(b => instrumentMapHavocs(b, allocConstants, newDecls))); rtprog.AddTopLevelDeclarations(newDecls); /* * foreach (var impl in rtprog.TopLevelDeclarations.OfType<Implementation>()) * { * // strip _trace from the impl name * var implName = impl.Name; * var c = implName.LastIndexOf("_trace"); * while (c != -1) * { * implName = implName.Substring(0, c); * c = implName.LastIndexOf("_trace"); * } * * var vu = new VarsUsed(); * vu.VisitImplementation(impl); * vu.varsUsed.Where(s => s.StartsWith("alloc_")) * .Iter(s => allocConstants[s] = implName); * } */ BoogieUtil.findProcedureImpl(rtprog.TopLevelDeclarations, rt.getFirstNameInstance(p.mainProcName)) .AddAttribute("entrypoint"); program = new PersistentCBAProgram(rtprog, rt.getFirstNameInstance(p.mainProcName), p.contextBound); // Lets inline it all var inlp = new InliningPass(1); program = inlp.run(program); var compress = new CompressBlocks(); var ret = program.getProgram(); compress.VisitProgram(ret); return(new CBAProgram(ret, program.mainProcName, 0)); }
// Verify prog while tracking only variables in trackedVars. // Returns true if no error is found. // Returns false if error is found. Returns counterexample via pout // If returnTrace is set to false, then pout is always null // (no counterexample generation is attempted) // cex: the error trace in prog (if there is one) // tinfo: the transformation carried out in going from prog to pout // Call this method via: checkProgram or checkPath private static bool VerifyProgram(ref PersistentCBAProgram prog, VarSet trackedVars, bool returnTrace, out PersistentCBAProgram pout, out InsertionTrans tinfo, out ErrorTrace cex) { PersistentCBAProgram curr = prog; pout = null; cex = null; tinfo = null; ////// // These are the compilation phases ////// VariableSlicePass cp1 = new VariableSlicePass(trackedVars); StormInstrumentationPass cp2 = null; var recordK = new HashSet <string>(); if (!GlobalConfig.isSingleThreaded) { cp2 = new StormInstrumentationPass(); } StaticInliningAndUnrollingPass cp3 = null; if (GlobalConfig.staticInlining > 0) { cp3 = new StaticInliningAndUnrollingPass(new StaticSettings(CommandLineOptions.Clo.RecursionBound, CommandLineOptions.Clo.RecursionBound)); } ContractInfer ciPass = null; // Run the source transformations curr = cp1.run(curr); if (cp2 != null) { curr = cp2.run(curr); } if (cp3 != null) { curr = cp3.run(curr); } // infer contracts if (GlobalConfig.InferPass != null) { ciPass = new ContractInfer(GlobalConfig.InferPass); ciPass.ExtractLoops = false; curr = ciPass.run(curr); Console.WriteLine("Houdini took {0} seconds", ciPass.lastRun.TotalSeconds.ToString("F2")); GlobalConfig.InferPass = null; // add summaries to the original program prog = ciPass.addSummaries(prog); } // record k and tid if (cp2 != null) { recordK.Add(cp2.varKName); recordK.Add(cp2.tidVarName); } if (GlobalConfig.varsToRecord.Count != 0) { recordK.UnionWith(GlobalConfig.varsToRecord); recordK.IntersectWith(trackedVars.Variables); } // Now verify VerificationPass cp4 = new VerificationPass(true, recordK); curr = cp4.run(curr); reachedBound = cp4.reachedBound; if (cp4.success) { // Program correct. return(true); } else if (!returnTrace) { return(false); } else { // Concretize the trace and see if its a real bug // Concretization: map back the trace to the original program var trace4 = cp4.trace; //PrintProgramPath.print(cp4.input as PersistentCBAProgram, trace4, "temp4"); if (ciPass != null) { trace4 = ciPass.mapBackTrace(trace4); } var trace3 = trace4; if (cp3 != null) { trace3 = cp3.mapBackTrace(trace4); } //PrintProgramPath.print(cp3.input as PersistentCBAProgram, trace3, "temp3"); var trace2 = trace3; if (cp2 != null) { trace2 = cp2.mapBackTrace(trace3); } var trace1 = cp1.mapBackTrace(trace2); //PrintProgramPath.print(cp1.input as PersistentCBAProgram, trace1, "temp1"); cex = trace1; // Restrict the program to the trace tinfo = new InsertionTrans(); var traceProgCons = new RestrictToTrace(cp1.input.getProgram(), tinfo); ErrorTrace.fillInContextSwitchInfo(trace1); traceProgCons.addTrace(trace1); pout = new PersistentCBAProgram(traceProgCons.getProgram(), traceProgCons.getFirstNameInstance(cp1.getInput().mainProcName), cp1.getInput().contextBound, ConcurrencyMode.FixedContext); //pout.writeToFile("pout.bpl"); return(false); } }