예제 #1
0
        /// <summary>
        /// Starting from the 0-index "split_here" annotation in begin, verifies until it reaches a subsequent "split_here" annotation
        /// Returns a list of blocks where all code not verified has asserts converted into assumes
        /// </summary>
        /// <param name="blocks">Implementation's collection of blocks</param>
        /// <param name="begin">Block containing the first split_here from which to start verifying</param>
        /// <param name="beginSplitId">0-based ID of the "split_here" annotation within begin at which to start verifying</param>
        /// <param name="blockInternalSplit">True if the entire split is contained within block begin</param>
        /// <param name="endPoints">Set of all blocks containing a "split_here" annotation</param>
        /// <returns></returns>
        // Note: Current implementation may over report errors.
        //       For example, if the control flow graph is a diamond (e.g., A -> B, C, B->D, C->D),
        //       and there is a split in B and an error in D, then D will be verified twice and hence report the error twice.
        //       Best solution may be to memoize blocks that have been fully verified and be sure not to verify them again
        private static List <Block> DoManualSplit(List <Block> blocks, Block begin, int beginSplitId,
                                                  bool blockInternalSplit, IEnumerable <Block> endPoints)
        {
            // Compute the set of blocks reachable from begin but not included in endPoints.  These will be verified in their entirety.
            var blocksToVerifyEntirely = new HashSet <Block>();
            var reachableEndPoints     =
                new HashSet <Block>(); // Reachable end points will be verified up to their first split point
            var todo = new Stack <Block>();

            todo.Push(begin);
            while (todo.Count > 0)
            {
                var currentBlock = todo.Pop();
                if (blocksToVerifyEntirely.Contains(currentBlock))
                {
                    continue;
                }
                blocksToVerifyEntirely.Add(currentBlock);
                var exit = currentBlock.TransferCmd as GotoCmd;
                if (exit != null)
                {
                    foreach (Block targetBlock in exit.labelTargets)
                    {
                        if (!endPoints.Contains(targetBlock))
                        {
                            todo.Push(targetBlock);
                        }
                        else
                        {
                            reachableEndPoints.Add(targetBlock);
                        }
                    }
                }
            }

            blocksToVerifyEntirely.Remove(begin);

            // Convert assumes to asserts in "unreachable" blocks, including portions of blocks containing "split_here"
            var newBlocks        = new List <Block>(blocks.Count()); // Copies of the original blocks
            var duplicator       = new Duplicator();
            var oldToNewBlockMap =
                new Dictionary <Block, Block>(blocks.Count()); // Maps original blocks to their new copies in newBlocks

            foreach (var currentBlock in blocks)
            {
                var newBlock = (Block)duplicator.VisitBlock(currentBlock);
                oldToNewBlockMap[currentBlock] = newBlock;
                newBlocks.Add(newBlock);

                if (!blockInternalSplit && blocksToVerifyEntirely.Contains(currentBlock))
                {
                    continue; // All reachable blocks must be checked in their entirety, so don't change anything
                }
                // Otherwise, we only verify a portion of the current block, so we'll need to look at each of its commands

                // !verify -> convert assert to assume
                var verify =
                    (currentBlock == begin &&
                     beginSplitId == -1
                    ) || // -1 tells us to start verifying from the very beginning (i.e., there is no split in the begin block)
                    (
                        reachableEndPoints
                        .Contains(currentBlock) && // This endpoint is reachable from begin, so we verify until we hit the first split point
                        !blockInternalSplit); // Don't bother verifying if all of the splitting is within the begin block
                var newCmds        = new List <Cmd>();
                var splitHereCount = 0;

                foreach (Cmd c in currentBlock.Cmds)
                {
                    var p = c as PredicateCmd;
                    if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here"))
                    {
                        if (currentBlock == begin)
                        {
                            // Verify everything between the beginSplitId we were given and the next split
                            if (splitHereCount == beginSplitId)
                            {
                                verify = true;
                            }
                            else if (splitHereCount == beginSplitId + 1)
                            {
                                verify = false;
                            }
                        }
                        else
                        {
                            // We're in an endpoint so we stop verifying as soon as we hit a "split_here"
                            verify = false;
                        }

                        splitHereCount++;
                    }

                    var asrt = c as AssertCmd;
                    if (verify || asrt == null)
                    {
                        newCmds.Add(c);
                    }
                    else
                    {
                        newCmds.Add(VCGen.AssertTurnedIntoAssume(asrt));
                    }
                }

                newBlock.Cmds = newCmds;
            }

            // Patch the edges between the new blocks
            foreach (var oldBlock in blocks)
            {
                if (oldBlock.TransferCmd is ReturnCmd)
                {
                    continue;
                }

                var gotoCmd         = (GotoCmd)oldBlock.TransferCmd;
                var newLabelTargets = new List <Block>(gotoCmd.labelTargets.Count());
                var newLabelNames   = new List <string>(gotoCmd.labelTargets.Count());
                foreach (var target in gotoCmd.labelTargets)
                {
                    newLabelTargets.Add(oldToNewBlockMap[target]);
                    newLabelNames.Add(oldToNewBlockMap[target].Label);
                }

                oldToNewBlockMap[oldBlock].TransferCmd = new GotoCmd(gotoCmd.tok, newLabelNames, newLabelTargets);
            }

            return(newBlocks);
        }
