org.sosy_lab.cpachecker.cpa.andersen.AndersenTransferRelation.java Source code

Java tutorial

Introduction

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

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;

import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.ast.c.CAssignment;
import org.sosy_lab.cpachecker.cfa.ast.c.CCastExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CExpressionStatement;
import org.sosy_lab.cpachecker.cfa.ast.c.CFunctionCallExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CFunctionCallStatement;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CInitializer;
import org.sosy_lab.cpachecker.cfa.ast.c.CInitializerExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CPointerExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CRightHandSide;
import org.sosy_lab.cpachecker.cfa.ast.c.CStatement;
import org.sosy_lab.cpachecker.cfa.ast.c.CUnaryExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CUnaryExpression.UnaryOperator;
import org.sosy_lab.cpachecker.cfa.ast.c.CVariableDeclaration;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.MultiEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CDeclarationEdge;
import org.sosy_lab.cpachecker.cfa.model.c.CStatementEdge;
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.andersen.util.BaseConstraint;
import org.sosy_lab.cpachecker.cpa.andersen.util.ComplexConstraint;
import org.sosy_lab.cpachecker.cpa.andersen.util.SimpleConstraint;
import org.sosy_lab.cpachecker.exceptions.CPATransferException;
import org.sosy_lab.cpachecker.exceptions.UnrecognizedCCodeException;

import com.google.common.collect.Iterables;

public class AndersenTransferRelation extends SingleEdgeTransferRelation {

    private final LogManager logger;

    public AndersenTransferRelation(Configuration pConfig, LogManager pLogger)
            throws InvalidConfigurationException {
        logger = pLogger;
    }

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

        AbstractState successor = null;
        AndersenState andersenState = (AndersenState) pElement;

        // check the type of the edge
        switch (pCfaEdge.getEdgeType()) {

        // if edge is a statement edge, e.g. a = b + c
        case StatementEdge:
            CStatementEdge statementEdge = (CStatementEdge) pCfaEdge;
            successor = handleStatement(andersenState, statementEdge.getStatement(), pCfaEdge);
            break;

        // edge is a declaration edge, e.g. int a;
        case DeclarationEdge:
            CDeclarationEdge declarationEdge = (CDeclarationEdge) pCfaEdge;
            successor = handleDeclaration(andersenState, declarationEdge);
            break;

        // this is an assumption, e.g. if (a == b)
        case AssumeEdge:
            successor = andersenState;
            break;

        case BlankEdge:
            successor = andersenState;
            break;
        case MultiEdge:
            successor = andersenState;
            Iterator<CFAEdge> edgeIterator = ((MultiEdge) pCfaEdge).iterator();
            while (pElement != null && edgeIterator.hasNext()) {
                successor = Iterables
                        .getFirst(getAbstractSuccessorsForEdge(successor, pPrecision, edgeIterator.next()), null);
            }
            break;

        case CallToReturnEdge:
        case FunctionCallEdge:
        case ReturnStatementEdge:
        case FunctionReturnEdge:
        default:
            printWarning(pCfaEdge);
        }

