void mutex_init_instrumentation( const symbol_tablet &symbol_table, goto_functionst &goto_functions) { // get pthread_mutex_lock symbol_tablet::symbolst::const_iterator f_it= symbol_table.symbols.find("pthread_mutex_lock"); if(f_it==symbol_table.symbols.end()) return; // get type of lock argument code_typet code_type=to_code_type(to_code_type(f_it->second.type)); if(code_type.parameters().size()!=1) return; typet lock_type=code_type.parameters()[0].type(); if(lock_type.id()!=ID_pointer) return; Forall_goto_functions(f_it, goto_functions) mutex_init_instrumentation( symbol_table, f_it->second.body, lock_type.subtype()); }
void java_record_outputs( const symbolt &function, const exprt::operandst &main_arguments, code_blockt &init_code, symbol_tablet &symbol_table) { const code_typet::parameterst ¶meters= to_code_type(function.type).parameters(); exprt::operandst result; result.reserve(parameters.size()+1); bool has_return_value= to_code_type(function.type).return_type()!=empty_typet(); if(has_return_value) { // record return value codet output(ID_output); output.operands().resize(2); const symbolt &return_symbol=symbol_table.lookup("return'"); output.op0()= address_of_exprt( index_exprt( string_constantt(return_symbol.base_name), from_integer(0, index_type()))); output.op1()=return_symbol.symbol_expr(); output.add_source_location()=function.location; init_code.move_to_operands(output); } for(std::size_t param_number=0; param_number<parameters.size(); param_number++) { const symbolt &p_symbol= symbol_table.lookup(parameters[param_number].get_identifier()); if(p_symbol.type.id()==ID_pointer) { // record as an output codet output(ID_output); output.operands().resize(2); output.op0()= address_of_exprt( index_exprt( string_constantt(p_symbol.base_name), from_integer(0, index_type()))); output.op1()=main_arguments[param_number]; output.add_source_location()=function.location; init_code.move_to_operands(output); } } }
code_function_callt function_to_call( symbol_tablet &symbol_table, const irep_idt &id, const irep_idt &argument) { // already there? symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(id); if(s_it==symbol_table.symbols.end()) { // not there pointer_typet p(char_type()); p.subtype().set(ID_C_constant, true); code_typet function_type; function_type.return_type()=empty_typet(); function_type.parameters().push_back( code_typet::parametert(p)); symbolt new_symbol; new_symbol.name=id; new_symbol.base_name=id; new_symbol.type=function_type; symbol_table.move(new_symbol); s_it=symbol_table.symbols.find(id); assert(s_it!=symbol_table.symbols.end()); } // signature is expected to be // (type *) -> ... if(s_it->second.type.id()!=ID_code || to_code_type(s_it->second.type).parameters().size()!=1 || to_code_type(s_it->second.type).parameters()[0].type().id()!=ID_pointer) { std::string error="function `"+id2string(id)+"' has wrong signature"; throw error; } string_constantt function_id_string(argument); code_function_callt call; call.lhs().make_nil(); call.function()= symbol_exprt(s_it->second.name, s_it->second.type); call.arguments().resize(1); call.arguments()[0]= typecast_exprt( address_of_exprt( index_exprt( function_id_string, from_integer(0, index_type()))), to_code_type(s_it->second.type).parameters()[0].type()); return call; }
Forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_function_call()) { code_function_callt &function_call=to_code_function_call(i_it->code); code_typet old_type=to_code_type(function_call.function().type()); // Do we return anything? if(old_type.return_type()!=empty_typet()) { // replace "lhs=f(...)" by "f(...); lhs=f#return_value; DEAD f#return_value;" assert(function_call.function().id()==ID_symbol); const irep_idt function_id= to_symbol_expr(function_call.function()).get_identifier(); // see if we have a body goto_functionst::function_mapt::const_iterator f_it=goto_functions.function_map.find(function_id); if(f_it==goto_functions.function_map.end()) throw "failed to find function `"+id2string(function_id)+"' in function map"; // fix the type to_code_type(function_call.function().type()).return_type()=empty_typet(); if(function_call.lhs().is_not_nil()) { exprt rhs; symbol_exprt return_value; return_value.type()=function_call.lhs().type(); return_value.set_identifier(id2string(function_id)+RETURN_VALUE_SUFFIX); rhs=return_value; goto_programt::targett t_a=goto_program.insert_after(i_it); t_a->make_assignment(); t_a->source_location=i_it->source_location; t_a->code=code_assignt(function_call.lhs(), rhs); t_a->function=i_it->function; // fry the previous assignment function_call.lhs().make_nil(); if(f_it->second.body_available()) { goto_programt::targett t_d=goto_program.insert_after(t_a); t_d->make_dead(); t_d->source_location=i_it->source_location; t_d->code=code_deadt(rhs); t_d->function=i_it->function; } } } } }
void cpp_declarator_convertert::main_function_rules( const symbolt &symbol) { if(symbol.name==ID_main) { if(symbol.type.id()!=ID_code) { cpp_typecheck.error().source_location=symbol.location; cpp_typecheck.error() << "main must be function" << messaget::eom; throw 0; } const typet &return_type= to_code_type(symbol.type).return_type(); if(return_type!=signed_int_type()) { // Too many embedded compilers ignore this rule. #if 0 cpp_typecheck.error().source_location=symbol.location; throw "main must return int"; #endif } } }
void java_bytecode_parsert::get_class_refs_rec(const typet &src) { if(src.id()==ID_code) { const code_typet &ct=to_code_type(src); const typet &rt=ct.return_type(); get_class_refs_rec(rt); for(const auto &p : ct.parameters()) get_class_refs_rec(p.type()); } else if(src.id()==ID_symbol) { irep_idt name=src.get(ID_C_base_name); if(has_prefix(id2string(name), "array[")) { const typet &element_type= static_cast<const typet &>(src.find(ID_C_element_type)); get_class_refs_rec(element_type); } else parse_tree.class_refs.insert(name); } else if(src.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(src); for(const auto &c : struct_type.components()) get_class_refs_rec(c.type()); } else if(src.id()==ID_pointer) get_class_refs_rec(src.subtype()); }
void remove_function_pointerst::fix_return_type( code_function_callt &function_call, goto_programt &dest) { // are we returning anything at all? if(function_call.lhs().is_nil()) return; const code_typet &code_type= to_code_type(ns.follow(function_call.function().type())); // type already ok? if(type_eq( function_call.lhs().type(), code_type.return_type(), ns)) return; symbolt &tmp_symbol=new_tmp_symbol(); tmp_symbol.type=code_type.return_type(); tmp_symbol.location=function_call.location(); symbol_exprt tmp_symbol_expr; tmp_symbol_expr.type()=tmp_symbol.type; tmp_symbol_expr.set_identifier(tmp_symbol.name); exprt old_lhs=function_call.lhs(); function_call.lhs()=tmp_symbol_expr; goto_programt::targett t_assign=dest.add_instruction(); t_assign->make_assignment(); t_assign->code=code_assignt( old_lhs, typecast_exprt(tmp_symbol_expr, old_lhs.type())); }
void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol) { if(symbol.is_parameter) adjust_function_parameter(symbol.type); // check initializer, if needed if(symbol.type.id()==ID_code) { if(symbol.value.is_not_nil() && !symbol.is_macro) typecheck_function_body(symbol); else { // we don't need the identifiers code_typet &code_type=to_code_type(symbol.type); for(code_typet::parameterst::iterator it=code_type.parameters().begin(); it!=code_type.parameters().end(); it++) it->set_identifier(irep_idt()); } } else { // check the initializer do_initializer(symbol); } }
void c_typecheck_baset::typecheck_type(typet &type) { // we first convert, and then check // do we have alignment? if(type.find(ID_C_alignment).is_not_nil()) { exprt &alignment=static_cast<exprt &>(type.add(ID_C_alignment)); if(alignment.id()!=ID_default) { typecheck_expr(alignment); make_constant(alignment); } } if(type.id()==ID_code) typecheck_code_type(to_code_type(type)); else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) typecheck_type(type.subtype()); else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); else if(type.id()==ID_c_enum) { } else if(type.id()==ID_c_bitfield) typecheck_c_bit_field_type(type); else if(type.id()==ID_typeof) typecheck_typeof_type(type); else if(type.id()==ID_symbol) typecheck_symbol_type(type); else if(type.id()==ID_vector) typecheck_vector_type(to_vector_type(type)); else if(type.id()==ID_custom_unsignedbv || type.id()==ID_custom_signedbv || type.id()==ID_custom_floatbv || type.id()==ID_custom_fixedbv) typecheck_custom_type(type); // do a bit of rule checking if(type.get_bool(ID_C_restricted) && type.id()!=ID_pointer && type.id()!=ID_array) { err_location(type); error("only a pointer can be 'restrict'"); throw 0; } }
void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol) { if(symbol.is_parameter) adjust_function_parameter(symbol.type); // check initializer, if needed if(symbol.type.id()==ID_code) { if(symbol.value.is_not_nil()) typecheck_function_body(symbol); else { // we don't need the identifiers code_typet &code_type=to_code_type(symbol.type); for(code_typet::parameterst::iterator it=code_type.parameters().begin(); it!=code_type.parameters().end(); it++) it->set_identifier(irep_idt()); } } else { if(symbol.type.id()==ID_array && to_array_type(symbol.type).size().is_nil() && !symbol.is_type) { // Insert a new type symbol for the array. // We do this because we want a convenient way // of adjusting the size of the type later on. type_symbolt new_symbol(symbol.type); new_symbol.name=id2string(symbol.name)+"$type"; new_symbol.base_name=id2string(symbol.base_name)+"$type"; new_symbol.location=symbol.location; new_symbol.mode=symbol.mode; new_symbol.module=symbol.module; symbol.type=symbol_typet(new_symbol.name); symbolt *new_sp; symbol_table.move(new_symbol, new_sp); } // check the initializer do_initializer(symbol); } }
bool restrict_bv_size(typet &type, const size_t width_in_bits) { const irep_idt &type_id=type.id(); if (ID_code == type_id) return restrict_bv_size(to_code_type(type), width_in_bits); if (ID_struct == type_id || ID_union == type_id) return restrict_bv_size(to_struct_union_type(type), width_in_bits); if (static_cast<const typet &>(type).subtype().is_not_nil()) restrict_bv_size(type.subtype(), width_in_bits); if (!is_bv_type(type)) return false; bitvector_typet &bvtype=to_bitvector_type(type); if (width_in_bits >= bvtype.get_width()) return false; to_bitvector_type(type).set_width(width_in_bits); return true; }
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()); }
irep_idt cpp_typecheckt::function_identifier(const typet &type) { const code_typet &function_type= to_code_type(template_subtype(type)); const code_typet::argumentst &arguments= function_type.arguments(); std::string result; bool first=true; result+='('; // the name of the function should not depend on // the class name that is encoded in the type of this, // but we must distinguish "const" and "non-const" member // functions code_typet::argumentst::const_iterator it= arguments.begin(); if(it!=arguments.end() && it->get_identifier()==ID_this) { const typet &pointer=it->type(); const typet &symbol =pointer.subtype(); if(symbol.get_bool(ID_C_constant)) result+="const$"; if(symbol.get_bool(ID_C_volatile)) result+="volatile$"; result+="this"; first=false; it++; } // we skipped the "this", on purpose! for(; it!=arguments.end(); it++) { if(first) first=false; else result+=","; typet tmp_type=it->type(); result+=cpp_type2name(it->type()); } result+=')'; return result; }
Forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_function_call()) { code_function_callt &function_call=to_code_function_call(i_it->code); // add x=y for f(y) where x is the parameter assert(function_call.function().id()==ID_symbol); const irep_idt &identifier= to_symbol_expr(function_call.function()).get_identifier(); // see if we have it const namespacet ns(symbol_table); const symbolt &function_symbol=ns.lookup(identifier); const code_typet &code_type=to_code_type(function_symbol.type); goto_programt tmp; for(std::size_t nr=0; nr<code_type.parameters().size(); nr++) { irep_idt p_identifier=code_type.parameters()[nr].get_identifier(); if(p_identifier.empty()) continue; if(nr<function_call.arguments().size()) { goto_programt::targett t=tmp.add_instruction(); t->make_assignment(); t->source_location=i_it->source_location; const symbolt &lhs_symbol=ns.lookup(p_identifier); symbol_exprt lhs=lhs_symbol.symbol_expr(); exprt rhs=function_call.arguments()[nr]; if(rhs.type()!=lhs.type()) rhs.make_typecast(lhs.type()); t->code=code_assignt(lhs, rhs); t->function=i_it->function; } } std::size_t count=tmp.instructions.size(); goto_program.insert_before_swap(i_it, tmp); for(; count!=0; count--) i_it++; } }
bool replace_symbolt::replace(typet &dest) { if(dest.has_subtype()) replace(dest.subtype()); Forall_subtypes(it, dest) replace(*it); if(dest.id()=="struct" || dest.id()=="union") { struct_typet &struct_type = to_struct_type(dest); struct_typet::componentst &components = struct_type.components(); for (struct_typet::componentst::iterator it = components.begin(); it!=components.end(); it++) replace(*it); } else if(dest.is_code()) { code_typet &code_type=to_code_type(dest); code_typet::argumentst &arguments=code_type.arguments(); for (code_typet::argumentst::iterator it = arguments.begin(); it!=arguments.end(); it++) replace(*it); } if(dest.id()=="symbol") { type_mapt::const_iterator it= type_map.find(dest.identifier()); if(it!=type_map.end()) { dest=it->second; return false; } } return true; }
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()); }
void get_symbols_rec( const namespacet &ns, const symbolt &symbol, find_symbols_sett &dest) { dest.insert(symbol.name); find_symbols_sett new_symbols; find_type_and_expr_symbols(symbol.type, new_symbols); find_type_and_expr_symbols(symbol.value, new_symbols); if(symbol.type.id()==ID_code) { const code_typet &code_type=to_code_type(symbol.type); const code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::const_iterator it=parameters.begin(); it!=parameters.end(); it++) { irep_idt id=it->get_identifier(); const symbolt *s; // identifiers for prototypes need not exist if(!ns.lookup(id, s)) new_symbols.insert(id); } } for(find_symbols_sett::const_iterator it=new_symbols.begin(); it!=new_symbols.end(); it++) { if(dest.find(*it)==dest.end()) { dest.insert(*it); get_symbols_rec(ns, ns.lookup(*it), dest); // recursive call } } }
void java_bytecode_typecheckt::typecheck_type(typet &type) { if(type.id()==ID_symbol) { irep_idt identifier=to_symbol_type(type).get_identifier(); symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); // must exist already in the symbol table if(s_it==symbol_table.symbols.end()) { error() << "failed to find type symbol "<< identifier << eom; throw 0; } assert(s_it->second.is_type); } else if(type.id()==ID_pointer) { typecheck_type(type.subtype()); } else if(type.id()==ID_array) { typecheck_type(type.subtype()); typecheck_expr(to_array_type(type).size()); } else if(type.id()==ID_code) { code_typet &code_type=to_code_type(type); typecheck_type(code_type.return_type()); code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::iterator it=parameters.begin(); it!=parameters.end(); it++) typecheck_type(it->type()); } }
void cpp_declarator_convertert::main_function_rules( const symbolt &symbol) { if(symbol.name==ID_main) { if(symbol.type.id()!=ID_code) { cpp_typecheck.err_location(symbol.location); throw "main must be function"; } const typet &return_type= to_code_type(symbol.type).return_type(); if(return_type!=signed_int_type()) { // Too many embedded compilers ignore this rule. // //cpp_typecheck.err_location(symbol.location); //throw "main must return int"; } } }
void jsil_typecheckt::typecheck_type(typet &type) { if(type.id()==ID_code) { code_typet ¶meters=to_code_type(type); for(code_typet::parametert &p : parameters.parameters()) { // create new symbol parameter_symbolt new_symbol; new_symbol.base_name=p.get_identifier(); // append procedure name to parameters p.set_identifier(add_prefix(p.get_identifier())); new_symbol.name=p.get_identifier(); if(is_jsil_builtin_code_type(type)) new_symbol.type=jsil_value_or_empty_type(); else if(is_jsil_spec_code_type(type)) new_symbol.type=jsil_value_or_reference_type(); else new_symbol.type=jsil_value_type(); // User defined function new_symbol.mode="jsil"; // mark as already typechecked new_symbol.is_extern=true; if(symbol_table.add(new_symbol)) { error() << "failed to add parameter symbol `" << new_symbol.name << "' in the symbol table" << eom; throw 0; } } } }
void remove_function_pointerst::fix_argument_types( code_function_callt &function_call) { const code_typet &code_type= to_code_type(ns.follow(function_call.function().type())); const code_typet::parameterst &function_parameters= code_type.parameters(); code_function_callt::argumentst &call_arguments= function_call.arguments(); for(unsigned i=0; i<function_parameters.size(); i++) { if(i<call_arguments.size()) { if(!type_eq(call_arguments[i].type(), function_parameters[i].type(), ns)) { call_arguments[i].make_typecast(function_parameters[i].type()); } } } }
std::string expr2javat::convert_rec( const typet &src, const c_qualifierst &qualifiers, const std::string &declarator) { c_qualifierst new_qualifiers(qualifiers); new_qualifiers.read(src); const std::string d= declarator==""?declarator:(" "+declarator); const std::string q= new_qualifiers.as_string(); if(src==java_int_type()) return q+"int"+d; else if(src==java_long_type()) return q+"long"+d; else if(src==java_short_type()) return q+"short"+d; else if(src==java_byte_type()) return q+"byte"+d; else if(src==java_char_type()) return q+"char"+d; else if(src==java_float_type()) return q+"float"+d; else if(src==java_double_type()) return q+"double"+d; else if(src==java_boolean_type()) return q+"bool"+d; else if(src==java_byte_type()) return q+"byte"+d; else if(src.id()==ID_code) { const code_typet &code_type=to_code_type(src); // Java doesn't really have syntax for function types, // so we make one up, loosley inspired by the syntax // of lamda expressions. std::string dest=""; dest+='('; const code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::const_iterator it=parameters.begin(); it!=parameters.end(); it++) { if(it!=parameters.begin()) dest+=", "; dest+=convert(it->type()); } if(code_type.has_ellipsis()) { if(!parameters.empty()) dest+=", "; dest+="..."; } dest+=')'; const typet &return_type=code_type.return_type(); dest+=" -> "+convert(return_type); return dest; } else return expr2ct::convert_rec(src, qualifiers, declarator); }
std::string expr2javat::convert_code_function_call( const code_function_callt &src, unsigned indent) { if(src.operands().size()!=3) { unsigned precedence; return convert_norep(src, precedence); } std::string dest=indent_str(indent); if(src.lhs().is_not_nil()) { unsigned p; std::string lhs_str=convert(src.lhs(), p); // TODO: ggf. Klammern je nach p dest+=lhs_str; dest+='='; } const code_typet &code_type= to_code_type(src.function().type()); bool has_this=code_type.has_this() && !src.arguments().empty(); if(has_this) { unsigned p; std::string this_str=convert(src.arguments()[0], p); dest+=this_str; dest+=" . "; // extra spaces for readability } { unsigned p; std::string function_str=convert(src.function(), p); dest+=function_str; } dest+='('; const exprt::operandst &arguments=src.arguments(); bool first=true; forall_expr(it, arguments) { if(has_this && it==arguments.begin()) { } else { unsigned p; std::string arg_str=convert(*it, p); if(first) first=false; else dest+=", "; // TODO: ggf. Klammern je nach p dest+=arg_str; } } dest+=");"; return dest; }
void cpp_typecheckt::typecheck_type(typet &type) { assert(!type.id().empty()); assert(type.is_not_nil()); try { cpp_convert_plain_type(type); } catch(const char *err) { error().source_location=type.source_location(); error() << err << eom; throw 0; } catch(const std::string &err) { error().source_location=type.source_location(); error() << err << eom; throw 0; } if(type.id()==ID_cpp_name) { c_qualifierst qualifiers(type); cpp_namet cpp_name; cpp_name.swap(type); exprt symbol_expr=resolve( cpp_name, cpp_typecheck_resolvet::wantt::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id()!=ID_type) { error().source_location=type.source_location(); error() << "error: expected type" << eom; throw 0; } type=symbol_expr.type(); assert(type.is_not_nil()); if(type.get_bool(ID_C_constant)) qualifiers.is_constant = true; qualifiers.write(type); } else if(type.id()==ID_struct || type.id()==ID_union) { typecheck_compound_type(to_struct_union_type(type)); } else if(type.id()==ID_pointer) { // the pointer might have a qualifier, but do subtype first typecheck_type(type.subtype()); // Check if it is a pointer-to-member if(type.find("to-member").is_not_nil()) { // these can point either to data members or member functions // of a class typet &class_object=static_cast<typet &>(type.add("to-member")); if(class_object.id()==ID_cpp_name) { assert(class_object.get_sub().back().id()=="::"); class_object.get_sub().pop_back(); } typecheck_type(class_object); // there may be parameters if this is a pointer to member function if(type.subtype().id()==ID_code) { irept::subt ¶meters=type.subtype().add(ID_parameters).get_sub(); if(parameters.empty() || parameters.front().get(ID_C_base_name)!=ID_this) { // Add 'this' to the parameters exprt a0(ID_parameter); a0.set(ID_C_base_name, ID_this); a0.type().id(ID_pointer); a0.type().subtype() = class_object; parameters.insert(parameters.begin(), a0); } } } } else if(type.id()==ID_array) { exprt &size_expr=to_array_type(type).size(); if(size_expr.is_not_nil()) { typecheck_expr(size_expr); simplify(size_expr, *this); } typecheck_type(type.subtype()); if(type.subtype().get_bool(ID_C_constant)) type.set(ID_C_constant, true); if(type.subtype().get_bool(ID_C_volatile)) type.set(ID_C_volatile, true); } else if(type.id()==ID_code) { code_typet &code_type=to_code_type(type); typecheck_type(code_type.return_type()); code_typet::parameterst ¶meters=code_type.parameters(); for(auto ¶m : parameters) { typecheck_type(param.type()); // see if there is a default value if(param.has_default_value()) { typecheck_expr(param.default_value()); implicit_typecast(param.default_value(), param.type()); } } } else if(type.id()==ID_template) { typecheck_type(type.subtype()); } else if(type.id()==ID_c_enum) { typecheck_enum_type(type); } else if(type.id()==ID_c_enum_tag) { } else if(type.id()==ID_c_bit_field) { typecheck_c_bit_field_type(to_c_bit_field_type(type)); } else if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bool || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_empty) { } else if(type.id()==ID_symbol) { } else if(type.id()==ID_constructor || type.id()==ID_destructor) { } else if(type.id()=="cpp-cast-operator") { } else if(type.id()=="cpp-template-type") { } else if(type.id()==ID_typeof) { exprt e=static_cast<const exprt &>(type.find(ID_expr_arg)); if(e.is_nil()) { typet tmp_type= static_cast<const typet &>(type.find(ID_type_arg)); if(tmp_type.id()==ID_cpp_name) { // this may be ambiguous -- it can be either a type or // an expression cpp_typecheck_fargst fargs; exprt symbol_expr=resolve( to_cpp_name(static_cast<const irept &>(tmp_type)), cpp_typecheck_resolvet::wantt::BOTH, fargs); type=symbol_expr.type(); } else { typecheck_type(tmp_type); type=tmp_type; } } else { typecheck_expr(e); type=e.type(); } } else if(type.id()==ID_decltype) { exprt e=static_cast<const exprt &>(type.find(ID_expr_arg)); typecheck_expr(e); type=e.type(); } else if(type.id()==ID_unassigned) { // ignore, for template parameter guessing } else if(type.id()==ID_template_class_instance) { // ok (internally generated) } else if(type.id()==ID_block_pointer) { // This is an Apple extension for lambda-like constructs. // http://thirdcog.eu/pwcblocks/ } else if(type.id()==ID_nullptr) { } else { error().source_location=type.source_location(); error() << "unexpected cpp type: " << type.pretty() << eom; throw 0; } assert(type.is_not_nil()); }
void c_typecheck_baset::typecheck_function_body(symbolt &symbol) { code_typet &code_type=to_code_type(symbol.type); assert(symbol.value.is_not_nil()); // reset labels labels_used.clear(); labels_defined.clear(); // fix type symbol.value.type()=code_type; // set return type return_type=code_type.return_type(); unsigned anon_counter=0; // Add the parameter declarations into the symbol table. code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::iterator p_it=parameters.begin(); p_it!=parameters.end(); p_it++) { // may be anonymous if(p_it->get_base_name()==irep_idt()) { irep_idt base_name="#anon"+i2string(anon_counter++); p_it->set_base_name(base_name); } // produce identifier irep_idt base_name=p_it->get_base_name(); irep_idt identifier=id2string(symbol.name)+"::"+id2string(base_name); p_it->set_identifier(identifier); parameter_symbolt p_symbol; p_symbol.type=p_it->type(); p_symbol.name=identifier; p_symbol.base_name=base_name; p_symbol.location=p_it->source_location(); symbolt *new_p_symbol; move_symbol(p_symbol, new_p_symbol); } // typecheck the body code typecheck_code(to_code(symbol.value)); // special case for main() if(symbol.name==ID_main) add_argc_argv(symbol); // check the labels for(std::map<irep_idt, source_locationt>::const_iterator it=labels_used.begin(); it!=labels_used.end(); it++) { if(labels_defined.find(it->first)==labels_defined.end()) { err_location(it->second); str << "branching label `" << it->first << "' is not defined in function"; throw 0; } } }
symbolt &cpp_declarator_convertert::convert( const typet &declaration_type, const cpp_storage_spect &storage_spec, const cpp_member_spect &member_spec, cpp_declaratort &declarator) { assert(declaration_type.is_not_nil()); if(declaration_type.id()=="cpp-cast-operator") { typet type; type.swap(declarator.name().get_sub().back()); declarator.type().subtype()=type; std::string tmp; cpp_typecheck.typecheck_type(type); irept name(ID_name); name.set(ID_identifier, "("+cpp_type2name(type)+")"); declarator.name().get_sub().back().swap(name); } assert(declarator.id()==ID_cpp_declarator); final_type=declarator.merge_type(declaration_type); assert(final_type.is_not_nil()); cpp_template_args_non_tct template_args; // run resolver on scope { cpp_save_scopet save_scope(cpp_typecheck.cpp_scopes); cpp_typecheck_resolvet cpp_typecheck_resolve(cpp_typecheck); cpp_typecheck_resolve.resolve_scope( declarator.name(), base_name, template_args); scope=&cpp_typecheck.cpp_scopes.current_scope(); // check the declarator-part of the type, in that scope cpp_typecheck.typecheck_type(final_type); } is_code=is_code_type(final_type); // global-scope arrays must have fixed size if(scope->is_global_scope()) cpp_typecheck.check_fixed_size_array(final_type); get_final_identifier(); // first see if it is a member if(scope->id_class==cpp_idt::CLASS && !is_friend) { // it's a member! it must be declared already typet &method_qualifier= static_cast<typet &>(declarator.method_qualifier()); // adjust template type if(final_type.id()==ID_template) { assert(0); typet tmp; tmp.swap(final_type.subtype()); final_type.swap(tmp); } // try static first symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { // adjust type if it's a non-static member function if(final_type.id()==ID_code) cpp_typecheck.adjust_method_type( scope->identifier, final_type, method_qualifier); get_final_identifier(); // try again c_it=cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) { cpp_typecheck.err_location(declarator.name()); cpp_typecheck.str << "member `" << base_name << "' not found in scope `" << scope->identifier << "'"; throw 0; } } assert(c_it!=cpp_typecheck.symbol_table.symbols.end()); symbolt &symbol=c_it->second; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // If it is a constructor, we take care of the // object initialization if(final_type.get(ID_return_type)==ID_constructor) { const cpp_namet &name=declarator.name(); exprt symbol_expr= cpp_typecheck.resolve( name, cpp_typecheck_resolvet::TYPE, cpp_typecheck_fargst()); if(symbol_expr.id()!=ID_type || symbol_expr.type().id()!=ID_symbol) { cpp_typecheck.err_location(name.source_location()); cpp_typecheck.str << "error: expected type"; throw 0; } irep_idt identifier=symbol_expr.type().get(ID_identifier); const symbolt &symb=cpp_typecheck.lookup(identifier); const typet &type = symb.type; assert(type.id()==ID_struct); if(declarator.find(ID_member_initializers).is_nil()) declarator.set(ID_member_initializers, ID_member_initializers); cpp_typecheck.check_member_initializers( type.find(ID_bases), to_struct_type(type).components(), declarator.member_initializers()); cpp_typecheck.full_member_initialization( to_struct_type(type), declarator.member_initializers()); } if(!storage_spec.is_extern()) symbol.is_extern=false; // initializer? handle_initializer(symbol, declarator); return symbol; } else { // no, it's no way a method // we won't allow the constructor/destructor type if(final_type.id()==ID_code && to_code_type(final_type).return_type().id()==ID_constructor) { cpp_typecheck.err_location(declarator.name().source_location()); cpp_typecheck.str << "function must have return type"; throw 0; } // already there? symbol_tablet::symbolst::iterator c_it= cpp_typecheck.symbol_table.symbols.find(final_identifier); if(c_it==cpp_typecheck.symbol_table.symbols.end()) return convert_new_symbol(storage_spec, member_spec, declarator); symbolt &symbol=c_it->second; if(!storage_spec.is_extern()) symbol.is_extern = false; if(declarator.get_bool("#template_case")) return symbol; combine_types(declarator.name().source_location(), final_type, symbol); enforce_rules(symbol); // initializer? handle_initializer(symbol, declarator); if(symbol.type.id()=="cpp-template-type") { cpp_scopet::id_sett id_set; scope->lookup_identifier(symbol.name, cpp_idt::TEMPLATE_PARAMETER, id_set); if(id_set.empty()) { cpp_idt &identifier= cpp_typecheck.cpp_scopes.put_into_scope(symbol,*scope); identifier.id_class=cpp_idt::TEMPLATE_PARAMETER; } } return symbol; } }
void cpp_declarator_convertert::combine_types( const source_locationt &source_location, const typet &decl_type, symbolt &symbol) { if(symbol.type.id()==decl_type.id() && decl_type.id()==ID_code) { // functions need special treatment due // to argument names, default values, and inlined-ness const code_typet &decl_code_type=to_code_type(decl_type); code_typet &symbol_code_type=to_code_type(symbol.type); if(decl_code_type.get_inlined()) symbol_code_type.set_inlined(true); if(decl_code_type.return_type()==symbol_code_type.return_type() && decl_code_type.parameters().size()==symbol_code_type.parameters().size()) { for(unsigned i=0; i<decl_code_type.parameters().size(); i++) { const code_typet::parametert &decl_parameter=decl_code_type.parameters()[i]; code_typet::parametert &symbol_parameter=symbol_code_type.parameters()[i]; // first check type if(decl_parameter.type()!=symbol_parameter.type()) { // The 'this' parameter of virtual functions mismatches if(i!=0 || !symbol_code_type.get_bool("#is_virtual")) { cpp_typecheck.err_location(source_location); cpp_typecheck.str << "symbol `" << symbol.display_name() << "': parameter " << (i+1) << " type mismatch" << std::endl; cpp_typecheck.str << "previous type: " << cpp_typecheck.to_string(symbol_parameter.type()) << std::endl; cpp_typecheck.str << "new type: " << cpp_typecheck.to_string(decl_parameter.type()); throw 0; } } if(symbol.value.is_nil()) { symbol_parameter.set_base_name(decl_parameter.get_base_name()); symbol_parameter.set_identifier(decl_parameter.get_identifier()); symbol_parameter.add_source_location()=decl_parameter.source_location(); } } // ok return; } } else if(symbol.type==decl_type) return; // ok else if(symbol.type.id()==ID_array && symbol.type.find(ID_size).is_nil() && decl_type.id()==ID_array && symbol.type.subtype()==decl_type.subtype()) { symbol.type = decl_type; return; // ok } cpp_typecheck.err_location(source_location); cpp_typecheck.str << "symbol `" << symbol.display_name() << "' already declared with different type:" << std::endl; cpp_typecheck.str << "original: " << cpp_typecheck.to_string(symbol.type) << std::endl; cpp_typecheck.str << " new: " << cpp_typecheck.to_string(final_type); throw 0; }
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 java_bytecode_convertt::convert( symbolt &class_symbol, const methodt &m) { class_typet &class_type=to_class_type(class_symbol.type); typet member_type=java_type_from_string(m.signature); assert(member_type.id()==ID_code); const irep_idt method_identifier= id2string(class_symbol.name)+"."+id2string(m.name)+":"+m.signature; code_typet &code_type=to_code_type(member_type); method_return_type=code_type.return_type(); code_typet::parameterst ¶meters=code_type.parameters(); // do we need to add 'this' as a parameter? if(!m.is_static) { code_typet::parametert this_p; const empty_typet empty; const pointer_typet object_ref_type(empty); this_p.type()=object_ref_type; this_p.set_this(); parameters.insert(parameters.begin(), this_p); } variables.clear(); // Do the parameters and locals in the variable table, // which is only available when compiled with -g for(const auto & v : m.local_variable_table) { typet t=java_type_from_string(v.signature); irep_idt identifier=id2string(method_identifier)+"::"+id2string(v.name); symbol_exprt result(identifier, t); result.set(ID_C_base_name, v.name); variables[v.index].symbol_expr=result; } // set up variables array for(std::size_t i=0, param_index=0; i < parameters.size(); ++i) { variables[param_index]; param_index+=get_variable_slots(parameters[i]); } // assign names to parameters for(std::size_t i=0, param_index=0; i < parameters.size(); ++i) { irep_idt base_name, identifier; if(i==0 && parameters[i].get_this()) { base_name="this"; identifier=id2string(method_identifier)+"::"+id2string(base_name); parameters[i].set_base_name(base_name); parameters[i].set_identifier(identifier); } else { // in the variable table? base_name=variables[param_index].symbol_expr.get(ID_C_base_name); identifier=variables[param_index].symbol_expr.get(ID_identifier); if(base_name.empty()) { const typet &type=parameters[i].type(); char suffix=java_char_from_type(type); base_name="arg"+i2string(param_index)+suffix; identifier=id2string(method_identifier)+"::"+id2string(base_name); } parameters[i].set_base_name(base_name); parameters[i].set_identifier(identifier); } // add to symbol table parameter_symbolt parameter_symbol; parameter_symbol.base_name=base_name; parameter_symbol.mode=ID_java; parameter_symbol.name=identifier; parameter_symbol.type=parameters[i].type(); symbol_table.add(parameter_symbol); // add as a JVM variable unsigned slots=get_variable_slots(parameters[i]); variables[param_index].symbol_expr=parameter_symbol.symbol_expr(); param_index+=slots; } class_type.methods().push_back(class_typet::methodt()); class_typet::methodt &method=class_type.methods().back(); method.set_base_name(m.base_name); method.set_name(method_identifier); const bool is_virtual=!m.is_static && !m.is_final; method.set(ID_abstract, m.is_abstract); method.set(ID_is_virtual, is_virtual); if(is_contructor(method)) method.set(ID_constructor, true); method.type()=member_type; // we add the symbol for the method symbolt method_symbol; method_symbol.name=method.get_name(); method_symbol.base_name=method.get_base_name(); method_symbol.mode=ID_java; method_symbol.name=method.get_name(); method_symbol.base_name=method.get_base_name(); if(method.get_base_name()=="<init>") method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ id2string(class_symbol.base_name)+"()"; else method_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+ id2string(method.get_base_name())+"()"; method_symbol.type=member_type; current_method=method_symbol.name; method_has_this=code_type.has_this(); tmp_vars.clear(); method_symbol.value=convert_instructions(m.instructions, code_type); // do we have the method symbol already? const auto s_it=symbol_table.symbols.find(method.get_name()); if(s_it!=symbol_table.symbols.end()) symbol_table.symbols.erase(s_it); // erase, we stubbed it symbol_table.add(method_symbol); }
bool static_lifetime_init( symbol_tablet &symbol_table, const source_locationt &source_location, message_handlert &message_handler) { namespacet ns(symbol_table); symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(INITIALIZE_FUNCTION); if(s_it==symbol_table.symbols.end()) return false; symbolt &init_symbol=s_it->second; init_symbol.value=code_blockt(); init_symbol.value.add_source_location()=source_location; code_blockt &dest=to_code_block(to_code(init_symbol.value)); // add the magic label to hide dest.add(code_labelt("__CPROVER_HIDE", code_skipt())); // do assignments based on "value" // sort alphabetically for reproducible results std::set<std::string> symbols; forall_symbols(it, symbol_table.symbols) symbols.insert(id2string(it->first)); for(const std::string &id : symbols) { const symbolt &symbol=ns.lookup(id); const irep_idt &identifier=symbol.name; if(!symbol.is_static_lifetime) continue; if(symbol.is_type || symbol.is_macro) continue; // special values if(identifier==CPROVER_PREFIX "constant_infinity_uint" || identifier==CPROVER_PREFIX "memory" || identifier=="__func__" || identifier=="__FUNCTION__" || identifier=="__PRETTY_FUNCTION__" || identifier=="argc'" || identifier=="argv'" || identifier=="envp'" || identifier=="envp_size'") continue; // just for linking if(has_prefix(id, CPROVER_PREFIX "architecture_")) continue; const typet &type=ns.follow(symbol.type); // check type if(type.id()==ID_code || type.id()==ID_empty) continue; // We won't try to initialize any symbols that have // remained incomplete. if(symbol.value.is_nil() && symbol.is_extern) // Compilers would usually complain about these // symbols being undefined. continue; if(type.id()==ID_array && to_array_type(type).size().is_nil()) { // C standard 6.9.2, paragraph 5 // adjust the type to an array of size 1 symbol_tablet::symbolst::iterator it= symbol_table.symbols.find(identifier); assert(it!=symbol_table.symbols.end()); it->second.type=type; it->second.type.set(ID_size, from_integer(1, size_type())); } if(type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union) continue; // do not initialize if(symbol.value.id()==ID_nondet) continue; // do not initialize exprt rhs; if(symbol.value.is_nil()) { try { namespacet ns(symbol_table); rhs=zero_initializer(symbol.type, symbol.location, ns, message_handler); assert(rhs.is_not_nil()); } catch(...) { return true; } } else rhs=symbol.value; code_assignt code(symbol.symbol_expr(), rhs); code.add_source_location()=symbol.location; dest.move_to_operands(code); } // call designated "initialization" functions for(const std::string &id : symbols) { const symbolt &symbol=ns.lookup(id); if(symbol.type.id()==ID_code && to_code_type(symbol.type).return_type().id()==ID_constructor) { code_function_callt function_call; function_call.function()=symbol.symbol_expr(); function_call.add_source_location()=source_location; dest.move_to_operands(function_call); } } return false; }