edu.buaa.satla.analysis.cfa.CFACheck.java Source code

Java tutorial

Introduction

Here is the source code for edu.buaa.satla.analysis.cfa.CFACheck.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package edu.buaa.satla.analysis.cfa;

import static edu.buaa.satla.analysis.util.CFAUtils.*;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;

import edu.buaa.satla.analysis.cfa.ast.FileLocation;
import edu.buaa.satla.analysis.cfa.model.AssumeEdge;
import edu.buaa.satla.analysis.cfa.model.CFAEdge;
import edu.buaa.satla.analysis.cfa.model.CFANode;
import edu.buaa.satla.analysis.cfa.model.CFATerminationNode;
import edu.buaa.satla.analysis.cfa.model.FunctionEntryNode;
import edu.buaa.satla.analysis.cfa.model.FunctionExitNode;
import edu.buaa.satla.analysis.cfa.model.c.CFunctionCallEdge;
import edu.buaa.satla.analysis.cfa.model.c.CFunctionSummaryStatementEdge;
import edu.buaa.satla.analysis.util.CFAUtils;

public class CFACheck {

    /**
     * Traverse the CFA and run a series of checks at each node
     * @param cfa Node to start traversal from
     * @param nodes Optional set of all nodes in the CFA (may be null)
     * @param pruned Whether the CFA was pruned and may be incomplete.
     */
    public static boolean check(FunctionEntryNode cfa, Collection<CFANode> nodes, boolean pruned) {

        Set<CFANode> visitedNodes = new HashSet<>();
        Deque<CFANode> waitingNodeList = new ArrayDeque<>();

        waitingNodeList.add(cfa);
        while (!waitingNodeList.isEmpty()) {
            CFANode node = waitingNodeList.poll();

            if (visitedNodes.add(node)) {
                Iterables.addAll(waitingNodeList, CFAUtils.successorsOf(node));
                Iterables.addAll(waitingNodeList, CFAUtils.predecessorsOf(node)); // just to be sure to get ALL nodes.

                // The actual checks
                isConsistent(node);
                checkEdgeCount(node, pruned);
            }
        }

        if (nodes != null) {
            if (!visitedNodes.equals(nodes)) {
                assert false : "\nNodes in CFA but not reachable through traversal: "
                        + Iterables.transform(Sets.difference(new HashSet<>(nodes), visitedNodes), DEBUG_FORMAT)
                        + "\nNodes reached that are not in CFA: "
                        + Iterables.transform(Sets.difference(visitedNodes, new HashSet<>(nodes)), DEBUG_FORMAT);
            }
        }
        return true;
    }

    private static final Function<CFANode, String> DEBUG_FORMAT = new Function<CFANode, String>() {
        @Override
        public String apply(CFANode node) {
            if (node == null) {
                // nothing useful to do. this line only exists, because input for Function.apply might be NULL.
                return "NULL";
            }
            // try to get some information about location from node
            FileLocation location = FileLocation.DUMMY;
            if (node.getNumEnteringEdges() > 0) {
                location = node.getEnteringEdge(0).getFileLocation();
            } else if (node.getNumLeavingEdges() > 0) {
                location = node.getLeavingEdge(0).getFileLocation();
            }
            return node.getFunctionName() + ":" + node + " (" + location + ")";
        }
    };