        if (successor == null) {
            return Collections.emptySet();
        } else {
            return Collections.singleton(successor);
        }
    }

    @Override
    public Collection<? extends AbstractState> strengthen(AbstractState pElement, List<AbstractState> pElements,
            CFAEdge pCfaEdge, Precision pPrecision) throws UnrecognizedCCodeException {

        return null;
    }

    private AndersenState handleStatement(AndersenState pElement, CStatement pExpression, CFAEdge pCfaEdge)
            throws UnrecognizedCCodeException {

        // e.g. a = b;
        if (pExpression instanceof CAssignment) {
            return handleAssignment(pElement, (CAssignment) pExpression, pCfaEdge);
        } else if (pExpression instanceof CFunctionCallStatement) {
            return pElement;
        } else if (pExpression instanceof CExpressionStatement) {
            return pElement;
        } else {
            throw new UnrecognizedCCodeException("unknown statement", pCfaEdge, pExpression);
        }
    }

    private AndersenState handleAssignment(AndersenState pElement, CAssignment pAssignExpression, CFAEdge pCfaEdge)
            throws UnrecognizedCCodeException {

        CExpression op1 = pAssignExpression.getLeftHandSide();
        CRightHandSide op2 = pAssignExpression.getRightHandSide();

        if (op1 instanceof CIdExpression) {

            // a = ...

            return handleAssignmentTo(op1.toASTString(), op2, pElement, pCfaEdge);

        } else if (op1 instanceof CPointerExpression && op2 instanceof CIdExpression) {

            // *a = b; complex constraint

            op1 = ((CPointerExpression) op1).getOperand();

            if (op1 instanceof CIdExpression) {

                return pElement.addConstraint(new ComplexConstraint(op2.toASTString(), op1.toASTString(), false));

            } else {
                throw new UnrecognizedCCodeException("not supported", pCfaEdge, op2);
            }

        } else {
            throw new UnrecognizedCCodeException("not supported", pCfaEdge, op1);
        }
    }

    /**
     * Handles an assignement of the form <code>op1 = ...</code> to a given variable <code>op1</code>.
     *
     * @param pOp1
     *        Name of the lefthandside variable in the assignement <code>op1 = ...</code>.
     * @param pOp2
     *        Righthandside of the assignement.
     * @param pElement
     *        Predecessor of this assignement's AndersonElement.
     * @param pCfaEdge
    *          Corresponding edge of the CFA.
     * @return <code>element</code>'s successor.
     *
     * @throws UnrecognizedCCodeException
     */
    private AndersenState handleAssignmentTo(String pOp1, CRightHandSide pOp2, AndersenState pElement,
            CFAEdge pCfaEdge) throws UnrecognizedCCodeException {

        // unpack cast if necessary
        while (pOp2 instanceof CCastExpression) {
            pOp2 = ((CCastExpression) pOp2).getOperand();
        }

        if (pOp2 instanceof CIdExpression) {

            // a = b; simple constraint

            return pElement.addConstraint(new SimpleConstraint(pOp2.toASTString(), pOp1));

        } else if (pOp2 instanceof CUnaryExpression
                && ((CUnaryExpression) pOp2).getOperator() == UnaryOperator.AMPER) {

            // a = &b; base constraint

            pOp2 = ((CUnaryExpression) pOp2).getOperand();

            if (pOp2 instanceof CIdExpression) {

                return pElement.addConstraint(new BaseConstraint(pOp2.toASTString(), pOp1));

            } else {
                throw new UnrecognizedCCodeException("not supported", pCfaEdge, pOp2);
            }

        } else if (pOp2 instanceof CPointerExpression) {

            // a = *b; complex constraint

            pOp2 = ((CPointerExpression) pOp2).getOperand();

            if (pOp2 instanceof CIdExpression) {

                return pElement.addConstraint(new ComplexConstraint(pOp2.toASTString(), pOp1, true));

            } else {
                throw new UnrecognizedCCodeException("not supported", pCfaEdge, pOp2);
            }

        } else if (pOp2 instanceof CFunctionCallExpression
                && "malloc".equals(((CFunctionCallExpression) pOp2).getFunctionNameExpression().toASTString())) {

            // TODO line numbers are not unique when we have multiple input files!
            return pElement.addConstraint(new BaseConstraint("malloc-" + pCfaEdge.getLineNumber(), pOp1));

        }

        // not implemented, or not interessing
        printWarning(pCfaEdge);
        return pElement;
    }

    private AndersenState handleDeclaration(AndersenState pElement, CDeclarationEdge pDeclarationEdge)
            throws UnrecognizedCCodeException {

        if (!(pDeclarationEdge.getDeclaration() instanceof CVariableDeclaration)) {
            // nothing interesting to see here, please move along
            return pElement;
        }

        CVariableDeclaration decl = (CVariableDeclaration) pDeclarationEdge.getDeclaration();

        // get the variable name in the declarator
        String varName = decl.getName();

        // get initial value
        CInitializer init = decl.getInitializer();
        if (init instanceof CInitializerExpression) {

            CRightHandSide exp = ((CInitializerExpression) init).getExpression();

            return handleAssignmentTo(varName, exp, pElement, pDeclarationEdge);
        }

        return pElement;
    }

    /**
     * Prints a warning to System.err that the statement corresponding to the given
     * <code>cfaEdge</code> was not handled.
     */
    private void printWarning(CFAEdge pCfaEdge) {
        logger.log(Level.WARNING, pCfaEdge.getFileLocation() + ":",
                "Warning! CFA Edge \"" + pCfaEdge.getRawStatement() + "\" not handled.");
    }
}