org.sosy_lab.cpachecker.cpa.bounds.BoundsTransferRelation.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.cpa.bounds.BoundsTransferRelation.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 org.sosy_lab.cpachecker.cpa.bounds;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.model.FunctionCallEdge;
import org.sosy_lab.cpachecker.cfa.model.FunctionReturnEdge;
import org.sosy_lab.cpachecker.core.defaults.SingleEdgeTransferRelation;
import org.sosy_lab.cpachecker.core.interfaces.AbstractState;
import org.sosy_lab.cpachecker.core.interfaces.Precision;
import org.sosy_lab.cpachecker.cpa.callstack.CallstackState;
import org.sosy_lab.cpachecker.exceptions.CPATransferException;
import org.sosy_lab.cpachecker.util.LoopStructure;
import org.sosy_lab.cpachecker.util.LoopStructure.Loop;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

public class BoundsTransferRelation extends SingleEdgeTransferRelation {

    private Multimap<CFANode, Loop> loopHeads = null;

    private final int maxLoopIterations;
    private final int maxRecursionDepth;
    private final int loopIterationsBeforeAbstraction;

    public BoundsTransferRelation(int pLoopIterationsBeforeAbstraction, int pMaxLoopIterations,
            int pMaxRecursionDepth, LoopStructure pLoops) {

        loopIterationsBeforeAbstraction = pLoopIterationsBeforeAbstraction;
        this.maxLoopIterations = pMaxLoopIterations;
        this.maxRecursionDepth = pMaxRecursionDepth;

        ImmutableMultimap.Builder<CFANode, Loop> heads = ImmutableMultimap.builder();

        for (Loop l : pLoops.getAllLoops()) {
            for (CFANode h : l.getLoopHeads()) {
                heads.put(h, l);
            }
        }
        loopHeads = heads.build();
    }

    @Override
    public Collection<? extends AbstractState> getAbstractSuccessorsForEdge(AbstractState pElement,
            Precision pPrecision, CFAEdge pCfaEdge) throws CPATransferException {

        BoundsState e = (BoundsState) pElement;

        if (e.isStopState()) {
            return Collections.emptySet();
        }

        if (pCfaEdge instanceof FunctionCallEdge) {
            // such edges do never change loop stack status
            return Collections.singleton(pElement);
        }

        if (pCfaEdge instanceof FunctionReturnEdge) {
            e = e.returnFromFunction();
        }

        CFANode loc = pCfaEdge.getSuccessor();

        Collection<Loop> loops = loopHeads.get(loc);
        assert loops.size() <= 1;
        if (!loops.isEmpty()) {
            for (Loop loop : loops) {
                e = e.enter(loop, loopIterationsBeforeAbstraction);
            }
            if ((maxLoopIterations > 0) && e.getDeepestIteration() > maxLoopIterations) {
                e = e.stopIt();
            }
        }

        if (maxRecursionDepth > 0 && e.getDeepestRecursion() > maxRecursionDepth) {
            e = e.stopRec();
        }

        return Collections.singleton(e);
    }

    @Override
    public Collection<? extends AbstractState> strengthen(AbstractState pState, List<AbstractState> pOtherStates,
            CFAEdge pCfaEdge, Precision pPrecision) {

        BoundsState state = (BoundsState) pState;

        for (CallstackState callstackState : FluentIterable.from(pOtherStates).filter(CallstackState.class)) {
            int recursionDepth = getRecursionDepth(callstackState);
            if (recursionDepth > state.getDeepestRecursion()) {
                assert recursionDepth == getDeepestRecursion(callstackState);
                state = state.setDeepestRecursion(recursionDepth);
            }
            state = state.setCurrentFunction(callstackState.getCurrentFunction());
            if (state.getReturnFromCounter() > state.getDeepestRecursion()) {
                state = state.setDeepestRecursion(state.getReturnFromCounter());
            }
        }
        return state.equals(pState) ? null : Collections.singleton(state);
    }

    private static final int getRecursionDepth(CallstackState pCallstackState) {
        int depth = 0;
        CallstackState state = pCallstackState;
        String function = pCallstackState.getCurrentFunction();
        while (state != null) {
            if (state.getCurrentFunction().equals(function)) {
                ++depth;
            }
            state = state.getPreviousState();
        }
        return depth;
    }

    private static final int getDeepestRecursion(CallstackState pCallstackState) {
        Map<String, Integer> depths = Maps.newHashMap();
        CallstackState state = pCallstackState;
        int deepest = 0;
        while (state != null) {
            String function = state.getCurrentFunction();
            Integer currentDepth = depths.get(function);
            currentDepth = currentDepth == null ? 1 : currentDepth + 1;
            if (currentDepth > deepest) {
                deepest = currentDepth;
            }
            depths.put(function, currentDepth);
            state = state.getPreviousState();
        }
        return deepest;
    }
}