예제 #2
0
        public static VerificationResult VerifyImplementation(VC.ConditionGeneration vcgen, Implementation impl, Program prog, out SDiffCounterexamples cex, out List <Model> errModelList)
        {
            VerifyImplCleanup vic;

            vic = new VerifyImplCleanup();
            vic.Visit(prog);


            cex          = null;
            errModelList = null;

            if (impl == null)
            {
                Log.Out(Log.Urgent, "VerifyImplementation saw null implementation");
                return(VerificationResult.Unknown);
            }

            //Log.Out(Log.Verifier, "Verifying implementation " + impl.Name);

            List <Counterexample> errors;
            List <Model>          errorsModel;
            VerificationResult    sdoutcome = VerificationResult.Unknown;

            VC.VCGen.Outcome outcome;

            //Log.Out(Log.Verifier, "Saving implementation before Boogie preprocessing");
            var duper            = new Duplicator();
            var imperativeBlocks = new Dictionary <string, Block>();

            foreach (Block b in impl.Blocks)
            {
                //new: to avoid repeated blocks (MYSTERY)
                if (!imperativeBlocks.ContainsKey(b.Label))
                {
                    imperativeBlocks.Add(b.Label, duper.VisitBlock(b));
                }
            }

            try
            {
                var start = DateTime.Now;

                //outcome = vcgen.VerifyImplementation(impl, prog, out errors);
                outcome      = vcgen.VerifyImplementation(impl, /*prog,*/ out errors, out errorsModel);
                errModelList = errorsModel;

                var end = DateTime.Now;

                TimeSpan elapsed = end - start;
                Console.WriteLine(string.Format("  [{0} s]  ", elapsed.TotalSeconds));
            }
            catch (VC.VCGenException e)
            {
                Log.Out(Log.Error, "Error BP5010: {0}  Encountered in implementation {1}: " + e.Message);
                errors  = null;
                outcome = VC.VCGen.Outcome.Inconclusive;
            }
            catch (UnexpectedProverOutputException upo)
            {
                Log.Out(Log.Error, "Advisory: {0} SKIPPED because of internal error: unexpected prover output: {1}" + upo.Message);
                errors  = null;
                outcome = VC.VCGen.Outcome.Inconclusive;
            }
            catch (Exception e)
            {
                Log.Out(Log.Error, "Unknown error somewhere in verification: ");
                Log.Out(Log.Error, e.ToString());
                return(VerificationResult.Unknown);
            }

            switch (outcome)
            {
            case VC.VCGen.Outcome.Correct:
                sdoutcome = VerificationResult.Verified;
                break;

            case VC.VCGen.Outcome.Errors:
                sdoutcome = VerificationResult.Error;
                break;

            case VC.VCGen.Outcome.Inconclusive:
                sdoutcome = VerificationResult.Inconclusive;
                break;

            case VC.VCGen.Outcome.OutOfMemory:
                sdoutcome = VerificationResult.OutOfMemory;
                break;

            case VC.VCGen.Outcome.TimedOut:
                sdoutcome = VerificationResult.TimeOut;
                break;
            }

            Log.Out(Log.Normal, outcome.ToString());

            var eqVarName = "";

            if (errors != null && errors.Count() == 1)
            {
                //eqVarName = errors[0];
            }

            Log.Out(Log.Verifier, (errors == null ? 0 : errors.Count) + " counterexamples...");

            if (errors != null)
            {
                cex = new SDiffCounterexamples();
                for (int i = 0; i < errors.Count; i++)
                {
                    if (Options.EnumerateAllPaths)
                    {
                        //just remove any time for this option
                        cex.Add(new SDiffCounterexample(errors[i], null, impl));
                        continue;
                    }

                    //reconstruct trace in terms of imperative blocks
                    var trace = ReconstructImperativeTrace(errors[i].Trace, imperativeBlocks);
                    if (SymEx.TraceValidator.Validate(trace))
                    {
                        Log.Out(Log.Cex, "Trace " + "[" + i + "]:");
                        Log.Out(Log.Cex, "Validating...");
                        Log.Out(Log.Cex, "Trace is not complete! Printing..");
                        SDiff.SymEx.CexDumper.PrintTrace(trace);
                        continue;
                    }
                    else
                    {
                        //Log.Out(Log.Cex, "Trace OK");
                        if (Options.DumpValidTraces)
                        {
                            SDiff.SymEx.CexDumper.PrintTrace(trace);
                        }
                    }

                    cex.Add(new SDiffCounterexample(errors[i], trace, impl));
                }
            }

            return(sdoutcome);
        }