Java tutorial
/* * 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.interval; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.sosy_lab.common.configuration.Configuration; import org.sosy_lab.common.configuration.InvalidConfigurationException; import org.sosy_lab.common.configuration.Option; import org.sosy_lab.common.configuration.Options; import org.sosy_lab.cpachecker.cfa.ast.AExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CArraySubscriptExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CAssignment; import org.sosy_lab.cpachecker.cfa.ast.c.CBinaryExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CBinaryExpression.BinaryOperator; import org.sosy_lab.cpachecker.cfa.ast.c.CCastExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CCharLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CComplexCastExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CDeclaration; 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.CFieldReference; import org.sosy_lab.cpachecker.cfa.ast.c.CFloatLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CFunctionCall; import org.sosy_lab.cpachecker.cfa.ast.c.CFunctionCallAssignmentStatement; 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.CImaginaryLiteralExpression; 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.CIntegerLiteralExpression; import org.sosy_lab.cpachecker.cfa.ast.c.CLiteralExpression; 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.CRightHandSideVisitor; import org.sosy_lab.cpachecker.cfa.ast.c.CSimpleDeclaration; import org.sosy_lab.cpachecker.cfa.ast.c.CStatement; import org.sosy_lab.cpachecker.cfa.ast.c.CStringLiteralExpression; 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.ast.c.DefaultCExpressionVisitor; import org.sosy_lab.cpachecker.cfa.model.CFAEdge; import org.sosy_lab.cpachecker.cfa.model.c.CAssumeEdge; import org.sosy_lab.cpachecker.cfa.model.c.CDeclarationEdge; import org.sosy_lab.cpachecker.cfa.model.c.CFunctionCallEdge; import org.sosy_lab.cpachecker.cfa.model.c.CFunctionEntryNode; import org.sosy_lab.cpachecker.cfa.model.c.CFunctionReturnEdge; import org.sosy_lab.cpachecker.cfa.model.c.CFunctionSummaryEdge; import org.sosy_lab.cpachecker.cfa.model.c.CReturnStatementEdge; import org.sosy_lab.cpachecker.cfa.model.c.CStatementEdge; import org.sosy_lab.cpachecker.cfa.types.c.CEnumType.CEnumerator; import org.sosy_lab.cpachecker.cfa.types.c.CPointerType; 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.exceptions.CPATransferException; import org.sosy_lab.cpachecker.exceptions.UnrecognizedCCodeException; import org.sosy_lab.cpachecker.exceptions.UnrecognizedCFAEdgeException; import com.google.common.base.Optional; @Options(prefix = "cpa.interval") public class IntervalAnalysisTransferRelation extends SingleEdgeTransferRelation { @Option(secure = true, description = "decides whether one (false) or two (true) successors should be created " + "when an inequality-check is encountered") private boolean splitIntervals = false; /** * base name of the variable that is introduced to pass results from returning function calls */ private static final String RETURN_VARIABLE_BASE_NAME = "___cpa_temp_result_var_"; private final Set<String> globalFieldVars = new HashSet<>(); @Option(secure = true, description = "at most that many intervals will be tracked per variable, -1 if number not restricted") private int threshold = -1; public IntervalAnalysisTransferRelation(Configuration config) throws InvalidConfigurationException { config.inject(this); } @Override public Collection<? extends AbstractState> getAbstractSuccessorsForEdge(AbstractState element, Precision precision, CFAEdge cfaEdge) throws CPATransferException { Collection<? extends AbstractState> successors = null; AbstractState successor = null; IntervalAnalysisState intervalElement = (IntervalAnalysisState) element; // check the type of the edge switch (cfaEdge.getEdgeType()) { // if edge is a statement edge, e.g. a = b + c case StatementEdge: CStatementEdge statementEdge = (CStatementEdge) cfaEdge; successor = handleStatement(intervalElement, statementEdge.getStatement(), cfaEdge); break; // this is the statement edge which leads the function to the last node of its CFA (not same as a return edge) case ReturnStatementEdge: CReturnStatementEdge returnEdge = (CReturnStatementEdge) cfaEdge; successor = handleExitFromFunction(intervalElement, returnEdge.getExpression(), returnEdge, cfaEdge); break; // edge is a declaration edge, e.g. int a; case DeclarationEdge: successor = handleDeclaration(intervalElement, (CDeclarationEdge) cfaEdge); break; // this is an assumption, e.g. if (a == b) case AssumeEdge: CAssumeEdge assumeEdge = (CAssumeEdge) cfaEdge; successors = handleAssumption(intervalElement, assumeEdge.getExpression(), cfaEdge, assumeEdge.getTruthAssumption()); break; case BlankEdge: successor = IntervalAnalysisState.copyOf(intervalElement); break; case FunctionCallEdge: CFunctionCallEdge functionCallEdge = (CFunctionCallEdge) cfaEdge; successor = handleFunctionCall(intervalElement, functionCallEdge, cfaEdge); break; // this is a return edge from function, this is different from return statement // of the function. See case in statement edge for details case FunctionReturnEdge: successor = handleFunctionReturn(intervalElement, (CFunctionReturnEdge) cfaEdge); break; default: throw new UnrecognizedCFAEdgeException(cfaEdge); } if (successors != null) { return successors; } else if (successor == null) { return noSuccessors(); } else { return soleSuccessor(successor); } } /** * Handles return from one function to another function. * * @param element previous abstract state. * @param functionReturnEdge return edge from a function to its call site. * @return new abstract state. */ private IntervalAnalysisState handleFunctionReturn(IntervalAnalysisState element, CFunctionReturnEdge functionReturnEdge) throws UnrecognizedCCodeException { CFunctionSummaryEdge summaryEdge = functionReturnEdge.getSummaryEdge(); CFunctionCall expression = summaryEdge.getExpression(); IntervalAnalysisState newElement = IntervalAnalysisState.copyOf(element); String callerFunctionName = functionReturnEdge.getSuccessor().getFunctionName(); String calledFunctionName = functionReturnEdge.getPredecessor().getFunctionName(); newElement.dropFrame(calledFunctionName); // expression is an assignment operation, e.g. a = g(b); if (expression instanceof CFunctionCallAssignmentStatement) { CFunctionCallAssignmentStatement funcExp = (CFunctionCallAssignmentStatement) expression; CExpression operand1 = funcExp.getLeftHandSide(); // left hand side of the expression has to be a variable if ((operand1 instanceof CIdExpression) || (operand1 instanceof CFieldReference)) { String returnedVariableName = calledFunctionName + "::" + RETURN_VARIABLE_BASE_NAME; // set the value of the assigned variable to the value of the returned variable Interval interval = element.contains(returnedVariableName) ? element.getInterval(returnedVariableName) : Interval.createUnboundInterval(); newElement.addInterval(constructVariableName(operand1, callerFunctionName), interval, this.threshold); } // a* = b(); TODO: for now, nothing is done here, but cloning the current element else if (operand1 instanceof CPointerExpression) { return IntervalAnalysisState.copyOf(element); } else { throw new UnrecognizedCCodeException("on function return", summaryEdge, operand1); } } else if (expression instanceof CFunctionCallStatement) { // nothing to do } else { throw new UnrecognizedCCodeException("on function return", summaryEdge, expression); } return newElement; } /** * This method handles function calls. * * @param previousElement the previous element of the analysis, before the function call * @param callEdge the respective CFA edge * @return the successor element * @throws UnrecognizedCCodeException */ private IntervalAnalysisState handleFunctionCall(IntervalAnalysisState previousElement, CFunctionCallEdge callEdge, CFAEdge edge) throws UnrecognizedCCodeException { CFunctionEntryNode functionEntryNode = callEdge.getSuccessor(); String calledFunctionName = functionEntryNode.getFunctionName(); String callerFunctionName = callEdge.getPredecessor().getFunctionName(); List<String> parameterNames = functionEntryNode.getFunctionParameterNames(); List<CExpression> arguments = callEdge.getArguments(); assert (parameterNames.size() == arguments.size()); IntervalAnalysisState newElement = IntervalAnalysisState.copyOf(previousElement); ExpressionValueVisitor visitor = new ExpressionValueVisitor(previousElement, callerFunctionName, edge); // set the interval of each formal parameter to the interval of its respective actual parameter for (int i = 0; i < arguments.size(); i++) { //Interval interval = evaluateInterval(previousElement, arguments.get(i), callerFunctionName, callEdge); // get value of actual parameter in caller function context Interval interval = arguments.get(i).accept(visitor); String formalParameterName = constructLocalVariableName(parameterNames.get(i), calledFunctionName); newElement.addInterval(formalParameterName, interval, this.threshold); } return newElement; } /** * This method handles the statement edge which leads the function to the last node of its CFA (not same as a return edge). * * @param element the analysis element * @param expression the expression * @param CReturnStatementEdge the CFA edge corresponding to this statement * @return the successor elements */ private IntervalAnalysisState handleExitFromFunction(IntervalAnalysisState element, Optional<CExpression> expression, CReturnStatementEdge returnEdge, CFAEdge edge) throws UnrecognizedCCodeException { CExpression exp = expression.or(CIntegerLiteralExpression.ZERO); // 0 is the default in C ExpressionValueVisitor visitor = new ExpressionValueVisitor(element, returnEdge.getPredecessor().getFunctionName(), edge); // assign the value of the function return to a new variable return handleAssignmentToVariable(RETURN_VARIABLE_BASE_NAME, exp, visitor); } /** * This method handles assumptions. * * @param element the analysis element * @param expression the expression containing the assumption * @param cfaEdge the CFA edge corresponding to this expression * @param truthValue flag to determine whether this is the then- or the else-branch of the assumption * @return the successor elements */ private Collection<? extends AbstractState> handleAssumption(IntervalAnalysisState element, CExpression expression, CFAEdge cfaEdge, boolean truthValue) throws UnrecognizedCCodeException { // first, unpack the expression to deal with a raw assumption if (expression instanceof CUnaryExpression) { throw new UnrecognizedCCodeException("unexpected operator in assumption", cfaEdge, expression); } // -> *exp - don't know anything else if (expression instanceof CPointerExpression) { return soleSuccessor(IntervalAnalysisState.copyOf(element)); } // a plain (boolean) identifier, e.g. if (a) else if (expression instanceof CIdExpression) { // this is simplified in the frontend throw new UnrecognizedCCodeException("unexpected expression in assumption", cfaEdge, expression); } else if (expression instanceof CBinaryExpression) { IntervalAnalysisState newElement = IntervalAnalysisState.copyOf(element); BinaryOperator operator = ((CBinaryExpression) expression).getOperator(); CExpression operand1 = ((CBinaryExpression) expression).getOperand1(); CExpression operand2 = ((CBinaryExpression) expression).getOperand2(); ExpressionValueVisitor visitor = new ExpressionValueVisitor(newElement, cfaEdge.getPredecessor().getFunctionName(), cfaEdge); Interval interval1 = operand1.accept(visitor); Interval interval2 = operand2.accept(visitor); switch (operator) { case MINUS: case PLUS: Interval result = null; if (operator == BinaryOperator.MINUS) { result = interval1.minus(interval2); } else if (operator == BinaryOperator.PLUS) { result = interval1.plus(interval2); } // in then-branch and interval maybe true, or in else-branch and interval maybe false, add a successor if ((truthValue && !result.isFalse()) || (!truthValue && !result.isTrue())) { return soleSuccessor(newElement); } else { return noSuccessors(); } case EQUALS: case NOT_EQUALS: case GREATER_THAN: case GREATER_EQUAL: case LESS_THAN: case LESS_EQUAL: return processAssumption(newElement, operator, operand1, operand2, truthValue, cfaEdge); case BINARY_AND: case BINARY_OR: case BINARY_XOR: return soleSuccessor(newElement); default: throw new UnrecognizedCCodeException("unexpected operator in assumption", cfaEdge, expression); } } return noSuccessors(); } private Collection<? extends AbstractState> processAssumption(IntervalAnalysisState element, BinaryOperator operator, CExpression operand1, CExpression operand2, boolean truthValue, CFAEdge cfaEdge) throws UnrecognizedCCodeException { if (!truthValue) { return processAssumption(element, negateOperator(operator), operand1, operand2, !truthValue, cfaEdge); } ExpressionValueVisitor visitor = new ExpressionValueVisitor(element, cfaEdge.getPredecessor().getFunctionName(), cfaEdge); Interval orgInterval1 = operand1.accept(visitor); Interval orgInterval2 = operand2.accept(visitor); //Interval orgInterval1 = evaluateInterval(element, operand1, cfaEdge.getPredecessor().getFunctionName(), cfaEdge); Interval tmpInterval1 = orgInterval1; //Interval orgInterval2 = evaluateInterval(element, operand2, cfaEdge.getPredecessor().getFunctionName(), cfaEdge); Interval tmpInterval2 = orgInterval2; String variableName1 = constructVariableName(operand1, cfaEdge.getPredecessor().getFunctionName()); String variableName2 = constructVariableName(operand2, cfaEdge.getPredecessor().getFunctionName()); // determine whether or not the respective operand is an identifier boolean isIdOp1 = operand1 instanceof CIdExpression; boolean isIdOp2 = operand2 instanceof CIdExpression; // a < b, a < 1 if (operator == BinaryOperator.LESS_THAN) { // a may be less than b, so there can be a successor if (tmpInterval1.mayBeLessThan(tmpInterval2)) { if (isIdOp1) { element.addInterval(variableName1, orgInterval1.limitUpperBoundBy(tmpInterval2.minus(1L)), threshold); } if (isIdOp2) { element.addInterval(variableName2, orgInterval2.limitLowerBoundBy(tmpInterval1.plus(1L)), threshold); } } else { return noSuccessors(); } } // a <= b, a <= 1 else if (operator == BinaryOperator.LESS_EQUAL) { // a may be less or equal than b, so there can be a successor if (tmpInterval1.mayBeLessOrEqualThan(tmpInterval2)) { if (isIdOp1) { element.addInterval(variableName1, orgInterval1.limitUpperBoundBy(tmpInterval2), threshold); } if (isIdOp2) { element.addInterval(variableName2, orgInterval2.limitLowerBoundBy(tmpInterval1), threshold); } } else { return noSuccessors(); } } // a > b, a > 1 else if (operator == BinaryOperator.GREATER_THAN) { // a may be greater than b, so there can be a successor if (tmpInterval1.mayBeGreaterThan(tmpInterval2)) { if (isIdOp1) { element.addInterval(variableName1, orgInterval1.limitLowerBoundBy(tmpInterval2.plus(1L)), threshold); } if (isIdOp2) { element.addInterval(variableName2, orgInterval2.limitUpperBoundBy(tmpInterval1.minus(1L)), threshold); } } else { return noSuccessors(); } } // a >= b, a >= 1 else if (operator == BinaryOperator.GREATER_EQUAL) { // a may be greater or equal than b, so there can be a successor if (tmpInterval1.mayBeGreaterOrEqualThan(tmpInterval2)) { if (isIdOp1) { element.addInterval(variableName1, orgInterval1.limitLowerBoundBy(tmpInterval2), threshold); } if (isIdOp2) { element.addInterval(variableName2, orgInterval2.limitUpperBoundBy(tmpInterval1), threshold); } } else { return noSuccessors(); } } // a == b, a == 1 else if (operator == BinaryOperator.EQUALS) { // a and b intersect, so they may have the same value, so they may be equal if (tmpInterval1.intersects(tmpInterval2)) { if (isIdOp1) { element.addInterval(variableName1, orgInterval1.intersect(tmpInterval2), threshold); } if (isIdOp2) { element.addInterval(variableName2, orgInterval2.intersect(tmpInterval1), threshold); } } else { return noSuccessors(); } } // a != b, a != 1 else if (operator == BinaryOperator.NOT_EQUALS) { // a = [x, x] = b => a and b are always equal, so there can't be a successor if (tmpInterval1.isSingular() && tmpInterval1.equals(tmpInterval2)) { return noSuccessors(); } // TODO: currently depends on the fact that operand1 is a identifier, while operand2 is a literal if (splitIntervals && isIdOp1 && !isIdOp2) { IntervalAnalysisState newElement = null; Collection<IntervalAnalysisState> successors = new LinkedList<>(); Interval result = null; if (!(result = orgInterval1 .intersect(Interval.createUpperBoundedInterval(orgInterval2.getLow() - 1L))).isEmpty()) { newElement = IntervalAnalysisState.copyOf(element); newElement.addInterval(variableName1, result, threshold); successors.add(newElement); } if (!(result = orgInterval1 .intersect(Interval.createLowerBoundedInterval(orgInterval2.getLow() + 1L))).isEmpty()) { newElement = IntervalAnalysisState.copyOf(element); newElement.addInterval(variableName1, result, threshold); successors.add(newElement); } return successors; } } else { throw new UnrecognizedCCodeException("unknown operator", cfaEdge); } return soleSuccessor(element); } /** * This method return the negated counter part for a given operator * * @param operator * @return the negated counter part of the given operator */ private BinaryOperator negateOperator(BinaryOperator operator) { switch (operator) { case EQUALS: return BinaryOperator.NOT_EQUALS; case NOT_EQUALS: return BinaryOperator.EQUALS; case LESS_THAN: return BinaryOperator.GREATER_EQUAL; case LESS_EQUAL: return BinaryOperator.GREATER_THAN; case GREATER_EQUAL: return BinaryOperator.LESS_THAN; case GREATER_THAN: return BinaryOperator.LESS_EQUAL; default: return operator; } } /** * This method handles variable declarations. * * So far, only primitive types are supported, pointers are not supported either. * * @param element the analysis element * @param declarationEdge the CFA edge * @return the successor element */ private IntervalAnalysisState handleDeclaration(IntervalAnalysisState element, CDeclarationEdge declarationEdge) throws UnrecognizedCCodeException { IntervalAnalysisState newElement = IntervalAnalysisState.copyOf(element); if (declarationEdge.getDeclaration() instanceof CVariableDeclaration) { CVariableDeclaration decl = (CVariableDeclaration) declarationEdge.getDeclaration(); // ignore pointer variables if (decl.getType() instanceof CPointerType) { return newElement; } String varName; // if this is a global variable, add it to the list of global variables if (decl.isGlobal()) { varName = decl.getName(); globalFieldVars.add(varName); } else { varName = constructLocalVariableName(decl.getName(), declarationEdge.getPredecessor().getFunctionName()); } Interval interval; CInitializer init = decl.getInitializer(); // variable may be initialized explicitly on the spot ... if (init instanceof CInitializerExpression) { CExpression exp = ((CInitializerExpression) init).getExpression(); interval = evaluateInterval(element, exp, declarationEdge.getPredecessor().getFunctionName(), declarationEdge); } else { if (decl.isGlobal()) { // according to C standard non initialized global vars are set to 0 interval = new Interval(0L); } else { interval = Interval.createUnboundInterval(); } } newElement.addInterval(varName, interval, this.threshold); } return newElement; } /** * This method handles unary and binary statements. * * @param element the analysis element * @param expression the current expression * @param cfaEdge the CFA edge * @return the successor * @throws UnrecognizedCCodeException */ private IntervalAnalysisState handleStatement(IntervalAnalysisState element, CStatement expression, CFAEdge cfaEdge) throws UnrecognizedCCodeException { // expression is an assignment operation, e.g. a = b; if (expression instanceof CAssignment) { return handleAssignment(element, (CAssignment) expression, cfaEdge); } else if (expression instanceof CFunctionCallStatement) { return IntervalAnalysisState.copyOf(element); } else if (expression instanceof CExpressionStatement) { return IntervalAnalysisState.copyOf(element); } else { throw new UnrecognizedCCodeException("unknown statement", cfaEdge, expression); } } /** * This method handles assignments. * * @param element the analysis element * @param assignExpression the expression containing the binary expression * @param declarationEdge the CFA edge * @return the successor element * TODO pointer dereferencing via strengthening */ private IntervalAnalysisState handleAssignment(IntervalAnalysisState element, CAssignment assignExpression, CFAEdge cfaEdge) throws UnrecognizedCCodeException { CExpression op1 = assignExpression.getLeftHandSide(); CRightHandSide op2 = assignExpression.getRightHandSide(); // a = ? if (op1 instanceof CIdExpression) { ExpressionValueVisitor visitor = new ExpressionValueVisitor(element, cfaEdge.getPredecessor().getFunctionName(), cfaEdge); return handleAssignmentToVariable(constructVariableName(op1, visitor.functionName), op2, visitor); } // TODO: assignment to pointer, *a = ? else if (op1 instanceof CPointerExpression) { return IntervalAnalysisState.copyOf(element); } else if (op1 instanceof CFieldReference) { return IntervalAnalysisState.copyOf(element); } else if (op1 instanceof CArraySubscriptExpression) { return IntervalAnalysisState.copyOf(element); } else { throw new UnrecognizedCCodeException("left operand of assignment has to be a variable", cfaEdge, op1); } } /** * This method handles the assignment of a variable. * * @param lParam the local name of the variable to assign to * @param rightExp the assigning expression * @param cfaEdge the respective CFA edge * @return the successor element */ private IntervalAnalysisState handleAssignmentToVariable(String pFullVariableName, CRightHandSide expression, ExpressionValueVisitor v) throws UnrecognizedCCodeException { Interval value = expression.accept(v); IntervalAnalysisState newElement = IntervalAnalysisState.copyOf(v.state); newElement.addInterval(pFullVariableName, value, this.threshold); return newElement; } /** * This method evaluates an expression and returns the respective interval. * * @param element the analysis element * @param expression the expression containing the expression to be evaluated * @param functionName the name of the function currently being analyzed * @param cfaEdge the respective CFA edge * @return the interval in respect to the evaluated expression of null, if the expression could not be evaluated properly */ //getExpressionValue private Interval evaluateInterval(IntervalAnalysisState element, CRightHandSide expression, String functionName, CFAEdge cfaEdge) throws UnrecognizedCCodeException { if (expression instanceof CLiteralExpression) { Long value = parseLiteral((CLiteralExpression) expression, cfaEdge); return (value == null) ? Interval.createUnboundInterval() : new Interval(value, value); } else if (expression instanceof CIdExpression) { String varName = constructVariableName((CIdExpression) expression, functionName); return (element.contains(varName)) ? element.getInterval(varName) : Interval.createUnboundInterval(); } else if (expression instanceof CCastExpression) { return evaluateInterval(element, ((CCastExpression) expression).getOperand(), functionName, cfaEdge); } else if (expression instanceof CUnaryExpression) { CUnaryExpression unaryExpression = (CUnaryExpression) expression; UnaryOperator unaryOperator = unaryExpression.getOperator(); CExpression unaryOperand = unaryExpression.getOperand(); switch (unaryOperator) { case MINUS: Interval interval = evaluateInterval(element, unaryOperand, functionName, cfaEdge); return (interval == null) ? Interval.createUnboundInterval() : interval.negate(); default: throw new UnrecognizedCCodeException("unknown unary operator", cfaEdge, unaryExpression); } } // clause for CPointerexpression does the same, as UnaryExpression clause would have done for the star operator else if (expression instanceof CPointerExpression) { throw new UnrecognizedCCodeException("PointerExpressions are not allowed at this place", cfaEdge, expression); } // added for expression "if (! (req_a___0 + 50 == rsp_d___0))" in "systemc/mem_slave_tlm.1.cil.c" else if (expression instanceof CBinaryExpression) { CBinaryExpression binaryExpression = (CBinaryExpression) expression; Interval interval1 = evaluateInterval(element, binaryExpression.getOperand1(), functionName, cfaEdge); Interval interval2 = evaluateInterval(element, binaryExpression.getOperand2(), functionName, cfaEdge); switch (binaryExpression.getOperator()) { case PLUS: return interval1.plus(interval2); default: throw new UnrecognizedCCodeException("unknown binary operator", cfaEdge, binaryExpression); } } else { //throw new UnrecognizedCCodeException(cfaEdge, expression); return Interval.createUnboundInterval(); } } /** * This method parses an expression to retrieve its literal value. * * @param expression the expression to parse * @return a number or null if the parsing failed * @throws UnrecognizedCCodeException */ private static Long parseLiteral(CLiteralExpression expression, CFAEdge edge) throws UnrecognizedCCodeException { if (expression instanceof CIntegerLiteralExpression) { return ((CIntegerLiteralExpression) expression).asLong(); } else if (expression instanceof CFloatLiteralExpression) { return null; } else if (expression instanceof CCharLiteralExpression) { return (long) ((CCharLiteralExpression) expression).getCharacter(); } else if (expression instanceof CStringLiteralExpression) { return null; } else { throw new UnrecognizedCCodeException("unknown literal", edge, expression); } } private String constructLocalVariableName(String pVariableName, String pCalledFunctionName) { return pCalledFunctionName + "::" + pVariableName; } private String constructVariableName(AExpression pVariableName, String pCalledFunctionName) { if (pVariableName instanceof CIdExpression) { CSimpleDeclaration decl = ((CIdExpression) pVariableName).getDeclaration(); if (decl instanceof CDeclaration) { if (((CDeclaration) decl).isGlobal()) { return pVariableName.toASTString(); } } } if (pVariableName instanceof CFieldReference && globalFieldVars.contains(pVariableName.toASTString())) { return pVariableName.toASTString(); } return pCalledFunctionName + "::" + pVariableName.toASTString(); } @Override public Collection<? extends AbstractState> strengthen(AbstractState element, List<AbstractState> elements, CFAEdge cfaEdge, Precision precision) throws UnrecognizedCCodeException { return null; } private Collection<? extends AbstractState> soleSuccessor(AbstractState successor) { return Collections.singleton(successor); } private Collection<? extends AbstractState> noSuccessors() { return Collections.emptySet(); } /** * Visitor that get's the value from an expression. * The result may be null, i.e., the value is unknown. */ private class ExpressionValueVisitor extends DefaultCExpressionVisitor<Interval, UnrecognizedCCodeException> implements CRightHandSideVisitor<Interval, UnrecognizedCCodeException> { protected final IntervalAnalysisState state; protected final String functionName; protected final CFAEdge cfaEdge; public ExpressionValueVisitor(IntervalAnalysisState pElement, String pFunctionName, CFAEdge edge) { state = pElement; functionName = pFunctionName; cfaEdge = edge; } // TODO fields, arrays @Override protected Interval visitDefault(CExpression expression) { return Interval.createUnboundInterval(); } @Override public Interval visit(CBinaryExpression binaryExpression) throws UnrecognizedCCodeException { Interval interval1 = binaryExpression.getOperand1().accept(this); Interval interval2 = binaryExpression.getOperand2().accept(this); if (interval1 == null || interval2 == null) { return Interval.createUnboundInterval(); } switch (binaryExpression.getOperator()) { case PLUS: return interval1.plus(interval2); case MINUS: return interval1.minus(interval2); case MULTIPLY: return interval1.times(interval2); case DIVIDE: return interval1.divide(interval2); case SHIFT_LEFT: return interval1.shiftLeft(interval2); case SHIFT_RIGHT: return interval1.shiftRight(interval2); case EQUALS: return new Interval(interval1.intersects(interval2) ? 1L : 0L); case NOT_EQUALS: return new Interval(!interval1.intersects(interval2) ? 1L : 0L); case GREATER_THAN: return new Interval(interval1.mayBeGreaterThan(interval2) ? 1L : 0L); case GREATER_EQUAL: return new Interval(interval1.mayBeGreaterOrEqualThan(interval2) ? 1L : 0L); case LESS_THAN: return new Interval(interval1.mayBeLessThan(interval2) ? 1L : 0L); case LESS_EQUAL: return new Interval(interval1.mayBeLessOrEqualThan(interval2) ? 1L : 0L); case MODULO: return interval1.modulo(interval2); case BINARY_AND: case BINARY_OR: case BINARY_XOR: // can these be handled? return Interval.createUnboundInterval(); default: throw new UnrecognizedCCodeException("unkown binary operator", cfaEdge, binaryExpression); } } @Override public Interval visit(CCastExpression cast) throws UnrecognizedCCodeException { return cast.getOperand().accept(this); } @Override public Interval visit(CComplexCastExpression cast) throws UnrecognizedCCodeException { // evaluation of complex numbers is not supported by now return Interval.createUnboundInterval(); } @Override public Interval visit(CFunctionCallExpression functionCall) throws UnrecognizedCCodeException { return Interval.createUnboundInterval(); } @Override public Interval visit(CCharLiteralExpression charLiteral) throws UnrecognizedCCodeException { Long l = parseLiteral(charLiteral, cfaEdge); return l == null ? Interval.createUnboundInterval() : new Interval(l); } @Override public Interval visit(CFloatLiteralExpression floatLiteral) throws UnrecognizedCCodeException { return Interval.createUnboundInterval(); } @Override public Interval visit(CImaginaryLiteralExpression exp) throws UnrecognizedCCodeException { return exp.getValue().accept(this); } @Override public Interval visit(CIntegerLiteralExpression integerLiteral) throws UnrecognizedCCodeException { return new Interval(parseLiteral(integerLiteral, cfaEdge)); } @Override public Interval visit(CStringLiteralExpression stringLiteral) throws UnrecognizedCCodeException { return Interval.createUnboundInterval(); } @Override public Interval visit(CIdExpression identifier) throws UnrecognizedCCodeException { if (identifier.getDeclaration() instanceof CEnumerator) { return new Interval(((CEnumerator) identifier.getDeclaration()).getValue()); } String variableName = constructVariableName(identifier, functionName); if (state.contains(variableName)) { return state.getInterval(variableName); } else { return Interval.createUnboundInterval(); } } @Override public Interval visit(CUnaryExpression unaryExpression) throws UnrecognizedCCodeException { UnaryOperator unaryOperator = unaryExpression.getOperator(); CExpression unaryOperand = unaryExpression.getOperand(); Interval interval = unaryOperand.accept(this); switch (unaryOperator) { case MINUS: return (interval != null) ? interval.negate() : Interval.createUnboundInterval(); case AMPER: return Interval.createUnboundInterval(); // valid expression, but it's a pointer value default: throw new UnrecognizedCCodeException("unknown unary operator", cfaEdge, unaryExpression); } } @Override public Interval visit(CPointerExpression pointerExpression) throws UnrecognizedCCodeException { CExpression operand = pointerExpression.getOperand(); operand.accept(this); return Interval.createUnboundInterval(); } } }