Example #1
0
        public static HashSet <string> RunHoudini(Program program, bool RobustAgainstEvaluate = false)
        {
            HoudiniStats.Reset();
            HoudiniInlining.RobustAgainstEvaluate = DualHoudini? false : RobustAgainstEvaluate;
            if (DualHoudini && CommandLineOptions.Clo.InlineDepth > 0)
            {
                throw new DualHoudiniFail("InlineDepth not supported");
            }

            // Gather existential constants
            var CandidateConstants = new Dictionary <string, Constant>();

            program.TopLevelDeclarations.OfType <Constant>()
            .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, "existential"))
            .Iter(c => CandidateConstants.Add(c.Name, c));

            // Create a function, one for each impl, for book-keeping
            var CandidateFuncsAssumed  = new Dictionary <string, Function>();
            var CandidateFuncsAsserted = new Dictionary <string, Function>();
            var AssumeToAssert         = new Dictionary <Function, Function>();

            program.TopLevelDeclarations.OfType <Implementation>()
            .Iter(impl =>
            {
                var fassumed  = GetCandidateFunc(CandidateFuncPrefix, impl.Name);
                var fasserted = GetCandidateFunc(CandidateFuncAssertedPrefix, impl.Name);
                CandidateFuncsAssumed.Add(impl.Name, fassumed);
                CandidateFuncsAsserted.Add(impl.Name, fasserted);
                AssumeToAssert.Add(fassumed, fasserted);
            });


            // Tag the ensures so we can keep track of them
            var iterimpls = program.TopLevelDeclarations.OfType <Implementation>().ToList();

            iterimpls.Iter(impl => InstrumentEnsures(program, impl, CandidateFuncsAssumed[impl.Name], CandidateConstants));

            //BoogieUtil.PrintProgram(program, "h2.bpl");

            var RewriteAssumedToAssertedAction = new Action <Implementation>(impl =>
            {
                // Rewrite functions that are asserted
                var rewrite = new RewriteFuncs(AssumeToAssert);
                foreach (var blk in impl.Blocks)
                {
                    foreach (var acmd in blk.Cmds.OfType <AssertCmd>())
                    {
                        acmd.Expr = rewrite.VisitExpr(acmd.Expr);
                    }
                }

                var funcs = new HashSet <Function>(CandidateFuncsAssumed.Values);
                // Move call-site constant to the first argument of CandidateFuncs
                foreach (var blk in impl.Blocks)
                {
                    Expr cv = null;
                    // walk backwards
                    for (int i = blk.Cmds.Count - 1; i >= 0; i--)
                    {
                        var acmd = blk.Cmds[i] as AssumeCmd;
                        if (acmd == null)
                        {
                            continue;
                        }

                        if (QKeyValue.FindBoolAttribute(acmd.Attributes, StratifiedVCGenBase.callSiteVarAttr))
                        {
                            cv = acmd.Expr;
                            continue;
                        }

                        InsertControlVar.Apply(acmd.Expr, funcs, cv);
                    }
                }

                //impl.Emit(new TokenTextWriter(Console.Out), 0);
            });

            program.AddTopLevelDeclarations(CandidateFuncsAssumed.Values);
            program.AddTopLevelDeclarations(CandidateFuncsAsserted.Values);

            var callgraph     = BoogieUtil.GetCallGraph(program);
            var impl2Priority = DeterminePriorityOrder(program, callgraph);
            var impls         = new HashSet <string>(impl2Priority.Keys);

            HoudiniStats.Start("VCGen");

            // VC Gen
            var hi = new HoudiniInlining(program, CommandLineOptions.Clo.ProverLogFilePath, CommandLineOptions.Clo.ProverLogFileAppend, RewriteAssumedToAssertedAction);

            HoudiniStats.Stop("VCGen");

            var worklist = new SortedSet <Tuple <int, string> >();

            impl2Priority.Iter(tup => worklist.Add(Tuple.Create(tup.Value, tup.Key)));

            // Current assignment: set of true constants
            // Initially: everything is true
            var assignment = new HashSet <string>(CandidateConstants.Keys);

            var prover   = hi.prover;
            var reporter = new EmptyErrorReporter();

            // assert true to flush all one-time axioms, decls, etc
            prover.Assert(VCExpressionGenerator.True, true);

            HoudiniStats.Start("MainLoop");

            // worklist algorithm
            while (worklist.Any())
            {
                var implName = worklist.First().Item2;
                worklist.Remove(worklist.First());

                if (dbg)
                {
                    Console.WriteLine("Processing " + implName);
                }
                prover.LogComment("Processing " + implName);

                prover.Push();

                var hvc           = new HoudiniVC(hi.implName2StratifiedInliningInfo[implName], impls, assignment);
                var openCallSites = new HashSet <StratifiedCallSite>(hvc.CallSites);
                prover.Assert(hvc.vcexpr, true);

                var candidates = !DualHoudini ? new HashSet <string>(hvc.constantToAssertedExpr.Keys.Where(k => assignment.Contains(k))) :
                                 new HashSet <string>(hvc.constantToAssumedExpr.Select(t => t.Item1).Where(k => assignment.Contains(k)));

                var provedTrue  = new HashSet <string>();
                var provedFalse = new HashSet <string>();
                var idepth      = Math.Max(0, CommandLineOptions.Clo.InlineDepth);

                // iterate over idepth
                while (true)
                {
                    // Part 1: over-approximate
                    var proved = ProveCandidates(prover, hvc.constantToAssertedExpr, hvc.constantToAssumedExpr, candidates.Difference(provedTrue.Union(provedFalse)));
                    provedTrue.UnionWith(proved);
                    if (dbg)
                    {
                        Console.WriteLine("Proved {0} candiates at depth {1}", proved.Count, CommandLineOptions.Clo.InlineDepth - idepth);
                    }

                    if (idepth == 0 || openCallSites.Count == 0)
                    {
                        break;
                    }

                    // Part 2: under-approximate
                    prover.Push();
                    foreach (var cs in openCallSites)
                    {
                        prover.Assert(cs.callSiteExpr, false);
                    }

                    var remaining = candidates.Difference(provedTrue.Union(provedFalse));
                    proved = ProveCandidates(prover, hvc.constantToAssertedExpr, hvc.constantToAssumedExpr, remaining);
                    provedFalse.UnionWith(remaining.Difference(proved));
                    if (dbg)
                    {
                        Console.WriteLine("Disproved {0} candiates at depth {1}", remaining.Difference(proved).Count, CommandLineOptions.Clo.InlineDepth - idepth);
                    }

                    prover.Pop();

                    // resolved all?
                    if (candidates.Difference(provedTrue.Union(provedFalse)).Count == 0)
                    {
                        break;
                    }

                    // Inline one level
                    idepth--;
                    var nextOpenCallSites = new HashSet <StratifiedCallSite>();
                    foreach (var cs in openCallSites)
                    {
                        var callee   = new HoudiniVC(hi.implName2StratifiedInliningInfo[cs.callSite.calleeName], impls, assignment);
                        var calleevc = cs.Attach(callee);
                        prover.Assert(prover.VCExprGen.Implies(cs.callSiteExpr, calleevc), true);
                        nextOpenCallSites.UnionWith(callee.CallSites);
                    }
                    openCallSites = nextOpenCallSites;
                }

                prover.Pop();

                var failed = candidates.Difference(provedTrue);
                assignment.ExceptWith(failed);

                if (failed.Count != 0)
                {
                    // add dependencies back into the worklist
                    if (!DualHoudini)
                    {
                        foreach (var caller in callgraph.Predecessors(implName))
                        {
                            worklist.Add(Tuple.Create(impl2Priority[caller], caller));
                        }
                    }
                    else
                    {
                        foreach (var caller in callgraph.Successors(implName))
                        {
                            worklist.Add(Tuple.Create(impl2Priority[caller], caller));
                        }
                    }
                }
            }

            HoudiniStats.Stop("MainLoop");

            hi.Close();

            return(assignment);
        }
