void goto_convertt::read(exprt &expr, goto_programt &dest) { if(expr.is_constant()) return; if(expr.id()=="symbol") { // see if we already renamed it } symbolt &new_symbol=new_tmp_symbol(expr.type()); codet assignment("assign"); assignment.reserve_operands(2); assignment.copy_to_operands(symbol_expr(new_symbol)); assignment.move_to_operands(expr); goto_programt tmp_program; convert(assignment, tmp_program); dest.destructive_append(tmp_program); expr=symbol_expr(new_symbol); }
void static_lifetime_init( const contextt &context, codet &dest) { dest=code_blockt(); // Do assignments based on "value". context.foreach_operand_in_order( [&dest] (const symbolt& s) { if(s.static_lifetime) init_variable(dest, s); } ); // call designated "initialization" functions context.foreach_operand_in_order( [&dest] (const symbolt& s) { if(s.type.initialization() && s.type.is_code()) { code_function_callt function_call; function_call.function() = symbol_expr(s); dest.move_to_operands(function_call); } } ); }
void goto_convertt::make_temp_symbol( exprt &expr, goto_programt &dest) { const locationt location=expr.find_location(); symbolt &new_symbol=new_tmp_symbol(expr.type()); code_assignt assignment; assignment.lhs()=symbol_expr(new_symbol); assignment.rhs()=expr; assignment.location()=location; convert(assignment, dest); expr=symbol_expr(new_symbol); }
void invariant_propagationt::get_objects( const symbolt &symbol, object_listt &dest) { std::list<exprt> object_list; get_objects_rec(symbol_expr(symbol), object_list); for(std::list<exprt>::const_iterator it=object_list.begin(); it!=object_list.end(); it++) dest.push_back(object_store.add(*it)); }
code_function_callt get_destructor( const namespacet &ns, const typet &type) { if(type.id()==ID_symbol) { return get_destructor(ns, ns.follow(type)); } else if(type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components= struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->type().id()==ID_code) { const code_typet &code_type=to_code_type(it->type()); if(code_type.return_type().id()==ID_destructor && code_type.parameters().size()==1) { const typet &arg_type=code_type.parameters().front().type(); if(arg_type.id()==ID_pointer && ns.follow(arg_type.subtype())==type) { exprt symbol_expr(ID_symbol, it->type()); symbol_expr.set(ID_identifier, it->get(ID_name)); code_function_callt function_call; function_call.function()=symbol_expr; return function_call; } } } } } return static_cast<const code_function_callt &>(get_nil_irep()); }
void termination_baset::replace_nondet_sideeffects(exprt &expr) { if(expr.id()=="sideeffect" && expr.get("statement")=="nondet") { symbolt symbol; symbol.name=std::string("termination::nondet")+i2string(++nondet_counter); symbol.base_name=std::string("nondet")+i2string(nondet_counter); symbol.type=expr.type(); expr=symbol_expr(symbol); shadow_context.move(symbol); } else Forall_operands(it, expr) replace_nondet_sideeffects(*it); }
code_function_callt get_destructor( const namespacet &ns, const typet &type) { if(type.id()==ID_symbol) { return get_destructor(ns, ns.follow(type)); } else if(type.id()==ID_struct) { const exprt &methods=static_cast<const exprt&>(type.find(ID_methods)); forall_operands(it, methods) { if(it->type().id()==ID_code) { const code_typet &code_type=to_code_type(it->type()); if(code_type.return_type().id()==ID_destructor && code_type.parameters().size()==1) { const typet &arg_type=code_type.parameters().front().type(); if(arg_type.id()==ID_pointer && ns.follow(arg_type.subtype())==type) { exprt symbol_expr(ID_symbol, it->type()); symbol_expr.set(ID_identifier, it->get(ID_name)); code_function_callt function_call; function_call.function()=symbol_expr; return function_call; } } } } } return static_cast<const code_function_callt &>(get_nil_irep()); }
codet java_bytecode_convertt::convert_instructions( const instructionst &instructions, const code_typet &method_type) { // Run a worklist algorithm, assuming that the bytecode has not // been tampered with. See "Leroy, X. (2003). Java bytecode // verification: algorithms and formalizations. Journal of Automated // Reasoning, 30(3-4), 235-269." for a more complete treatment. // first pass: get targets and map addresses to instructions struct converted_instructiont { converted_instructiont( const instructionst::const_iterator &it, const codet &_code):source(it), code(_code), done(false) { } instructionst::const_iterator source; std::list<unsigned> successors; std::set<unsigned> predecessors; codet code; stackt stack; bool done; }; typedef std::map<unsigned, converted_instructiont> address_mapt; address_mapt address_map; std::set<unsigned> targets; for(instructionst::const_iterator i_it=instructions.begin(); i_it!=instructions.end(); i_it++) { std::pair<address_mapt::iterator, bool> a_entry= address_map.insert(std::make_pair( i_it->address, converted_instructiont(i_it, code_skipt()))); assert(a_entry.second); // addresses are strictly increasing, hence we must have inserted // a new maximal key assert(a_entry.first==--address_map.end()); if(i_it->statement!="goto" && i_it->statement!="return" && !(i_it->statement==patternt("?return")) && i_it->statement!="athrow") { instructionst::const_iterator next=i_it; if(++next!=instructions.end()) a_entry.first->second.successors.push_back(next->address); } if(i_it->statement=="goto" || i_it->statement==patternt("if_?cmp??") || i_it->statement==patternt("if??") || i_it->statement=="ifnonnull" || i_it->statement=="ifnull") { assert(!i_it->args.empty()); const unsigned target=safe_string2unsigned( id2string(to_constant_expr(i_it->args[0]).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } else if(i_it->statement=="tableswitch" || i_it->statement=="lookupswitch") { bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { const unsigned target=safe_string2unsigned( id2string(to_constant_expr(*a_it).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } } } } for(address_mapt::iterator it=address_map.begin(); it!=address_map.end(); ++it) { for(unsigned s : it->second.successors) { address_mapt::iterator a_it=address_map.find(s); assert(a_it!=address_map.end()); a_it->second.predecessors.insert(it->first); } } std::set<unsigned> working_set; if(!instructions.empty()) working_set.insert(instructions.front().address); while(!working_set.empty()) { std::set<unsigned>::iterator cur=working_set.begin(); address_mapt::iterator a_it=address_map.find(*cur); assert(a_it!=address_map.end()); working_set.erase(cur); if(a_it->second.done) continue; working_set.insert(a_it->second.successors.begin(), a_it->second.successors.end()); instructionst::const_iterator i_it=a_it->second.source; stack.swap(a_it->second.stack); a_it->second.stack.clear(); codet &c=a_it->second.code; assert(stack.empty() || a_it->second.predecessors.size()<=1 || has_prefix(stack.front().get_string(ID_C_base_name), "$stack")); irep_idt statement=i_it->statement; exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); const bytecode_infot &bytecode_info=get_bytecode_info(statement); // deal with _idx suffixes if(statement.size()>=2 && statement[statement.size()-2]=='_' && isdigit(statement[statement.size()-1])) { arg0=constant_exprt( std::string(id2string(statement), statement.size()-1, 1), integer_typet()); statement=std::string(id2string(statement), 0, statement.size()-2); } exprt::operandst op=pop(bytecode_info.pop); exprt::operandst results; results.resize(bytecode_info.push, nil_exprt()); if(statement=="aconst_null") { assert(results.size()==1); results[0]=gen_zero(java_reference_type(void_typet())); } else if(statement=="athrow") { assert(op.size()==1 && results.size()==1); side_effect_expr_throwt throw_expr; throw_expr.add_source_location()=i_it->source_location; throw_expr.copy_to_operands(op[0]); c=code_expressiont(throw_expr); results[0]=op[0]; } else if(statement=="checkcast") { // checkcast throws an exception in case a cast of object // on stack to given type fails. // The stack isn't modified. assert(op.size()==1 && results.size()==1); results[0]=op[0]; } else if(statement=="invokedynamic") { // not used in Java code_typet &code_type=to_code_type(arg0.type()); const code_typet::parameterst ¶meters(code_type.parameters()); pop(parameters.size()); const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { results.resize(1); results[0]=nil_exprt(); } } else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || statement=="invokestatic") { const bool use_this(statement != "invokestatic"); const bool is_virtual( statement == "invokevirtual" || statement == "invokeinterface"); code_typet &code_type=to_code_type(arg0.type()); code_typet::parameterst ¶meters(code_type.parameters()); if(use_this) { if(parameters.empty() || !parameters[0].get_this()) { const empty_typet empty; pointer_typet object_ref_type(empty); code_typet::parametert this_p(object_ref_type); this_p.set_this(); this_p.set_base_name("this"); parameters.insert(parameters.begin(), this_p); } } code_function_callt call; call.add_source_location()=i_it->source_location; call.arguments() = pop(parameters.size()); // double-check a bit if(use_this) { const exprt &this_arg=call.arguments().front(); assert(this_arg.type().id()==ID_pointer); } // do some type adjustment for the arguments, // as Java promotes arguments for(unsigned i=0; i<parameters.size(); i++) { const typet &type=parameters[i].type(); if(type==java_boolean_type() || type==java_char_type() || type==java_byte_type() || type==java_short_type()) { assert(i<call.arguments().size()); call.arguments()[i].make_typecast(type); } } // do some type adjustment for return values const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { // return types are promoted in Java call.lhs()=tmp_variable("return", return_type); exprt promoted=java_bytecode_promotion(call.lhs()); results.resize(1); results[0]=promoted; } assert(arg0.id()==ID_virtual_function); // does the function symbol exist? irep_idt id=arg0.get(ID_identifier); if(symbol_table.symbols.find(id)==symbol_table.symbols.end()) { // no, create stub symbolt symbol; symbol.name=id; symbol.base_name=arg0.get(ID_C_base_name); symbol.type=arg0.type(); symbol.value.make_nil(); symbol.mode=ID_java; symbol_table.add(symbol); } if(is_virtual) { // dynamic binding assert(use_this); assert(!call.arguments().empty()); call.function()=arg0; } else { // static binding /*if(id == "java::java.lang.String.charAt:(I)C") call.function()=symbol_exprt("java::__CPROVER_uninterpreted_char_at", arg0.type()); else*/ call.function()=symbol_exprt(arg0.get(ID_identifier), arg0.type()); } call.function().add_source_location()=i_it->source_location; c = call; } else if(statement=="return") { assert(op.empty() && results.empty()); c=code_returnt(); } else if(statement==patternt("?return")) { // Return types are promoted in java, so this might need // conversion. assert(op.size()==1 && results.empty()); exprt r=op[0]; if(r.type()!=method_return_type) r=typecast_exprt(r, method_return_type); c=code_returnt(r); } else if(statement==patternt("?astore")) { assert(op.size()==3 && results.empty()); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); const dereference_exprt element(data_plus_offset, element_type); c=code_assignt(element, op[2]); } else if(statement==patternt("?store")) { // store value into some local variable assert(op.size()==1 && results.empty()); exprt var=variable(arg0, statement[0]); const bool is_array('a' == statement[0]); if(is_array) var.type()=op[0].type(); c=code_assignt(var, op[0]); } else if(statement==patternt("?aload")) { assert(op.size() == 2 && results.size() == 1); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); dereference_exprt element(data_plus_offset, element_type); results[0]=java_bytecode_promotion(element); } else if(statement==patternt("?load")) { // load a value from a local variable results[0]=variable(arg0, statement[0]); } else if(statement=="ldc" || statement=="ldc_w" || statement=="ldc2" || statement=="ldc2_w") { assert(op.empty() && results.size()==1); // 1) Pushing a String causes a reference to a java.lang.String object // to be constructed and pushed onto the operand stack. // 2) Pushing an int or a float causes a primitive value to be pushed // onto the stack. // 3) Pushing a Class constant causes a reference to a java.lang.Class // to be pushed onto the operand stack if(arg0.id()==ID_java_string_literal) { // these need to be references to java.lang.String results[0]=arg0; symbol_typet string_type("java::java.lang.String"); results[0].type()=pointer_typet(string_type); } else if(arg0.id()==ID_type) { irep_idt class_id=arg0.type().get(ID_identifier); symbol_typet java_lang_Class("java::java.lang.Class"); symbol_exprt symbol_expr(id2string(class_id)+"@class_model", java_lang_Class); address_of_exprt address_of_expr(symbol_expr); results[0]=address_of_expr; } else if(arg0.id()==ID_constant) { results[0]=arg0; } else { error() << "unexpected ldc argument" << eom; throw 0; } } else if(statement=="goto" || statement=="goto_w") { assert(op.empty() && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_gotot code_goto(label(number)); c=code_goto; } else if(statement=="iconst_m1") { assert(results.size()==1); results[0]=from_integer(-1, java_int_type()); } else if(statement==patternt("?const")) { assert(results.size() == 1); const char type_char=statement[0]; const bool is_double('d' == type_char); const bool is_float('f' == type_char); if(is_double || is_float) { const ieee_float_spect spec( is_float ? ieee_float_spect::single_precision() : ieee_float_spect::double_precision()); ieee_floatt value(spec); const typet &arg_type(arg0.type()); if(ID_integer == arg_type.id()) value.from_integer(arg0.get_int(ID_value)); else value.from_expr(to_constant_expr(arg0)); results[0] = value.to_expr(); } else { const unsigned int value(arg0.get_unsigned_int(ID_value)); const typet type=java_type_from_char(statement[0]); results[0] = as_number(value, type); } } else if(statement==patternt("?ipush")) { assert(results.size()==1); results[0]=typecast_exprt(arg0, java_int_type()); } else if(statement==patternt("if_?cmp??")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==2 && results.empty()); code_ifthenelset code_branch; const irep_idt cmp_op=get_if_cmp_operator(statement); binary_relation_exprt condition(op[0], cmp_op, op[1]); cast_if_necessary(condition); code_branch.cond()=condition; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("if??")) { const irep_idt id= statement=="ifeq"?ID_equal: statement=="ifne"?ID_notequal: statement=="iflt"?ID_lt: statement=="ifge"?ID_ge: statement=="ifgt"?ID_gt: statement=="ifle"?ID_le: (assert(false), ""); irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; code_branch.cond()=binary_relation_exprt(op[0], id, gen_zero(op[0].type())); code_branch.cond().add_source_location()=i_it->source_location; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnonnull")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet()); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnull")) { assert(op.size()==1 && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement=="iinc") { code_assignt code_assign; code_assign.lhs()=variable(arg0, 'i'); code_assign.rhs()=plus_exprt( variable(arg0, 'i'), typecast_exprt(arg1, java_int_type())); c=code_assign; } else if(statement==patternt("?xor")) { assert(op.size()==2 && results.size()==1); results[0]=bitxor_exprt(op[0], op[1]); } else if(statement==patternt("?or")) { assert(op.size()==2 && results.size()==1); results[0]=bitor_exprt(op[0], op[1]); } else if(statement==patternt("?and")) { assert(op.size()==2 && results.size()==1); results[0]=bitand_exprt(op[0], op[1]); } else if(statement==patternt("?shl")) { assert(op.size()==2 && results.size()==1); results[0]=shl_exprt(op[0], op[1]); } else if(statement==patternt("?shr")) { assert(op.size()==2 && results.size()==1); results[0]=ashr_exprt(op[0], op[1]); } else if(statement==patternt("?ushr")) { assert(op.size()==2 && results.size()==1); const typet type(java_type_from_char(statement[0])); const unsigned int width(type.get_unsigned_int(ID_width)); typet target=unsigned_long_int_type(); target.set(ID_width, width); const typecast_exprt lhs(op[0], target); const typecast_exprt rhs(op[1], target); results[0]=lshr_exprt(lhs, rhs); } else if(statement==patternt("?add")) { assert(op.size()==2 && results.size()==1); results[0]=plus_exprt(op[0], op[1]); } else if(statement==patternt("?sub")) { assert(op.size()==2 && results.size()==1); results[0]=minus_exprt(op[0], op[1]); } else if(statement==patternt("?div")) { assert(op.size()==2 && results.size()==1); results[0]=div_exprt(op[0], op[1]); } else if(statement==patternt("?mul")) { assert(op.size()==2 && results.size()==1); results[0]=mult_exprt(op[0], op[1]); } else if(statement==patternt("?neg")) { assert(op.size()==1 && results.size()==1); results[0]=unary_minus_exprt(op[0], op[0].type()); } else if(statement==patternt("?rem")) { assert(op.size()==2 && results.size()==1); if(statement=="frem" || statement=="drem") results[0]=rem_exprt(op[0], op[1]); else results[0]=mod_exprt(op[0], op[1]); } else if(statement==patternt("?cmp")) { assert(op.size() == 2 && results.size() == 1); // The integer result on the stack is: // 0 if op[0] equals op[1] // -1 if op[0] is less than op[1] // 1 if op[0] is greater than op[1] const typet t=java_int_type(); results[0]= if_exprt(binary_relation_exprt(op[0], ID_equal, op[1]), gen_zero(t), if_exprt(binary_relation_exprt(op[0], ID_gt, op[1]), from_integer(1, t), from_integer(-1, t))); } else if(statement==patternt("?cmp?")) { assert(op.size()==2 && results.size()==1); const floatbv_typet type(to_floatbv_type(java_type_from_char(statement[0]))); const ieee_float_spect spec(type); const ieee_floatt nan(ieee_floatt::NaN(spec)); const constant_exprt nan_expr(nan.to_expr()); const int nan_value(statement[4] == 'l' ? -1 : 1); const typet result_type(java_int_type()); const exprt nan_result(from_integer(nan_value, result_type)); // (value1 == NaN || value2 == NaN) ? nan_value : value1 < value2 ? -1 : value2 < value1 1 ? 1 : 0; // (value1 == NaN || value2 == NaN) ? nan_value : value1 == value2 ? 0 : value1 < value2 -1 ? 1 : 0; results[0]= if_exprt(or_exprt(ieee_float_equal_exprt(nan_expr, op[0]), ieee_float_equal_exprt(nan_expr, op[1])), nan_result, if_exprt(ieee_float_equal_exprt(op[0], op[1]), gen_zero(result_type), if_exprt(binary_relation_exprt(op[0], ID_lt, op[1]), from_integer(-1, result_type), from_integer(1, result_type)))); } else if(statement==patternt("?cmpl")) { assert(op.size()==2 && results.size()==1); results[0]=binary_relation_exprt(op[0], ID_lt, op[1]); } else if(statement=="dup") { assert(op.size()==1 && results.size()==2); results[0]=results[1]=op[0]; } else if(statement=="dup_x1") { assert(op.size()==2 && results.size()==3); results[0]=op[1]; results[1]=op[0]; results[2]=op[1]; } else if(statement=="dup_x2") { assert(op.size()==3 && results.size()==4); results[0]=op[2]; results[1]=op[0]; results[2]=op[1]; results[3]=op[2]; } // dup2* behaviour depends on the size of the operands on the // stack else if(statement=="dup2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x1") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(3); else op=pop(2); results.insert(results.end(), op.begin()+1, op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); assert(!stack.empty()); exprt::operandst op2; if(stack.back().type().get_unsigned_int(ID_width)==32) op2=pop(2); else op2=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op2.begin(), op2.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dconst") { assert(op.empty() && results.size()==1); } else if(statement=="fconst") { assert(op.empty() && results.size()==1); } else if(statement=="getfield") { assert(op.size()==1 && results.size()==1); results[0]=to_member(op[0], arg0); } else if(statement=="getstatic") { assert(op.empty() && results.size()==1); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); results[0]=symbol_expr; } else if(statement=="putfield") { assert(op.size()==2 && results.size()==0); c = code_assignt(to_member(op[0], arg0), op[1]); } else if(statement=="putstatic") { assert(op.size()==1 && results.empty()); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); c=code_assignt(symbol_expr, op[0]); } else if(statement==patternt("?2?")) // i2c etc. { assert(op.size()==1 && results.size()==1); results[0]=typecast_exprt(op[0], java_type_from_char(statement[2])); } else if(statement=="new") { // use temporary since the stack symbol might get duplicated assert(op.empty() && results.size()==1); const pointer_typet ref_type(arg0.type()); exprt java_new_expr=side_effect_exprt(ID_java_new, ref_type); if(!i_it->source_location.get_line().empty()) java_new_expr.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("new", ref_type); c=code_assignt(tmp, java_new_expr); results[0]=tmp; } else if(statement=="newarray" || statement=="anewarray") { // the op is the array size assert(op.size()==1 && results.size()==1); char element_type; if(statement=="newarray") { irep_idt id=arg0.type().id(); if(id==ID_bool) element_type='z'; else if(id==ID_char) element_type='c'; else if(id==ID_float) element_type='f'; else if(id==ID_double) element_type='d'; else if(id==ID_byte) element_type='b'; else if(id==ID_short) element_type='s'; else if(id==ID_int) element_type='i'; else if(id==ID_long) element_type='j'; else element_type='?'; } else element_type='a'; const pointer_typet ref_type=java_array_type(element_type); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.copy_to_operands(op[0]); if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="multianewarray") { // The first argument is the type, the second argument is the dimension. // The size of each dimension is on the stack. irep_idt number=to_constant_expr(arg1).get_value(); unsigned dimension=safe_c_str2unsigned(number.c_str()); op=pop(dimension); assert(results.size()==1); // arg0.type() const pointer_typet ref_type=java_array_type('a'); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.operands()=op; if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="arraylength") { assert(op.size()==1 && results.size()==1); exprt pointer= typecast_exprt(op[0], java_array_type(statement[0])); const dereference_exprt array(pointer, pointer.type().subtype()); assert(pointer.type().subtype().id()==ID_symbol); const member_exprt length(array, "length", java_int_type()); results[0]=length; } else if(statement=="tableswitch" || statement=="lookupswitch") { assert(op.size()==1 && results.size()==0); // we turn into switch-case code_switcht code_switch; code_switch.add_source_location()=i_it->source_location; code_switch.value()=op[0]; code_blockt code_block; code_block.add_source_location()=i_it->source_location; bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { code_switch_caset code_case; code_case.add_source_location()=i_it->source_location; irep_idt number=to_constant_expr(*a_it).get_value(); code_case.code()=code_gotot(label(number)); code_case.code().add_source_location()=i_it->source_location; if(a_it==i_it->args.begin()) code_case.set_default(); else { instructiont::argst::const_iterator prev=a_it; prev--; code_case.case_op()=typecast_exprt(*prev, op[0].type()); code_case.case_op().add_source_location()=i_it->source_location; } code_block.add(code_case); } } code_switch.body()=code_block; c=code_switch; } else if(statement=="pop" || statement=="pop2") { // these are skips c=code_skipt(); // pop2 removes two single-word items from the stack (e.g. two // integers, or an integer and an object reference) or one // two-word item (i.e. a double or a long). // http://cs.au.dk/~mis/dOvs/jvmspec/ref-pop2.html if(statement=="pop2" && op[0].type().get_unsigned_int(ID_width)==32) pop(1); } else if(statement=="instanceof") { assert(op.size()==1 && results.size()==1); results[0]= binary_predicate_exprt(op[0], "java_instanceof", arg0); } else { c=codet(statement); c.operands()=op; } if(!i_it->source_location.get_line().empty()) c.add_source_location()=i_it->source_location; push(results); a_it->second.done=true; for(std::list<unsigned>::iterator it=a_it->second.successors.begin(); it!=a_it->second.successors.end(); ++it) { address_mapt::iterator a_it2=address_map.find(*it); assert(a_it2!=address_map.end()); if(!stack.empty() && a_it2->second.predecessors.size()>1) { // copy into temporaries code_blockt more_code; // introduce temporaries when successor is seen for the first // time if(a_it2->second.stack.empty()) { for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { symbol_exprt lhs=tmp_variable("$stack", s_it->type()); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); } } else { assert(a_it2->second.stack.size()==stack.size()); stackt::const_iterator os_it=a_it2->second.stack.begin(); for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { assert(has_prefix(os_it->get_string(ID_C_base_name), "$stack")); symbol_exprt lhs=to_symbol_expr(*os_it); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); ++os_it; } } if(results.empty()) { more_code.copy_to_operands(c); c.swap(more_code); } else { c.make_block(); forall_operands(o_it, more_code) c.copy_to_operands(*o_it); } } a_it2->second.stack=stack; } } // TODO: add exception handlers from exception table // review successor computation of athrow! code_blockt code; // temporaries for(const auto & var : tmp_vars) { code.add(code_declt(var)); } for(const auto & it : address_map) { const unsigned address=it.first; assert(it.first==it.second.source->address); const codet &c=it.second.code; if(targets.find(address)!=targets.end()) code.add(code_labelt(label(i2string(address)), c)); else if(c.get_statement()!=ID_skip) code.add(c); } return code; }
void goto_inlinet::parameter_assignments( const locationt &location, const code_typet &code_type, const exprt::operandst &arguments, goto_programt &dest) { // iterates over the operands exprt::operandst::const_iterator it1=arguments.begin(); goto_programt::local_variablest local_variables; const code_typet::argumentst &argument_types= code_type.arguments(); // iterates over the types of the arguments for(code_typet::argumentst::const_iterator it2=argument_types.begin(); it2!=argument_types.end(); it2++) { // if you run out of actual arguments there was a mismatch if(it1==arguments.end()) { err_location(location); throw "function call: not enough arguments"; } const exprt &argument=static_cast<const exprt &>(*it2); // this is the type the n-th argument should be const typet &arg_type=ns.follow(argument.type()); const irep_idt &identifier=argument.cmt_identifier(); if(identifier=="") { err_location(location); throw "no identifier for function argument"; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett decl=dest.add_instruction(); decl->make_other(); exprt tmp = code_declt(symbol_expr(symbol)); migrate_expr(tmp, decl->code); decl->location=location; decl->function=location.get_function(); decl->local_variables=local_variables; } local_variables.insert(identifier); // nil means "don't assign" if(it1->is_nil()) { } else { // this is the actual parameter exprt actual(*it1); // it should be the same exact type type2tc arg_type_2, actual_type_2; migrate_type(arg_type, arg_type_2); migrate_type(actual.type(), actual_type_2); if (!base_type_eq(arg_type_2, actual_type_2, ns)) { const typet &f_argtype = ns.follow(arg_type); const typet &f_acttype = ns.follow(actual.type()); // we are willing to do some conversion if((f_argtype.id()=="pointer" && f_acttype.id()=="pointer") || (f_argtype.is_array() && f_acttype.id()=="pointer" && f_argtype.subtype()==f_acttype.subtype())) { actual.make_typecast(arg_type); } else if((f_argtype.id()=="signedbv" || f_argtype.id()=="unsignedbv" || f_argtype.is_bool()) && (f_acttype.id()=="signedbv" || f_acttype.id()=="unsignedbv" || f_acttype.is_bool())) { actual.make_typecast(arg_type); } else { err_location(location); str << "function call: argument `" << identifier << "' type mismatch: got " << from_type(ns, identifier, it1->type()) << ", expected " << from_type(ns, identifier, arg_type); throw 0; } } // adds an assignment of the actual parameter to the formal parameter code_assignt assignment(symbol_exprt(identifier, arg_type), actual); assignment.location()=location; dest.add_instruction(ASSIGN); dest.instructions.back().location=location; migrate_expr(assignment, dest.instructions.back().code); dest.instructions.back().local_variables=local_variables; dest.instructions.back().function=location.get_function(); } it1++; } if(it1!=arguments.end()) { // too many arguments -- we just ignore that, no harm done } }
void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol) { const irept &arguments= main_symbol.type.find(ID_arguments); if(arguments.get_sub().size()==0) return; if(arguments.get_sub().size()!=2 && arguments.get_sub().size()!=3) { err_location(main_symbol.location); throw "main expected to have no or two or three arguments"; } symbolt *argc_new_symbol; const exprt &op0=static_cast<const exprt &>(arguments.get_sub()[0]); const exprt &op1=static_cast<const exprt &>(arguments.get_sub()[1]); { symbolt argc_symbol; argc_symbol.base_name="argc"; argc_symbol.name="c::argc'"; argc_symbol.type=op0.type(); argc_symbol.is_static_lifetime=true; argc_symbol.is_lvalue=true; if(argc_symbol.type.id()!=ID_signedbv && argc_symbol.type.id()!=ID_unsignedbv) { err_location(main_symbol.location); str << "argc argument expected to be integer type, but got `" << to_string(argc_symbol.type) << "'"; throw 0; } move_symbol(argc_symbol, argc_new_symbol); } { if(op1.type().id()!=ID_pointer || op1.type().subtype().id()!=ID_pointer) { err_location(main_symbol.location); str << "argv argument expected to be pointer-to-pointer type, " "but got `" << to_string(op1.type()) << "'"; throw 0; } // we make the type of this thing an array of pointers typet argv_type=array_typet(); argv_type.subtype()=op1.type().subtype(); // need to add one to the size -- the array is terminated // with NULL exprt one_expr=from_integer(1, argc_new_symbol->type); exprt size_expr(ID_plus, argc_new_symbol->type); size_expr.copy_to_operands(symbol_expr(*argc_new_symbol), one_expr); argv_type.add(ID_size).swap(size_expr); symbolt argv_symbol; argv_symbol.base_name="argv'"; argv_symbol.name="c::argv'"; argv_symbol.type=argv_type; argv_symbol.is_static_lifetime=true; argv_symbol.is_lvalue=true; symbolt *argv_new_symbol; move_symbol(argv_symbol, argv_new_symbol); } if(arguments.get_sub().size()==3) { symbolt envp_symbol; envp_symbol.base_name="envp'"; envp_symbol.name="c::envp'"; envp_symbol.type=(static_cast<const exprt&>(arguments.get_sub()[2])).type(); envp_symbol.is_static_lifetime=true; symbolt envp_size_symbol, *envp_new_size_symbol; envp_size_symbol.base_name="envp_size"; envp_size_symbol.name="c::envp_size'"; envp_size_symbol.type=op0.type(); // same type as argc! envp_size_symbol.is_static_lifetime=true; move_symbol(envp_size_symbol, envp_new_size_symbol); if(envp_symbol.type.id()!=ID_pointer) { err_location(main_symbol.location); str << "envp argument expected to be pointer type, but got `" << to_string(envp_symbol.type) << "'"; throw 0; } exprt size_expr = symbol_expr(*envp_new_size_symbol); envp_symbol.type.id(ID_array); envp_symbol.type.add(ID_size).swap(size_expr); symbolt *envp_new_symbol; move_symbol(envp_symbol, envp_new_symbol); } }
void interpretert::execute_function_call() { const code_function_callt &function_call= to_code_function_call(PC->code); // function to be called mp_integer a=evaluate_address(function_call.function()); if(a==0) throw "function call to NULL"; else if(a>=memory.size()) throw "out-of-range function call"; const memory_cellt &cell=memory[integer2long(a)]; const irep_idt &identifier=cell.identifier; const goto_functionst::function_mapt::const_iterator f_it= goto_functions.function_map.find(identifier); if(f_it==goto_functions.function_map.end()) throw "failed to find function "+id2string(identifier); // return value mp_integer return_value_address; if(function_call.lhs().is_not_nil()) return_value_address= evaluate_address(function_call.lhs()); else return_value_address=0; // values of the arguments std::vector<std::vector<mp_integer> > argument_values; argument_values.resize(function_call.arguments().size()); for(std::size_t i=0; i<function_call.arguments().size(); i++) evaluate(function_call.arguments()[i], argument_values[i]); // do the call if(f_it->second.body_available) { call_stack.push(stack_framet()); stack_framet &frame=call_stack.top(); frame.return_PC=next_PC; frame.return_function=function; frame.old_stack_pointer=stack_pointer; frame.return_value_address=return_value_address; // local variables std::set<irep_idt> locals; get_local_identifiers(f_it->second, locals); for(std::set<irep_idt>::const_iterator it=locals.begin(); it!=locals.end(); it++) { const irep_idt &id=*it; const symbolt &symbol=ns.lookup(id); unsigned size=get_size(symbol.type); if(size!=0) { frame.local_map[id]=stack_pointer; for(unsigned i=0; i<stack_pointer; i++) { unsigned address=stack_pointer+i; if(address>=memory.size()) memory.resize(address+1); memory[address].value=0; memory[address].identifier=id; memory[address].offset=i; } stack_pointer+=size; } } // assign the arguments const code_typet::parameterst ¶meters= to_code_type(f_it->second.type).parameters(); if(argument_values.size()<parameters.size()) throw "not enough arguments"; for(unsigned i=0; i<parameters.size(); i++) { const code_typet::parametert &a=parameters[i]; exprt symbol_expr(ID_symbol, a.type()); symbol_expr.set(ID_identifier, a.get_identifier()); assert(i<argument_values.size()); assign(evaluate_address(symbol_expr), argument_values[i]); } // set up new PC function=f_it; next_PC=f_it->second.body.instructions.begin(); } else throw "no body for "+id2string(identifier); }
void string_instrumentationt::do_strerror( goto_programt &dest, goto_programt::targett it, code_function_callt &call) { if(call.lhs().is_nil()) { it->make_skip(); return; } irep_idt identifier_buf="c::__strerror_buffer"; irep_idt identifier_size="c::__strerror_buffer_size"; if(context.symbols.find(identifier_buf)==context.symbols.end()) { symbolt new_symbol_size; new_symbol_size.base_name="__strerror_buffer_size"; new_symbol_size.pretty_name=new_symbol_size.base_name; new_symbol_size.name=identifier_size; new_symbol_size.mode="C"; new_symbol_size.type=uint_type(); new_symbol_size.is_statevar=true; new_symbol_size.lvalue=true; new_symbol_size.static_lifetime=true; array_typet type; type.subtype()=char_type(); type.size()=symbol_expr(new_symbol_size); symbolt new_symbol_buf; new_symbol_buf.mode="C"; new_symbol_buf.type=type; new_symbol_buf.is_statevar=true; new_symbol_buf.lvalue=true; new_symbol_buf.static_lifetime=true; new_symbol_buf.base_name="__strerror_buffer"; new_symbol_buf.pretty_name=new_symbol_buf.base_name; new_symbol_buf.name="c::"+id2string(new_symbol_buf.base_name); context.move(new_symbol_buf); context.move(new_symbol_size); } const symbolt &symbol_size=ns.lookup(identifier_size); const symbolt &symbol_buf=ns.lookup(identifier_buf); goto_programt tmp; { goto_programt::targett assignment1=tmp.add_instruction(ASSIGN); exprt nondet_size=side_effect_expr_nondett(uint_type()); assignment1->code=code_assignt(symbol_expr(symbol_size), nondet_size); assignment1->location=it->location; goto_programt::targett assumption1=tmp.add_instruction(); assumption1->make_assumption(binary_relation_exprt( symbol_expr(symbol_size), "notequal", gen_zero(symbol_size.type))); assumption1->location=it->location; } // return a pointer to some magic buffer exprt index=exprt("index", char_type()); index.copy_to_operands(symbol_expr(symbol_buf), gen_zero(uint_type())); exprt ptr=exprt("address_of", pointer_typet()); ptr.type().subtype()=char_type(); ptr.copy_to_operands(index); // make that zero-terminated { goto_programt::targett assignment2=tmp.add_instruction(ASSIGN); assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt()); assignment2->location=it->location; } // assign address { goto_programt::targett assignment3=tmp.add_instruction(ASSIGN); exprt rhs=ptr; make_type(rhs, call.lhs().type()); assignment3->code=code_assignt(call.lhs(), rhs); assignment3->location=it->location; } it->make_skip(); dest.insert_before_swap(it, tmp); }
void string_instrumentationt::invalidate_buffer( goto_programt &dest, goto_programt::const_targett target, const exprt &buffer, const typet &buf_type, const mp_integer &limit) { irep_idt cntr_id="string_instrumentation::$counter"; if(context.symbols.find(cntr_id)==context.symbols.end()) { symbolt new_symbol; new_symbol.base_name="$counter"; new_symbol.pretty_name=new_symbol.base_name; new_symbol.name=cntr_id; new_symbol.mode="C"; new_symbol.type=uint_type(); new_symbol.is_statevar=true; new_symbol.lvalue=true; new_symbol.static_lifetime=true; context.move(new_symbol); } const symbolt &cntr_sym=ns.lookup(cntr_id); // create a loop that runs over the buffer // and invalidates every element goto_programt::targett init=dest.add_instruction(ASSIGN); init->location=target->location; init->code=code_assignt(symbol_expr(cntr_sym), gen_zero(cntr_sym.type)); goto_programt::targett check=dest.add_instruction(); check->location=target->location; goto_programt::targett invalidate=dest.add_instruction(ASSIGN); invalidate->location=target->location; goto_programt::targett increment=dest.add_instruction(ASSIGN); increment->location=target->location; exprt plus("+", uint_type()); plus.copy_to_operands(symbol_expr(cntr_sym)); plus.copy_to_operands(gen_one(uint_type())); increment->code=code_assignt(symbol_expr(cntr_sym), plus); goto_programt::targett back=dest.add_instruction(); back->location=target->location; back->make_goto(check); back->guard=true_exprt(); goto_programt::targett exit=dest.add_instruction(); exit->location=target->location; exit->make_skip(); exprt cnt_bs, bufp; if(buf_type.id()=="pointer") bufp = buffer; else { index_exprt index; index.array()=buffer; index.index()=gen_zero(uint_type()); index.type()=buf_type.subtype(); bufp = address_of_exprt(index); } exprt deref("dereference", buf_type.subtype()); exprt b_plus_i("+", bufp.type()); b_plus_i.copy_to_operands(bufp); b_plus_i.copy_to_operands(symbol_expr(cntr_sym)); deref.copy_to_operands(b_plus_i); check->make_goto(exit); if(limit==0) check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">=", buffer_size(bufp)); else check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">", from_integer(limit, uint_type())); exprt nondet=side_effect_expr_nondett(buf_type.subtype()); invalidate->code=code_assignt(deref, nondet); }
void cpp_typecheckt::typecheck_compound_declarator( const symbolt &symbol, const cpp_declarationt &declaration, cpp_declaratort &declarator, struct_typet::componentst &components, const irep_idt &access, bool is_static, bool is_typedef, bool is_mutable) { bool is_cast_operator= declaration.type().id()=="cpp-cast-operator"; if(is_cast_operator) { assert(declarator.name().get_sub().size()==2 && declarator.name().get_sub().front().id()==ID_operator); typet type=static_cast<typet &>(declarator.name().get_sub()[1]); declarator.type().subtype()=type; irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } typet final_type= declarator.merge_type(declaration.type()); // this triggers template elaboration elaborate_class_template(final_type); typecheck_type(final_type); cpp_namet cpp_name; cpp_name.swap(declarator.name()); irep_idt base_name; if(cpp_name.is_nil()) { // Yes, there can be members without name. base_name=irep_idt(); } else if(cpp_name.is_simple_name()) { base_name=cpp_name.get_base_name(); } else { err_location(cpp_name.location()); str << "declarator in compound needs to be simple name"; throw 0; } bool is_method=!is_typedef && final_type.id()==ID_code; bool is_constructor=declaration.is_constructor(); bool is_destructor=declaration.is_destructor(); bool is_virtual=declaration.member_spec().is_virtual(); bool is_explicit=declaration.member_spec().is_explicit(); bool is_inline=declaration.member_spec().is_inline(); final_type.set(ID_C_member_name, symbol.name); // first do some sanity checks if(is_virtual && !is_method) { err_location(cpp_name.location()); str << "only methods can be virtual"; throw 0; } if(is_inline && !is_method) { err_location(cpp_name.location()); str << "only methods can be inlined"; throw 0; } if(is_virtual && is_static) { err_location(cpp_name.location()); str << "static methods cannot be virtual"; throw 0; } if(is_cast_operator && is_static) { err_location(cpp_name.location()); str << "cast operators cannot be static`"; throw 0; } if(is_constructor && is_virtual) { err_location(cpp_name.location()); str << "constructors cannot be virtual"; throw 0; } if(!is_constructor && is_explicit) { err_location(cpp_name.location()); str << "only constructors can be explicit"; throw 0; } if(is_constructor && base_name!=id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "member function must return a value or void"; throw 0; } if(is_destructor && base_name!="~"+id2string(symbol.base_name)) { err_location(cpp_name.location()); str << "destructor with wrong name"; throw 0; } // now do actual work struct_typet::componentt component; irep_idt identifier= language_prefix+ cpp_scopes.current_scope().prefix+ id2string(base_name); component.set(ID_name, identifier); component.type()=final_type; component.set(ID_access, access); component.set(ID_base_name, base_name); component.set(ID_pretty_name, base_name); component.location()=cpp_name.location(); if(cpp_name.is_operator()) { component.set("is_operator", true); component.type().set("#is_operator", true); } if(is_cast_operator) component.set("is_cast_operator", true); if(declaration.member_spec().is_explicit()) component.set("is_explicit", true); typet &method_qualifier= (typet &)declarator.add("method_qualifier"); if(is_static) { component.set(ID_is_static, true); component.type().set("#is_static", true); } if(is_typedef) component.set("is_type", true); if(is_mutable) component.set("is_mutable", true); exprt &value=declarator.value(); irept &initializers=declarator.member_initializers(); if(is_method) { component.set(ID_is_inline, declaration.member_spec().is_inline()); // the 'virtual' name of the function std::string virtual_name= component.get_string(ID_base_name)+ id2string( function_identifier(static_cast<const typet &>(component.find(ID_type)))); if(method_qualifier.id()==ID_const) virtual_name += "$const"; if(component.type().get(ID_return_type) == ID_destructor) virtual_name= "@dtor"; // The method may be virtual implicitly. std::set<irep_idt> virtual_bases; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_bool("is_virtual")) { if(it->get("virtual_name")==virtual_name) { is_virtual=true; const code_typet& code_type = to_code_type(it->type()); assert(code_type.arguments().size()>0); const typet& pointer_type = code_type.arguments()[0].type(); assert(pointer_type.id() == ID_pointer); virtual_bases.insert(pointer_type.subtype().get(ID_identifier)); } } } if(!is_virtual) { typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); if(!value.is_nil() && !is_static) { err_location(cpp_name.location()); str << "no initialization allowed here"; throw 0; } } else // virtual { component.type().set("#is_virtual", true); component.type().set("#virtual_name",virtual_name); // Check if it is a pure virtual method if(is_virtual) { if(value.is_not_nil() && value.id() == ID_constant) { mp_integer i; to_integer(value, i); if(i!=0) { err_location(declarator.name().location()); str << "expected 0 to mark pure virtual method, got " << i; } component.set("is_pure_virtual", true); value.make_nil(); } } typecheck_member_function( symbol.name, component, initializers, method_qualifier, value); // get the virtual-table symbol type irep_idt vt_name = "virtual_table::"+symbol.name.as_string(); contextt::symbolst::iterator vtit = context.symbols.find(vt_name); if(vtit == context.symbols.end()) { // first time: create a virtual-table symbol type symbolt vt_symb_type; vt_symb_type.name= vt_name; vt_symb_type.base_name="virtual_table::"+symbol.base_name.as_string(); vt_symb_type.pretty_name = vt_symb_type.base_name; vt_symb_type.mode=ID_cpp; vt_symb_type.module=module; vt_symb_type.location=symbol.location; vt_symb_type.type = struct_typet(); vt_symb_type.type.set(ID_name, vt_symb_type.name); vt_symb_type.is_type = true; bool failed = context.move(vt_symb_type); assert(!failed); vtit = context.symbols.find(vt_name); // add a virtual-table pointer struct_typet::componentt compo; compo.type() = pointer_typet(symbol_typet(vt_name)); compo.set_name(symbol.name.as_string() +"::@vtable_pointer"); compo.set(ID_base_name, "@vtable_pointer"); compo.set(ID_pretty_name, symbol.base_name.as_string() +"@vtable_pointer"); compo.set("is_vtptr", true); compo.set(ID_access, ID_public); components.push_back(compo); put_compound_into_scope(compo); } assert(vtit->second.type.id()==ID_struct); struct_typet &virtual_table= to_struct_type(vtit->second.type); component.set("virtual_name", virtual_name); component.set("is_virtual", is_virtual); // add an entry to the virtual table struct_typet::componentt vt_entry; vt_entry.type() = pointer_typet(component.type()); vt_entry.set_name(vtit->first.as_string()+"::"+virtual_name); vt_entry.set(ID_base_name, virtual_name); vt_entry.set(ID_pretty_name, virtual_name); vt_entry.set(ID_access, ID_public); vt_entry.location() = symbol.location; virtual_table.components().push_back(vt_entry); // take care of overloading while(!virtual_bases.empty()) { irep_idt virtual_base = *virtual_bases.begin(); // a new function that does 'late casting' of the 'this' parameter symbolt func_symb; func_symb.name=component.get_name().as_string() + "::" +virtual_base.as_string(); func_symb.base_name=component.get(ID_base_name); func_symb.pretty_name = component.get(ID_base_name); func_symb.mode=ID_cpp; func_symb.module=module; func_symb.location=component.location(); func_symb.type=component.type(); // change the type of the 'this' pointer code_typet& code_type = to_code_type(func_symb.type); code_typet::argumentt& arg= code_type.arguments().front(); arg.type().subtype().set(ID_identifier, virtual_base); // create symbols for the arguments code_typet::argumentst& args = code_type.arguments(); for(unsigned i=0; i<args.size(); i++) { code_typet::argumentt& arg = args[i]; irep_idt base_name = arg.get_base_name(); if(base_name==irep_idt()) base_name="arg"+i2string(i); symbolt arg_symb; arg_symb.name = func_symb.name.as_string() + "::"+ base_name.as_string(); arg_symb.base_name = base_name; arg_symb.pretty_name = base_name; arg_symb.mode=ID_cpp; arg_symb.location=func_symb.location; arg_symb.type = arg.type(); arg.set(ID_C_identifier, arg_symb.name); // add the argument to the symbol table bool failed = context.move(arg_symb); assert(!failed); } // do the body of the function typecast_exprt late_cast(to_code_type(component.type()).arguments()[0].type()); late_cast.op0()= symbol_expr(namespacet(context).lookup( args[0].get(ID_C_identifier))); if(code_type.return_type().id()!=ID_empty && code_type.return_type().id()!=ID_destructor) { side_effect_expr_function_callt expr_call; expr_call.function() = symbol_exprt(component.get_name(),component.type()); expr_call.type() = to_code_type(component.type()).return_type(); expr_call.arguments().reserve(args.size()); expr_call.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { expr_call.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } code_returnt code_return; code_return.return_value() = expr_call; func_symb.value = code_return; } else { code_function_callt code_func; code_func.function() = symbol_exprt(component.get_name(),component.type()); code_func.arguments().reserve(args.size()); code_func.arguments().push_back(late_cast); for(unsigned i=1; i < args.size(); i++) { code_func.arguments().push_back( symbol_expr(namespacet(context).lookup( args[i].get(ID_C_identifier)))); } func_symb.value = code_func; } // add this new function to the list of components struct_typet::componentt new_compo = component; new_compo.type() = func_symb.type; new_compo.set_name(func_symb.name); components.push_back(new_compo); // add the function to the symbol table { bool failed = context.move(func_symb); assert(!failed); } // next base virtual_bases.erase(virtual_bases.begin()); } } } if(is_static && !is_method) // static non-method member { // add as global variable to context symbolt static_symbol; static_symbol.mode=symbol.mode; static_symbol.name=identifier; static_symbol.type=component.type(); static_symbol.base_name=component.get(ID_base_name); static_symbol.lvalue=true; static_symbol.static_lifetime=true; static_symbol.location=cpp_name.location(); static_symbol.is_extern=true; // TODO: not sure about this: should be defined separately! dynamic_initializations.push_back(static_symbol.name); symbolt *new_symbol; if(context.move(static_symbol, new_symbol)) { err_location(cpp_name.location()); str << "redeclaration of static member `" << static_symbol.base_name.as_string() << "'"; throw 0; } if(value.is_not_nil()) { if(cpp_is_pod(new_symbol->type)) { new_symbol->value.swap(value); c_typecheck_baset::do_initializer(*new_symbol); // these are macros if they are PODs and come with a (constant) value if(new_symbol->type.get_bool(ID_C_constant)) { simplify(new_symbol->value, *this); new_symbol->is_macro=true; } } else { symbol_exprt symexpr; symexpr.set_identifier(new_symbol->name); exprt::operandst ops; ops.push_back(value); codet defcode = cpp_constructor(locationt(), symexpr, ops); new_symbol->value.swap(defcode); } } } // array members must have fixed size check_fixed_size_array(component.type()); put_compound_into_scope(component); components.push_back(component); }