    /**
     * Verify that the number of edges and their types match.
     * @param pNode Node to be checked
     */
    private static void checkEdgeCount(CFANode pNode, boolean pruned) {

        // check entering edges
        int entering = pNode.getNumEnteringEdges();
        if (entering == 0) {
            assert (pNode instanceof FunctionEntryNode) : "Dead code: node " + DEBUG_FORMAT.apply(pNode)
                    + " has no incoming edges (successors are "
                    + CFAUtils.successorsOf(pNode).transform(DEBUG_FORMAT) + ")";
        }

        // check leaving edges
        if (!(pNode instanceof FunctionExitNode)) {
            switch (pNode.getNumLeavingEdges()) {
            case 0:
                if (!pruned) {
                    // not possible to check this when CFA was pruned
                    assert pNode instanceof CFATerminationNode : "Dead end at node " + DEBUG_FORMAT.apply(pNode);
                }
                break;

            case 1:
                CFAEdge edge = pNode.getLeavingEdge(0);
                if (!pruned) {
                    // not possible to check this when CFA was pruned
                    assert !(edge instanceof AssumeEdge) : "AssumeEdge does not appear in pair at node "
                            + DEBUG_FORMAT.apply(pNode);
                }
                assert !(edge instanceof CFunctionSummaryStatementEdge) : "CFunctionSummaryStatementEdge is not paired with CFunctionCallEdge at node "
                        + DEBUG_FORMAT.apply(pNode);
                break;

            case 2:
                CFAEdge edge1 = pNode.getLeavingEdge(0);
                CFAEdge edge2 = pNode.getLeavingEdge(1);
                //relax this assumption for summary edges
                if (edge1 instanceof CFunctionSummaryStatementEdge) {
                    assert edge2 instanceof CFunctionCallEdge : "CFunctionSummaryStatementEdge is not paired with CFunctionCallEdge at node "
                            + DEBUG_FORMAT.apply(pNode);
                } else if (edge2 instanceof CFunctionSummaryStatementEdge) {
                    assert edge1 instanceof CFunctionCallEdge : "CFunctionSummaryStatementEdge is not paired with CFunctionCallEdge at node "
                            + DEBUG_FORMAT.apply(pNode);
                } else {
                    assert (edge1 instanceof AssumeEdge)
                            && (edge2 instanceof AssumeEdge) : "Branching without conditions at node "
                                    + DEBUG_FORMAT.apply(pNode); // TODO Ask for permission

                    AssumeEdge ae1 = (AssumeEdge) edge1;
                    AssumeEdge ae2 = (AssumeEdge) edge2;
                    assert ae1.getTruthAssumption() != ae2.getTruthAssumption() : "Inconsistent branching at node "
                            + DEBUG_FORMAT.apply(pNode);
                }
                break;

            default:
                assert false : "Too much branching at node " + DEBUG_FORMAT.apply(pNode);
            }
        }
    }

    /**
     * Check all entering and leaving edges for corresponding leaving/entering edges
     * at predecessor/successor nodes, and that there are no duplicates
     * @param pNode Node to be checked
     */
    private static void isConsistent(CFANode pNode) {
        Set<CFAEdge> seenEdges = new HashSet<>();
        Set<CFANode> seenNodes = new HashSet<>();

        for (CFAEdge edge : leavingEdges(pNode)) {
            if (!seenEdges.add(edge)) {
                assert false : "Duplicate leaving edge " + edge + " on node " + DEBUG_FORMAT.apply(pNode);
            }

            CFANode successor = edge.getSuccessor();
            if (!seenNodes.add(successor)) {
                assert false : "Duplicate successor " + successor + " for node " + DEBUG_FORMAT.apply(pNode);
            }

            boolean hasEdge = enteringEdges(successor).contains(edge);
            assert hasEdge : "Node " + DEBUG_FORMAT.apply(pNode) + " has leaving edge " + edge + ", but pNode "
                    + DEBUG_FORMAT.apply(successor) + " does not have this edge as entering edge!";
        }

        seenEdges.clear();
        seenNodes.clear();

        for (CFAEdge edge : enteringEdges(pNode)) {
            if (!seenEdges.add(edge)) {
                assert false : "Duplicate entering edge " + edge + " on node " + DEBUG_FORMAT.apply(pNode);
            }

            CFANode predecessor = edge.getPredecessor();
            if (!seenNodes.add(predecessor)) {
                assert false : "Duplicate predecessor " + predecessor + " for node " + DEBUG_FORMAT.apply(pNode);
            }

            boolean hasEdge = leavingEdges(predecessor).contains(edge);
            assert hasEdge : "Node " + DEBUG_FORMAT.apply(pNode) + " has entering edge " + edge + ", but pNode "
                    + DEBUG_FORMAT.apply(pNode) + " does not have this edge as leaving edge!";
        }
    }
}