Example #2
0
        // Prove candidates that hold (using an over-approximation, at the current inline depth).
        // Return the set of candidates proved correct
        static HashSet <string> ProveCandidates(ProverInterface prover, Dictionary <string, VCExpr> constantToAssertedExpr, List <Tuple <string, VCExpr, VCExpr> > constantToAssumedExpr, HashSet <string> candidates)
        {
            var remaining = new HashSet <string>(candidates);
            var reporter  = new EmptyErrorReporter();
            var failed    = new HashSet <string>();

            // for dual houdini, we have to iterate once around to the loop
            // even if remaining is empty
            bool secondtry = false;

            while (true)
            {
                remaining.ExceptWith(failed);

                if (remaining.Count == 0 && (!DualHoudini || secondtry))
                {
                    break;
                }

                if (remaining.Count == 0)
                {
                    secondtry = true;
                }
                else
                {
                    secondtry = false;
                }

                HoudiniStats.ProverCount++;
                HoudiniStats.Start("ProverTime");

                prover.Push();

                var nameToCallSiteVar           = new Dictionary <string, VCExprVar>();
                var callSiteVarToConstantToExpr = new Dictionary <string, Dictionary <string, VCExpr> >();

                if (!DualHoudini)
                {
                    // assert post
                    VCExpr toassert = VCExpressionGenerator.True;
                    foreach (var k in remaining)
                    {
                        toassert = prover.VCExprGen.And(toassert, constantToAssertedExpr[k]);
                    }

                    prover.Assert(toassert, false);
                }
                else
                {
                    // assume post of callees
                    foreach (var tup in constantToAssumedExpr)
                    {
                        if (!remaining.Contains(tup.Item1))
                        {
                            continue;
                        }

                        var csVar = tup.Item2 as VCExprVar;
                        Debug.Assert(csVar != null);
                        if (!nameToCallSiteVar.ContainsKey(csVar.ToString()))
                        {
                            nameToCallSiteVar.Add(csVar.ToString(), csVar);
                        }

                        if (!callSiteVarToConstantToExpr.ContainsKey(csVar.ToString()))
                        {
                            callSiteVarToConstantToExpr.Add(csVar.ToString(), new Dictionary <string, VCExpr>());
                        }
                        callSiteVarToConstantToExpr[csVar.ToString()].Add(tup.Item1, tup.Item3);
                    }

                    foreach (var tup in callSiteVarToConstantToExpr)
                    {
                        var expr = VCExpressionGenerator.False;
                        tup.Value.Values.Iter(e => expr = prover.VCExprGen.Or(expr, e));
                        prover.Assert(prover.VCExprGen.Implies(nameToCallSiteVar[tup.Key], expr), true);
                    }
                }

                Dictionary <string, VCExprVar> recordingBool = null;
                if (RobustAgainstEvaluate)
                {
                    recordingBool = new Dictionary <string, VCExprVar>();
                    VCExpr torecord = VCExpressionGenerator.True;
                    foreach (var k in remaining)
                    {
                        var b = prover.VCExprGen.Variable("recordingVar_" + k, Microsoft.Boogie.Type.Bool);
                        recordingBool.Add(k, b);
                        torecord = prover.VCExprGen.And(torecord, prover.VCExprGen.Eq(b, constantToAssertedExpr[k]));
                    }
                    prover.Assert(torecord, true);
                }

                prover.Check();
                var outcome = prover.CheckOutcomeCore(reporter);

                // check which ones failed
                if (outcome == ProverInterface.Outcome.Invalid || outcome == ProverInterface.Outcome.Undetermined)
                {
                    var removed = 0;
                    if (!DualHoudini)
                    {
                        foreach (var k in remaining)
                        {
                            var b = recordingBool == null ? (bool)prover.Evaluate(constantToAssertedExpr[k])
                                : (bool)prover.Evaluate(recordingBool[k]);

                            if (!b)
                            {
                                failed.Add(k);
                                if (dbg)
                                {
                                    Console.WriteLine("Failed: {0}", k);
                                }
                                removed++;
                            }
                        }
                    }
                    else
                    {
                        foreach (var tup in callSiteVarToConstantToExpr)
                        {
                            if (!(bool)prover.Evaluate(nameToCallSiteVar[tup.Key]))
                            {
                                continue;
                            }
                            // call site taken
                            foreach (var tup2 in tup.Value)
                            {
                                if ((bool)prover.Evaluate(tup2.Value))
                                {
                                    failed.Add(tup2.Key);
                                    if (dbg)
                                    {
                                        Console.WriteLine("Failed: {0}", tup2.Key);
                                    }
                                    removed++;
                                }
                            }
                        }
                        if (removed == 0)
                        {
                            throw new DualHoudiniFail("Nothing to drop");
                        }
                    }
                    Debug.Assert(removed != 0);
                    //if(dbg) Console.WriteLine("Query {0}: Invalid, {1} removed", HoudiniStats.ProverCount, removed);
                }

                HoudiniStats.Stop("ProverTime");
                prover.Pop();


                if (outcome == ProverInterface.Outcome.TimeOut || outcome == ProverInterface.Outcome.OutOfMemory)
                {
                    if (DualHoudini)
                    {
                        throw new DualHoudiniFail("Timeout");
                    }
                    failed.UnionWith(remaining);
                    break;
                }

                if (outcome == ProverInterface.Outcome.Valid)
                {
                    //if(dbg) Console.WriteLine("Query {0}: Valid", HoudiniStats.ProverCount);
                    break;
                }
            }

            remaining.ExceptWith(failed);

            return(remaining);
        }