VariableId VariableIdMapping::variableIdOfArrayElement(VariableId arrayVar, int elemIndex) { int idCode = arrayVar.getIdCode(); int elemIdCode = idCode + elemIndex; VariableId elemVarId; elemVarId.setIdCode(elemIdCode); return elemVarId; }
/*! * \author Markus Schordan * \date 2013. */ void RDTransferFunctions::transferExpression(Label lab, SgExpression* node, Lattice& element0) { RDLattice* element1=dynamic_cast<RDLattice*>(&element0); ROSE_ASSERT(element1); RDLattice& element=*element1; // update analysis information // this is only correct for RERS12-C programs // 1) remove all pairs with lhs-variableid // 2) add (lab,lhs.varid) // (for programs with pointers we require a set here) VariableIdSet defVarIds=AnalysisAbstractionLayer::defVariables(node,*_variableIdMapping); ROSE_ASSERT(_pointerAnalysisInterface); if(hasDereferenceOperation(node)) { VariableIdSet modVarIds=_pointerAnalysisInterface->getModByPointer(); // union sets defVarIds+=modVarIds; } if(defVarIds.size()>1 /* TODO: || existsArrayVarId(defVarIds)*/ ) { // If an unknown array element is referenced, we consider // all its elements modified in the same statement. // Here *var* is an array element if its symbol is equal to at // least one of those corresponding to VariableIds with next or previous ids. for(VariableIdMapping::VariableIdSet::iterator i=defVarIds.begin();i!=defVarIds.end();++i) { VariableId var = *i; VariableId prev_var_id; VariableId next_var_id; prev_var_id.setIdCode(var.getIdCode() - 1); next_var_id.setIdCode(var.getIdCode() + 1); SgSymbol *var_smb = _variableIdMapping->getSymbol(var); SgSymbol *prev_var_smb = _variableIdMapping->getSymbol(prev_var_id); SgSymbol *next_var_smb = _variableIdMapping->getSymbol(next_var_id); if((var_smb == prev_var_smb) || (var_smb == next_var_smb)) element.removeAllPairsWithVariableId(var); } // since multiple memory locations may be modified, we cannot know which one will be updated and can only add information for(VariableIdMapping::VariableIdSet::iterator i=defVarIds.begin();i!=defVarIds.end();++i) { element.insertPair(lab,*i); } } else if(defVarIds.size()==1) { // one unique memory location (variable). We can remove all pairs with this variable VariableId var=*defVarIds.begin(); element.removeAllPairsWithVariableId(var); element.insertPair(lab,var); } }
//NOTE: missing: UD must take uses in initializers into account void RDTransferFunctions::transferDeclaration(Label lab, SgVariableDeclaration* declnode, Lattice& element0) { RDLattice& element=dynamic_cast<RDLattice&>(element0); // ROSE_ASSERT(element1); //RDLattice& element=*element1; SgInitializedName* node=SgNodeHelper::getInitializedNameOfVariableDeclaration(declnode); ROSE_ASSERT(node); // same as in transferExpression ... needs to be refined VariableIdSet defVarIds=AnalysisAbstractionLayer::defVariables(node,*_variableIdMapping); if(defVarIds.size()>1 /* TODO: || existsArrayVarId(defVarIds)*/ ) { // If an array is defined, we add all its elements to def set. // Remove pairs corresponding to array elements as in transferExpression() // but now assert that only elements of one array were modified. unsigned elements = 0; SgSymbol *array_smb = _variableIdMapping->getSymbol(*(defVarIds.begin())); for(VariableIdMapping::VariableIdSet::iterator i=defVarIds.begin();i!=defVarIds.end();++i) { VariableId var = *i; VariableId prev_var_id; VariableId next_var_id; prev_var_id.setIdCode(var.getIdCode() - 1); next_var_id.setIdCode(var.getIdCode() + 1); SgSymbol *var_smb = _variableIdMapping->getSymbol(var); SgSymbol *prev_var_smb = _variableIdMapping->getSymbol(prev_var_id); SgSymbol *next_var_smb = _variableIdMapping->getSymbol(next_var_id); if((var_smb == prev_var_smb) || (var_smb == next_var_smb)) { element.removeAllPairsWithVariableId(var); elements++; } if(var_smb != array_smb) assert(0); // more than one array is modified } // since multiple memory locations may be modified, we cannot know which one will be updated and can only add information for(VariableIdMapping::VariableIdSet::iterator i=defVarIds.begin();i!=defVarIds.end();++i) { element.insertPair(lab,*i); } if(elements != defVarIds.size()) assert(0); } else if(defVarIds.size()==1) { // one unique memory location (variable). We can remove all pairs with this variable VariableId var=*defVarIds.begin(); element.removeAllPairsWithVariableId(var); element.insertPair(lab,var); } }
list<SingleEvalResultConstInt> ExprAnalyzer::evalConstInt(SgNode* node,EState estate, bool useConstraints, bool safeConstraintPropagation) { assert(estate.pstate()); // ensure state exists SingleEvalResultConstInt res; //cout<<"DEBUG: evalConstInt: "<<node->unparseToString()<<astTermWithNullValuesToString(node)<<endl; // guard: for floating-point expression: return immediately with most general result // TODO: refine to walk the tree, when assignments are allowed in sub-expressions // MS: 2014-06-27: this cannot run in parallel because exp->get_type() seg-faults #if 0 if(SgExpression* exp=isSgExpression(node)) { bool isFloatingPointType; // ROSE workaround. get_type cannot be run in parallel #pragma omp critical { isFloatingPointType=SgNodeHelper::isFloatingPointType(exp->get_type()); } if(isFloatingPointType) { res.estate=estate; res.result=AType::ConstIntLattice(AType::Top()); return listify(res); } } #endif // initialize with default values from argument(s) res.estate=estate; res.result=AType::ConstIntLattice(AType::Bot()); if(SgNodeHelper::isPostfixIncDecOp(node)) { cout << "Error: incdec-op not supported in conditions yet."<<endl; exit(1); } if(SgConditionalExp* condExp=isSgConditionalExp(node)) { list<SingleEvalResultConstInt> resultList; SgExpression* cond=condExp->get_conditional_exp(); list<SingleEvalResultConstInt> condResultList=evalConstInt(cond,estate,useConstraints,safeConstraintPropagation); if(condResultList.size()==0) { cerr<<"Error: evaluating condition of conditional operator inside expressions gives no result."<<endl; exit(1); } if(condResultList.size()==2) { list<SingleEvalResultConstInt>::iterator i=condResultList.begin(); SingleEvalResultConstInt singleResult1=*i; ++i; SingleEvalResultConstInt singleResult2=*i; if((singleResult1.value()==singleResult2.value()).isTrue()) { cout<<"Info: evaluating condition of conditional operator gives two equal results"<<endl; } } if(condResultList.size()>1) { cerr<<"Error: evaluating condition of conditional operator gives more than one result. Not supported yet."<<endl; exit(1); } SingleEvalResultConstInt singleResult=*condResultList.begin(); if(singleResult.result.isTop()) { SgExpression* trueBranch=condExp->get_true_exp(); list<SingleEvalResultConstInt> trueBranchResultList=evalConstInt(trueBranch,estate,useConstraints,safeConstraintPropagation); SgExpression* falseBranch=condExp->get_false_exp(); list<SingleEvalResultConstInt> falseBranchResultList=evalConstInt(falseBranch,estate,useConstraints,safeConstraintPropagation); // append falseBranchResultList to trueBranchResultList (moves elements), O(1). trueBranchResultList.splice(trueBranchResultList.end(), falseBranchResultList); return trueBranchResultList; } if(singleResult.result.isTrue()) { SgExpression* trueBranch=condExp->get_true_exp(); list<SingleEvalResultConstInt> trueBranchResultList=evalConstInt(trueBranch,estate,useConstraints,safeConstraintPropagation); return trueBranchResultList; } if(singleResult.result.isFalse()) { SgExpression* falseBranch=condExp->get_false_exp(); list<SingleEvalResultConstInt> falseBranchResultList=evalConstInt(falseBranch,estate,useConstraints,safeConstraintPropagation); return falseBranchResultList; } // dummy return value to avoid compiler warning cerr<<"Error: evaluating conditional operator inside expressions - unknown behavior (condition may have evaluated to bot)."<<endl; exit(1); return resultList; } if(dynamic_cast<SgBinaryOp*>(node)) { //cout << "BinaryOp:"<<SgNodeHelper::nodeToString(node)<<endl; SgNode* lhs=SgNodeHelper::getLhs(node); list<SingleEvalResultConstInt> lhsResultList=evalConstInt(lhs,estate,useConstraints,safeConstraintPropagation); SgNode* rhs=SgNodeHelper::getRhs(node); list<SingleEvalResultConstInt> rhsResultList=evalConstInt(rhs,estate,useConstraints,safeConstraintPropagation); //assert(lhsResultList.size()==1); //assert(rhsResultList.size()==1); list<SingleEvalResultConstInt> resultList; for(list<SingleEvalResultConstInt>::iterator liter=lhsResultList.begin(); liter!=lhsResultList.end(); ++liter) { for(list<SingleEvalResultConstInt>::iterator riter=rhsResultList.begin(); riter!=rhsResultList.end(); ++riter) { SingleEvalResultConstInt lhsResult=*liter; SingleEvalResultConstInt rhsResult=*riter; switch(node->variantT()) { case V_SgEqualityOp: { res.result=(lhsResult.result==rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; // record new constraint VariableId varId; if(variable(lhs,varId) && rhsResult.isConstInt()) { // if var is top add two states with opposing constraints if(!res.estate.pstate()->varIsConst(varId)) { SingleEvalResultConstInt tmpres1=res; SingleEvalResultConstInt tmpres2=res; tmpres1.exprConstraints.addConstraint(Constraint(Constraint::EQ_VAR_CONST,varId,rhsResult.value())); tmpres1.result=true; tmpres2.exprConstraints.addConstraint(Constraint(Constraint::NEQ_VAR_CONST,varId,rhsResult.value())); tmpres2.result=false; resultList.push_back(tmpres1); resultList.push_back(tmpres2); //return resultList; MS: removed 3/11/2014 break; } } if(lhsResult.isConstInt() && variable(rhs,varId)) { // only add the equality constraint if no constant is bound to the respective variable if(!res.estate.pstate()->varIsConst(varId)) { SingleEvalResultConstInt tmpres1=res; SingleEvalResultConstInt tmpres2=res; tmpres1.exprConstraints.addConstraint(Constraint(Constraint::EQ_VAR_CONST,varId,lhsResult.value())); tmpres1.result=true; tmpres2.exprConstraints.addConstraint(Constraint(Constraint::NEQ_VAR_CONST,varId,lhsResult.value())); tmpres2.result=false; resultList.push_back(tmpres1); resultList.push_back(tmpres2); break; } } resultList.push_back(res); break; } case V_SgNotEqualOp: { res.result=(lhsResult.result!=rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; // record new constraint VariableId varId; if(variable(lhs,varId) && rhsResult.isConstInt()) { // only add the equality constraint if no constant is bound to the respective variable if(!res.estate.pstate()->varIsConst(varId)) { SingleEvalResultConstInt tmpres1=res; SingleEvalResultConstInt tmpres2=res; tmpres1.exprConstraints.addConstraint(Constraint(Constraint::NEQ_VAR_CONST,varId,rhsResult.value())); tmpres1.result=true; tmpres2.exprConstraints.addConstraint(Constraint(Constraint::EQ_VAR_CONST,varId,rhsResult.value())); tmpres2.result=false; resultList.push_back(tmpres1); resultList.push_back(tmpres2); break; } } if(lhsResult.isConstInt() && variable(rhs,varId)) { // only add the equality constraint if no constant is bound to the respective variable if(!res.estate.pstate()->varIsConst(varId)) { SingleEvalResultConstInt tmpres1=res; SingleEvalResultConstInt tmpres2=res; tmpres1.exprConstraints.addConstraint(Constraint(Constraint::NEQ_VAR_CONST,varId,lhsResult.value())); tmpres1.result=true; tmpres2.exprConstraints.addConstraint(Constraint(Constraint::EQ_VAR_CONST,varId,lhsResult.value())); tmpres2.result=false; resultList.push_back(tmpres1); resultList.push_back(tmpres2); break; } } resultList.push_back(res); break; } case V_SgAndOp: { //cout << "SgAndOp: "<<lhsResult.result.toString()<<"&&"<<rhsResult.result.toString()<<" ==> "; res.result=(lhsResult.result&&rhsResult.result); //cout << res.result.toString()<<endl; #if 0 cout << lhsResult.exprConstraints.toString(); cout << "&&"; cout << rhsResult.exprConstraints.toString(); cout << " == > "; #endif if(lhsResult.result.isFalse()) { res.exprConstraints=lhsResult.exprConstraints; // rhs is not considered due to short-circuit AND semantics } if(lhsResult.result.isTrue() && rhsResult.result.isFalse()) { res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; // nothing to do } if(lhsResult.result.isTrue() && rhsResult.result.isTrue()) { res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; } // in case of top we do not propagate constraints if(lhsResult.result.isTop() && !safeConstraintPropagation) { res.exprConstraints+=lhsResult.exprConstraints; } if(rhsResult.result.isTop() && !safeConstraintPropagation) { res.exprConstraints+=rhsResult.exprConstraints; } resultList.push_back(res); // cout << res.exprConstraints.toString(); //cout << endl; break; } case V_SgOrOp: { res.result=(lhsResult.result||rhsResult.result); // we encode short-circuit CPP-OR semantics here! if(lhsResult.result.isTrue()) { res.result=lhsResult.result; res.exprConstraints=lhsResult.exprConstraints; } if(lhsResult.result.isFalse() && rhsResult.result.isFalse()) { res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; } if(lhsResult.result.isFalse() && rhsResult.result.isTrue()) { res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; } // in case of top we do not propagate constraints if(lhsResult.result.isTop() && !safeConstraintPropagation) { res.exprConstraints+=lhsResult.exprConstraints; } if(rhsResult.result.isTop() && !safeConstraintPropagation) { res.exprConstraints+=rhsResult.exprConstraints; } resultList.push_back(res); break; } case V_SgAddOp: { res.result=(lhsResult.result+rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgSubtractOp: { res.result=(lhsResult.result-rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgMultiplyOp: { res.result=(lhsResult.result*rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgDivideOp: { res.result=(lhsResult.result/rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgModOp: { res.result=(lhsResult.result%rhsResult.result); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgGreaterOrEqualOp: { res.result=(lhsResult.result>=rhsResult.result); if(boolOptions["relop-constraints"]) { if(res.result.isTop()) throw "Error: Top found in relational operator (not supported yet)."; } res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgGreaterThanOp: { res.result=(lhsResult.result>rhsResult.result); if(boolOptions["relop-constraints"]) { if(res.result.isTop()) throw "Error: Top found in relational operator (not supported yet)."; } res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgLessThanOp: { res.result=(lhsResult.result<rhsResult.result); if(boolOptions["relop-constraints"]) { if(res.result.isTop()) throw "Error: Top found in relational operator (not supported yet)."; } res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgLessOrEqualOp: { res.result=(lhsResult.result<=rhsResult.result); if(boolOptions["relop-constraints"]) { if(res.result.isTop()) throw "Error: Top found in relational operator (not supported yet)."; } res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } case V_SgPntrArrRefExp: { // assume top for array elements (array elements are not stored in state) //cout<<"DEBUG: ARRAY-ACCESS2: ARR"<<node->unparseToString()<<"Index:"<<rhsResult.value()<<"skip:"<<getSkipArrayAccesses()<<endl; if(rhsResult.value().isTop()||getSkipArrayAccesses()==true) { res.result=AType::Top(); res.exprConstraints=lhsResult.exprConstraints+rhsResult.exprConstraints; resultList.push_back(res); break; } else { if(SgVarRefExp* varRefExp=isSgVarRefExp(lhs)) { const PState* pstate=estate.pstate(); PState pstate2=*pstate; // also removes constness VariableId arrayVarId=_variableIdMapping->variableId(varRefExp); // two cases if(_variableIdMapping->hasArrayType(arrayVarId)) { // has already correct id // nothing to do } else if(_variableIdMapping->hasPointerType(arrayVarId)) { // in case it is a pointer retrieve pointer value //cout<<"DEBUG: pointer-array access!"<<endl; if(pstate->varExists(arrayVarId)) { AValue aValuePtr=pstate2[arrayVarId].getValue(); // convert integer to VariableId int aValueInt=aValuePtr.getIntValue(); // change arrayVarId to refered array! //cout<<"DEBUG: defering pointer-to-array: ptr:"<<_variableIdMapping->variableName(arrayVarId); arrayVarId=_variableIdMapping->variableIdFromCode(aValueInt); //cout<<" to "<<_variableIdMapping->variableName(arrayVarId)<<endl;//DEBUG } else { cerr<<"Error: pointer variable does not exist in PState."<<endl; exit(1); } } else { cerr<<"Error: unkown type of array or pointer."<<endl; exit(1); } VariableId arrayElementId; AValue aValue=rhsResult.value(); if(aValue.isConstInt()) { int index=aValue.getIntValue(); arrayElementId=_variableIdMapping->variableIdOfArrayElement(arrayVarId,index); //cout<<"DEBUG: arrayElementVarId:"<<arrayElementId.toString()<<":"<<_variableIdMapping->variableName(arrayVarId)<<" Index:"<<index<<endl; } else { cerr<<"Error: array index cannot be evaluated to a constant. Not supported yet."<<endl; cerr<<"expr: "<<varRefExp->unparseToString()<<endl; exit(1); } ROSE_ASSERT(arrayElementId.isValid()); // read value of variable var id (same as for VarRefExp - TODO: reuse) if(pstate->varExists(arrayElementId)) { res.result=pstate2[arrayElementId].getValue(); //cout<<"DEBUG: retrieved value:"<<res.result<<endl; if(res.result.isTop() && useConstraints) { AType::ConstIntLattice val=res.estate.constraints()->varConstIntLatticeValue(arrayElementId); res.result=val; } return listify(res); } else { cerr<<"Error: Array Element does not exist (out of array access?)"<<endl; cerr<<"array-element-id: "<<arrayElementId.toString()<<" name:"<<_variableIdMapping->variableName(arrayElementId)<<endl; cerr<<"PState: "<<pstate->toString(_variableIdMapping)<<endl; cerr<<"AST: "<<node->unparseToString()<<endl; exit(1); } } else { cerr<<"Error: array-access uses expr for denoting the array. Not supported yet."<<endl; cerr<<"expr: "<<lhs->unparseToString()<<endl; cerr<<"arraySkip: "<<getSkipArrayAccesses()<<endl; exit(1); } } break; } default: cerr << "Binary Op:"<<SgNodeHelper::nodeToString(node)<<"(nodetype:"<<node->class_name()<<")"<<endl; throw "Error: evalConstInt::unkown binary operation."; } } } return resultList; } if(dynamic_cast<SgUnaryOp*>(node)) { SgNode* child=SgNodeHelper::getFirstChild(node); list<SingleEvalResultConstInt> operandResultList=evalConstInt(child,estate,useConstraints,safeConstraintPropagation); //assert(operandResultList.size()==1); list<SingleEvalResultConstInt> resultList; for(list<SingleEvalResultConstInt>::iterator oiter=operandResultList.begin(); oiter!=operandResultList.end(); ++oiter) { SingleEvalResultConstInt operandResult=*oiter; switch(node->variantT()) { case V_SgNotOp: res.result=!operandResult.result; // we do NOT invert the constraints, instead we negate the operand result (TODO: investigate) res.exprConstraints=operandResult.exprConstraints; resultList.push_back(res); break; case V_SgCastExp: { // TODO: model effect of cast when sub language is extended //SgCastExp* castExp=isSgCastExp(node); res.result=operandResult.result; res.exprConstraints=operandResult.exprConstraints; resultList.push_back(res); break; } // unary minus case V_SgMinusOp: { res.result=-operandResult.result; // using overloaded operator res.exprConstraints=operandResult.exprConstraints; resultList.push_back(res); break; } default: cerr << "@NODE:"<<node->sage_class_name()<<endl; throw "Error: evalConstInt::unknown unary operation."; } // end switch } return resultList; } ROSE_ASSERT(!dynamic_cast<SgBinaryOp*>(node) && !dynamic_cast<SgUnaryOp*>(node)); // ALL REMAINING CASES DO NOT GENERATE CONSTRAINTS // EXPRESSION LEAF NODES switch(node->variantT()) { case V_SgBoolValExp: { SgBoolValExp* boolValExp=isSgBoolValExp(node); assert(boolValExp); int boolVal= boolValExp->get_value(); if(boolVal==0) { res.result=false; return listify(res); } if(boolVal==1) { res.result=true; return listify(res); } break; } case V_SgDoubleVal: { //SgDoubleVal* doubleValNode=isSgDoubleVal(node); // floating point values are currently not computed res.result=AType::Top(); return listify(res); } case V_SgIntVal: { SgIntVal* intValNode=isSgIntVal(node); int intVal=intValNode->get_value(); res.result=intVal; return listify(res); } case V_SgVarRefExp: { VariableId varId; bool isVar=ExprAnalyzer::variable(node,varId); assert(isVar); const PState* pstate=estate.pstate(); if(pstate->varExists(varId)) { PState pstate2=*pstate; // also removes constness if(_variableIdMapping->hasArrayType(varId)) { // CODE-POINT-1 // for arrays (by default the address is used) return its pointer value (the var-id-code) res.result=AType::ConstIntLattice(varId.getIdCode()); } else { res.result=pstate2[varId].getValue(); // this include assignment of pointer values } if(res.result.isTop() && useConstraints) { // in case of TOP we try to extract a possibly more precise value from the constraints AType::ConstIntLattice val=res.estate.constraints()->varConstIntLatticeValue(varId); // TODO: TOPIFY-MODE: most efficient here res.result=val; } return listify(res); } else { res.result=AType::Top(); cerr << "WARNING: variable not in PState (var="<<_variableIdMapping->uniqueLongVariableName(varId)<<"). Initialized with top."<<endl; return listify(res); } break; } case V_SgFunctionCallExp: { if(getSkipSelectedFunctionCalls()) { // return default value return listify(res); } else { throw "Error: evalConstInt::function call inside expression."; } } default: cerr << "@NODE:"<<node->sage_class_name()<<endl; throw "Error: evalConstInt::unknown operation failed."; } // end of switch throw "Error: evalConstInt failed."; }
/*! * \author Markus Schordan * \date 2012. */ size_t SPRAY::hash_value(const VariableId& vid) { return vid.getIdCode(); }