Exemple #1
0
        public InstrumentationPolicy(int K, HashSet <string> glob, HashSet <string> procsWithImpl, HashSet <string> asyncProcs, HashSet <Tuple <string, string> > recursiveProcs, ConcurrencyMode mode)
        {
            executionContextBound = K;
            globalsToInstrument   = glob;
            this.procsWithImpl    = procsWithImpl;
            this.asyncProcs       = asyncProcs;
            this.recursiveProcs   = recursiveProcs;
            this.mode             = mode;

            atomicBeginProcName    = LanguageSemantics.atomicBeginProcName();
            atomicEndProcName      = LanguageSemantics.atomicEndProcName();
            assertNotReachableName = LanguageSemantics.assertNotReachableName();
            getThreadIDName        = LanguageSemantics.getThreadIDName();
        }
Exemple #2
0
        public override CBAProgram runCBAPass(CBAProgram p)
        {
            if (p.mode == ConcurrencyMode.FixedContext)
            {
                InstrumentationConfig.addRaiseException = false;
            }

            // Step1: Gather program information
            pinfo = new ProgramInfo(p.mainProcName, p, LanguageSemantics.assertNotReachableName());

            TidArithmetic.reset();
            if (pinfo.threadIdType.IsBv)
            {
                TidArithmetic.useIntArithmetic = false;
                p.AddTopLevelDeclaration(TidArithmetic.getBvAdd());
                p.AddTopLevelDeclaration(TidArithmetic.getBvGt());
            }
            else
            {
                TidArithmetic.useIntArithmetic = true;
            }

            // Step2: Set up a variable manager
            vmgr = new VariableManager(pinfo);

            // Step3: Set up the instrumentation policy

            // The globals not to instrument are:
            //   -- ones not modified by any procedure
            //   -- ones not shared
            //   -- ones to treat as thread-local
            HashSet <string> globalsToInstrument = new HashSet <string>();

            foreach (var g in pinfo.declaredGlobals)
            {
                string name = g.Key;
                if (!pinfo.modifiedGlobals.ContainsKey(name))
                {
                    continue;
                }
                if (!LanguageSemantics.isShared(name))
                {
                    continue;
                }
                if (pinfo.threadLocalGlobals.ContainsKey(name))
                {
                    continue;
                }
                globalsToInstrument.Add(name);
            }

            var rprocs = findRecursiveProcs(p);

            //foreach (var be in rprocs) Console.WriteLine("{0} -> {1}", be.Item1, be.Item2);

            policy =
                new InstrumentationPolicy(p.contextBound, globalsToInstrument, pinfo.procsWithImplementation, pinfo.asyncProcs, rprocs, p.mode);

            //policy.print(Log.getWriter(Log.Debug));

            // Step4: Split program declarations based on the instrumentation policy

            // skipping this step (not needed for basic CBA reduction)

            // Step5: Carry out the K-split instrumentation
            inst = new Instrumenter(policy, vmgr, pinfo, tinfo_instrument);
            List <Declaration> newDecls = inst.instrument(p.TopLevelDeclarations.ToList());

            foreach (var trp in inst.blocksWithFixedK)
            {
                blockExecutionContextMap.Add(trp.fst + "::" + trp.snd, trp.trd);
            }

            // Step6: Instrument main with initialization and the Checker
            Implementation mainProcImpl = BoogieUtil.findProcedureImpl(newDecls, p.mainProcName);

            inst.instrumentGivenMainImpl(mainProcImpl);

            // Step7: Instrument Async calls
            bool instrumentedAsync     = false;
            InstrumentAsyncCalls ainst = new InstrumentAsyncCalls(vmgr, pinfo, tinfo_async);

            foreach (var decl in newDecls)
            {
                if (decl is Implementation)
                {
                    ainst.VisitImplementation(decl as Implementation);
                    instrumentedAsync = instrumentedAsync || ainst.hasAsync;
                }
            }

            if (!instrumentedAsync)
            {
                Log.WriteLine(Log.Debug, "Warning: Did not find any async call");
            }

            // Step8: Set entrypoint
            mainProcImpl.AddAttribute("entrypoint");

            // Step9: Add new variable declarations
            newDecls.AddRange(vmgr.getNewDeclarations(policy.executionContextBound));
            newDecls.AddRange(BoogieAstFactory.newDecls);
            BoogieAstFactory.newDecls.Clear();

            // Thats it.

            Program ret = new Program();

            ret.TopLevelDeclarations = newDecls;

            if (InstrumentationConfig.printInstrumented)
            {
                // Re-resolve ret
                ProgTransformation.PersistentProgram tprog = new ProgTransformation.PersistentProgram(ret);
                var instrumented = tprog.getProgram();

                // Re-do the modsets -- make them as concise as possible.
                BoogieUtil.DoModSetAnalysis(instrumented);

                // Temporary fix for Boogie's bug while inlining calls
                // that have don't care expressions.
                RewriteCallDontCares rdc = new RewriteCallDontCares();
                rdc.VisitProgram(instrumented);

                BoogieUtil.PrintProgram(instrumented, InstrumentationConfig.instrumentedFile);

                throw new NormalExit("Printed " + InstrumentationConfig.instrumentedFile);
            }

            // Resolve the program (Do not typecheck because that does inlining).
            //BoogieUtil.PrintProgram(ret, "instrumented.bpl");
            //ret = BoogieUtil.ReadAndOnlyResolve("instrumented.bpl");
            if (p.mode == ConcurrencyMode.FixedContext)
            {
                InstrumentationConfig.addRaiseException = true;
            }

            p = new CBAProgram(ret, p.mainProcName, p.contextBound);

            return(p);
        }
