Beispiel #1
0
        List <Cmd> SliceCmds(Block b)
        {
            Contract.Requires(b != null);
            Contract.Ensures(Contract.Result <List <Cmd> >() != null);

            List <Cmd> seq = b.Cmds;

            Contract.Assert(seq != null);
            if (!doingSlice && !ShouldAssumize(b))
            {
                return(seq);
            }
            List <Cmd> res = new List <Cmd>();

            foreach (Cmd c in seq)
            {
                Contract.Assert(c != null);
                AssertCmd a         = c as AssertCmd;
                Cmd       theNewCmd = c;
                bool      swap      = false;
                if (a != null)
                {
                    if (doingSlice)
                    {
                        double cost  = AssertionCost(a);
                        bool   first = (sliceLimit - cost) >= 0 || sliceInitialLimit == sliceLimit;
                        sliceLimit -= cost;
                        swap        = slicePos == first;
                    }
                    else if (assertToAssume)
                    {
                        swap = true;
                    }
                    else
                    {
                        Contract.Assert(false);
                        throw new cce.UnreachableException();
                    }

                    if (swap)
                    {
                        theNewCmd = VCGen.AssertTurnedIntoAssume(a);
                    }
                }

                res.Add(theNewCmd);
            }

            return(res);
        }
Beispiel #2
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);
        }