Exemple #3
0
        // Return the set of all procedures that can trasitively reach
        // an assertion, or another procedure's requires
        private HashSet <string> procsWithAssertions(Program program)
        {
            // Build a call graph and mark procedures with assertions in them
            Dictionary <string, HashSet <string> > callSucc = new Dictionary <string, HashSet <string> >();
            Dictionary <string, HashSet <string> > callPred = new Dictionary <string, HashSet <string> >();
            HashSet <string> hasAssert = new HashSet <string>();

            foreach (var decl in program.TopLevelDeclarations)
            {
                if (decl is Implementation)
                {
                    var impl = decl as Implementation;
                    callSucc.Add(impl.Name, new HashSet <string>());

                    foreach (var block in impl.Blocks)
                    {
                        foreach (var cmd in block.Cmds)
                        {
                            if (cmd is AssertCmd)
                            {
                                hasAssert.Add(impl.Name);
                            }
                            if (cmd is CallCmd)
                            {
                                var ccmd = cmd as CallCmd;
                                callSucc[impl.Name].Add(ccmd.Proc.Name);
                                if (LanguageSemantics.assertNotReachableName() == ccmd.Proc.Name)
                                {
                                    hasAssert.Add(impl.Name);
                                }
                            }
                        }
                    }
                }
            }

            // Build the predecessor map
            foreach (var kvp in callSucc)
            {
                if (!callPred.ContainsKey(kvp.Key))
                {
                    callPred.Add(kvp.Key, new HashSet <string>());
                }

                foreach (var tgt in kvp.Value)
                {
                    if (!callPred.ContainsKey(tgt))
                    {
                        callPred.Add(tgt, new HashSet <string>());
                    }
                    callPred[tgt].Add(kvp.Key);
                }
            }

            // Requires become asserts on the caller.
            // (No need to bother about ensures because if we're not interested
            // in a procedure, then we don't care about verifying its ensures either)
            foreach (var decl in program.TopLevelDeclarations)
            {
                if (decl is Procedure)
                {
                    var proc = decl as Procedure;

                    foreach (Requires re in proc.Requires)
                    {
                        if (re.Free)
                        {
                            continue;
                        }
                        if (!callPred.ContainsKey(proc.Name))
                        {
                            continue;
                        }

                        foreach (var pred in callPred[proc.Name])
                        {
                            hasAssert.Add(pred);
                        }
                    }
                }
            }

            // Now propagate hasAssert to all its predecessors
            var done = false;

            while (!done)
            {
                var newproc = new HashSet <string>();
                foreach (var proc in hasAssert)
                {
                    foreach (var pred in callPred[proc])
                    {
                        newproc.Add(pred);
                    }
                }

                if (newproc.Any(x => !hasAssert.Contains(x)))
                {
                    hasAssert.UnionWith(newproc);
                }
                else
                {
                    done = true;
                }
            }
            return(hasAssert);
        }