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 java_internal_additions(symbol_tablet &dest) { // add __CPROVER_rounding_mode { symbolt symbol; symbol.base_name="__CPROVER_rounding_mode"; symbol.name=CPROVER_PREFIX "rounding_mode"; symbol.type=signed_int_type(); symbol.mode=ID_C; symbol.is_lvalue=true; symbol.is_state_var=true; symbol.is_thread_local=true; dest.add(symbol); } // add __CPROVER_malloc_object { symbolt symbol; symbol.base_name="__CPROVER_malloc_object"; symbol.name=CPROVER_PREFIX "malloc_object"; symbol.type=pointer_type(empty_typet()); symbol.mode=ID_C; symbol.is_lvalue=true; symbol.is_state_var=true; symbol.is_thread_local=true; dest.add(symbol); } }
void thread_exit_instrumentation(goto_programt &goto_program) { if(goto_program.instructions.empty()) return; // add assertion that all may flags for mutex-locked are gone // at the end goto_programt::targett end=goto_program.instructions.end(); end--; assert(end->is_end_function()); source_locationt source_location=end->source_location; irep_idt function=end->function; goto_program.insert_before_swap(end); exprt mutex_locked_string= string_constantt("mutex-locked"); binary_exprt get_may("get_may"); // NULL is any get_may.op0()=constant_exprt(ID_NULL, pointer_typet(empty_typet())); get_may.op1()=address_of_exprt(mutex_locked_string); end->make_assertion(not_exprt(get_may)); end->source_location=source_location; end->source_location.set_comment("mutexes must not be locked on thread exit"); end->function=function; }
static void create_initialize(symbol_tablet &symbol_table) { symbolt initialize; initialize.name=INITIALIZE; initialize.base_name=INITIALIZE; initialize.mode=ID_java; code_typet type; type.return_type()=empty_typet(); initialize.type=type; code_blockt init_code; namespacet ns(symbol_table); symbol_exprt rounding_mode= ns.lookup(CPROVER_PREFIX "rounding_mode").symbol_expr(); init_code.add( code_assignt(rounding_mode, from_integer(0, rounding_mode.type()))); initialize.value=init_code; if(symbol_table.add(initialize)) throw "failed to add "+std::string(INITIALIZE); }
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; }
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); } } }
bool remove_function_pointerst::is_type_compatible( bool return_value_used, const code_typet &call_type, const code_typet &function_type) { // we are willing to ignore anything that's returned // if we call with 'void' if(!return_value_used) { } else if(type_eq(call_type.return_type(), empty_typet(), ns)) { // ok } else { if(!arg_is_type_compatible(call_type.return_type(), function_type.return_type())) return false; } // let's look at the parameters const code_typet::parameterst &call_parameters=call_type.parameters(); const code_typet::parameterst &function_parameters=function_type.parameters(); if(function_type.has_ellipsis() && function_parameters.empty()) { // always ok } else if(call_type.has_ellipsis() && call_parameters.empty()) { // always ok } else { // we are quite strict here, could be much more generous if(call_parameters.size()!=function_parameters.size()) return false; for(unsigned i=0; i<call_parameters.size(); i++) if(!arg_is_type_compatible(call_parameters[i].type(), function_parameters[i].type())) return false; } return true; }
void c_typecheck_baset::typecheck_gcc_computed_goto(codet &code) { if(code.operands().size()!=1) { err_location(code); error() << "computed-goto expected to have one operand" << eom; throw 0; } exprt &dest=code.op0(); if(dest.id()!=ID_dereference) { err_location(dest); error() << "computed-goto expected to have dereferencing operand" << eom; throw 0; } assert(dest.operands().size()==1); typecheck_expr(dest.op0()); dest.type()=empty_typet(); }
bool java_entry_point( symbol_tablet &symbol_table, const irep_idt &main_class, message_handlert &message_handler) { // check if the entry point is already there if(symbol_table.symbols.find(goto_functionst::entry_point())!= symbol_table.symbols.end()) return false; // silently ignore messaget message(message_handler); symbolt symbol; // main function symbol // find main symbol if(config.main!="") { // Add java:: prefix std::string main_identifier="java::"+config.main; symbol_tablet::symbolst::const_iterator s_it; // Does it have a type signature? (':' suffix) if(config.main.rfind(':')==std::string::npos) { std::string prefix=main_identifier+':'; std::set<irep_idt> matches; for(const auto & s : symbol_table.symbols) if(has_prefix(id2string(s.first), prefix) && s.second.type.id()==ID_code) matches.insert(s.first); if(matches.empty()) { message.error() << "main symbol `" << config.main << "' not found" << messaget::eom; return true; } else if(matches.size()==1) { s_it=symbol_table.symbols.find(*matches.begin()); assert(s_it!=symbol_table.symbols.end()); } else { message.error() << "main symbol `" << config.main << "' is ambiguous:\n"; for(const auto & s : matches) message.error() << " " << s << '\n'; message.error() << messaget::eom; return true; } } else { // just look it up s_it=symbol_table.symbols.find(main_identifier); if(s_it==symbol_table.symbols.end()) { message.error() << "main symbol `" << config.main << "' not found" << messaget::eom; return true; } } // function symbol symbol=s_it->second; if(symbol.type.id()!=ID_code) { message.error() << "main symbol `" << config.main << "' not a function" << messaget::eom; return true; } // check if it has a body if(symbol.value.is_nil()) { message.error() << "main method `" << main_class << "' has no body" << messaget::eom; return true; } } else { // no function given, we look for the main class assert(config.main==""); // are we given a main class? if(main_class.empty()) return false; // silently ignore std::string entry_method= id2string(main_class)+".main"; std::string prefix="java::"+entry_method+":"; // look it up std::set<irep_idt> matches; for(symbol_tablet::symbolst::const_iterator s_it=symbol_table.symbols.begin(); s_it!=symbol_table.symbols.end(); s_it++) { if(s_it->second.type.id()==ID_code && has_prefix(id2string(s_it->first), prefix)) matches.insert(s_it->first); } if(matches.empty()) { // Not found, silently ignore return false; } if(matches.size()>=2) { message.error() << "main method in `" << main_class << "' is ambiguous" << messaget::eom; return true; // give up with error, no main } // function symbol symbol=symbol_table.symbols.find(*matches.begin())->second; // check if it has a body if(symbol.value.is_nil()) { message.error() << "main method `" << main_class << "' has no body" << messaget::eom; return true; // give up with error } } assert(!symbol.value.is_nil()); assert(symbol.type.id()==ID_code); const code_typet &code_type=to_code_type(symbol.type); create_initialize(symbol_table); if(java_static_lifetime_init(symbol_table, symbol.location, message_handler)) return true; code_blockt init_code; // build call to initialization function { symbol_tablet::symbolst::iterator init_it= symbol_table.symbols.find(INITIALIZE); if(init_it==symbol_table.symbols.end()) { message.error() << "failed to find " INITIALIZE " symbol" << messaget::eom; return true; // give up with error } code_function_callt call_init; call_init.lhs().make_nil(); call_init.add_source_location()=symbol.location; call_init.function()=init_it->second.symbol_expr(); init_code.move_to_operands(call_init); } // build call to the main method code_function_callt call_main; call_main.add_source_location()=symbol.location; call_main.function()=symbol.symbol_expr(); const code_typet::parameterst ¶meters= code_type.parameters(); exprt::operandst main_arguments; main_arguments.resize(parameters.size()); for(std::size_t param_number=0; param_number<parameters.size(); param_number++) { bool is_this=param_number==0 && parameters[param_number].get_this(); bool allow_null=config.main!="" && !is_this; main_arguments[param_number]= object_factory(parameters[param_number].type(), init_code, allow_null, symbol_table); } call_main.arguments()=main_arguments; init_code.move_to_operands(call_main); // add "main" symbolt new_symbol; code_typet main_type; main_type.return_type()=empty_typet(); new_symbol.name=goto_functionst::entry_point(); new_symbol.type.swap(main_type); new_symbol.value.swap(init_code); new_symbol.mode=ID_java; if(symbol_table.move(new_symbol)) { message.error() << "failed to move main symbol" << messaget::eom; return true; } return false; }
typet void_type() { return empty_typet(); }
void cpp_typecheckt::convert_function(symbolt &symbol) { code_typet &function_type= to_code_type(template_subtype(symbol.type)); // only a prototype? if(symbol.value.is_nil()) return; // if it is a destructor, add the implicit code if(symbol.type.get(ID_return_type)==ID_destructor) { const symbolt &msymb=lookup(symbol.type.get(ID_C_member_name)); assert(symbol.value.id()==ID_code); assert(symbol.value.get(ID_statement)==ID_block); symbol.value.copy_to_operands(dtor(msymb)); } // enter appropriate scope cpp_save_scopet saved_scope(cpp_scopes); cpp_scopet &function_scope=cpp_scopes.set_scope(symbol.name); // fix the scope's prefix function_scope.prefix+=id2string(symbol.name)+"::"; // genuine function definition -- do the parameter declarations convert_arguments(symbol.mode, function_type); // create "this" if it's a non-static method if(function_scope.is_method && !function_scope.is_static_member) { code_typet::argumentst &arguments=function_type.arguments(); assert(arguments.size()>=1); code_typet::argumentt &this_argument_expr=arguments.front(); function_scope.this_expr=exprt(ID_symbol, this_argument_expr.type()); function_scope.this_expr.set(ID_identifier, this_argument_expr.get(ID_C_identifier)); } else function_scope.this_expr.make_nil(); // do the function body start_typecheck_code(); // save current return type typet old_return_type=return_type; return_type=function_type.return_type(); // constructor, destructor? if(return_type.id()==ID_constructor || return_type.id()==ID_destructor) return_type=empty_typet(); typecheck_code(to_code(symbol.value)); symbol.value.type()=symbol.type; return_type = old_return_type; }
Inputs: Outputs: Purpose: \*******************************************************************/ bool bp_languaget::final( contextt &context, message_handlert &message_handler) { // do main symbol code_typet main_type; main_type.return_type()=empty_typet(); symbolt new_symbol; new_symbol.name="main"; new_symbol.type=main_type; const contextt::symbolst::const_iterator s_it= context.symbols.find("bp::fkt::main"); if(s_it==context.symbols.end()) return false; const symbolt &symbol=s_it->second; code_function_callt call; call.function()=symbol_expr(symbol);
/// turns 'return x' into an assignment to fkt#return_value void remove_returnst::replace_returns( goto_functionst::function_mapt::iterator f_it) { typet return_type=f_it->second.type.return_type(); const irep_idt function_id=f_it->first; // returns something but void? bool has_return_value=return_type!=empty_typet(); if(has_return_value) { // look up the function symbol symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(function_id); assert(s_it!=symbol_table.symbols.end()); symbolt &function_symbol=s_it->second; // make the return type 'void' f_it->second.type.return_type()=empty_typet(); function_symbol.type=f_it->second.type; // add return_value symbol to symbol_table auxiliary_symbolt new_symbol; new_symbol.is_static_lifetime=true; new_symbol.module=function_symbol.module; new_symbol.base_name= id2string(function_symbol.base_name)+RETURN_VALUE_SUFFIX; new_symbol.name=id2string(function_symbol.name)+RETURN_VALUE_SUFFIX; new_symbol.mode=function_symbol.mode; new_symbol.type=return_type; symbol_table.add(new_symbol); } goto_programt &goto_program=f_it->second.body; if(goto_program.empty()) return; if(has_return_value) { Forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_return()) { assert(i_it->code.operands().size()==1); // replace "return x;" by "fkt#return_value=x;" symbol_exprt lhs_expr; lhs_expr.set_identifier(id2string(function_id)+RETURN_VALUE_SUFFIX); lhs_expr.type()=return_type; code_assignt assignment(lhs_expr, i_it->code.op0()); // now turn the `return' into `assignment' i_it->type=ASSIGN; i_it->code=assignment; } } } }
bool java_static_lifetime_init( symbol_tablet &symbol_table, const source_locationt &source_location, message_handlert &message_handler, bool assume_init_pointers_not_null, unsigned max_nondet_array_length) { symbolt &initialize_symbol=symbol_table.lookup(INITIALIZE); code_blockt &code_block=to_code_block(to_code(initialize_symbol.value)); // We need to zero out all static variables, or nondet-initialize if they're // external. Iterate over a copy of the symtab, as its iterators are // invalidated by object_factory: std::list<irep_idt> symbol_names; for(const auto &entry : symbol_table.symbols) symbol_names.push_back(entry.first); for(const auto &symname : symbol_names) { const symbolt &sym=symbol_table.lookup(symname); if(should_init_symbol(sym)) { if(sym.value.is_nil() && sym.type!=empty_typet()) { bool allow_null=!assume_init_pointers_not_null; if(allow_null) { std::string namestr=id2string(sym.symbol_expr().get_identifier()); const std::string suffix="@class_model"; // Static '.class' fields are always non-null. if(has_suffix(namestr, suffix)) allow_null=false; if(allow_null && has_prefix( namestr, "java::java.lang.String.Literal")) allow_null=false; } auto newsym=object_factory( sym.type, code_block, allow_null, symbol_table, max_nondet_array_length, source_location, message_handler); code_assignt assignment(sym.symbol_expr(), newsym); code_block.add(assignment); } else if(sym.value.is_not_nil()) { code_assignt assignment(sym.symbol_expr(), sym.value); assignment.add_source_location()=source_location; code_block.add(assignment); } } } // we now need to run all the <clinit> methods for(symbol_tablet::symbolst::const_iterator it=symbol_table.symbols.begin(); it!=symbol_table.symbols.end(); it++) { if(it->second.base_name=="<clinit>" && it->second.type.id()==ID_code && it->second.mode==ID_java) { code_function_callt function_call; function_call.lhs()=nil_exprt(); function_call.function()=it->second.symbol_expr(); function_call.add_source_location()=source_location; code_block.add(function_call); } } return false; }
bool java_entry_point( symbol_tablet &symbol_table, const irep_idt &main_class, message_handlert &message_handler, bool assume_init_pointers_not_null, size_t max_nondet_array_length) { // check if the entry point is already there if(symbol_table.symbols.find(goto_functionst::entry_point())!= symbol_table.symbols.end()) return false; // silently ignore messaget message(message_handler); main_function_resultt res= get_main_symbol(symbol_table, main_class, message_handler); if(res.stop_convert) return res.stop_convert; symbolt symbol=res.main_function; assert(!symbol.value.is_nil()); assert(symbol.type.id()==ID_code); create_initialize(symbol_table); if(java_static_lifetime_init( symbol_table, symbol.location, message_handler, assume_init_pointers_not_null, max_nondet_array_length)) return true; code_blockt init_code; // build call to initialization function { symbol_tablet::symbolst::iterator init_it= symbol_table.symbols.find(INITIALIZE); if(init_it==symbol_table.symbols.end()) { message.error() << "failed to find " INITIALIZE " symbol" << messaget::eom; return true; // give up with error } code_function_callt call_init; call_init.lhs().make_nil(); call_init.add_source_location()=symbol.location; call_init.function()=init_it->second.symbol_expr(); init_code.move_to_operands(call_init); } // build call to the main method code_function_callt call_main; source_locationt loc=symbol.location; loc.set_function(symbol.name); source_locationt &dloc=loc; call_main.add_source_location()=dloc; call_main.function()=symbol.symbol_expr(); call_main.function().add_source_location()=dloc; if(to_code_type(symbol.type).return_type()!=empty_typet()) { auxiliary_symbolt return_symbol; return_symbol.mode=ID_C; return_symbol.is_static_lifetime=false; return_symbol.name="return'"; return_symbol.base_name="return"; return_symbol.type=to_code_type(symbol.type).return_type(); symbol_table.add(return_symbol); call_main.lhs()=return_symbol.symbol_expr(); } exprt::operandst main_arguments= java_build_arguments( symbol, init_code, symbol_table, assume_init_pointers_not_null, max_nondet_array_length, message_handler); call_main.arguments()=main_arguments; init_code.move_to_operands(call_main); java_record_outputs(symbol, main_arguments, init_code, symbol_table); // add "main" symbolt new_symbol; code_typet main_type; main_type.return_type()=empty_typet(); new_symbol.name=goto_functionst::entry_point(); new_symbol.type.swap(main_type); new_symbol.value.swap(init_code); new_symbol.mode=ID_java; if(symbol_table.move(new_symbol)) { message.error() << "failed to move main symbol" << messaget::eom; return true; } return false; }
void c_typecheck_baset::typecheck_declaration( ansi_c_declarationt &declaration) { if(declaration.get_is_static_assert()) { assert(declaration.operands().size()==2); typecheck_expr(declaration.op0()); typecheck_expr(declaration.op1()); } else { // get storage spec c_storage_spect c_storage_spec(declaration.type()); // first typecheck the type of the declaration typecheck_type(declaration.type()); // mark as 'already typechecked' make_already_typechecked(declaration.type()); codet contract; { exprt spec_requires= static_cast<const exprt&>(declaration.find(ID_C_spec_requires)); contract.add(ID_C_spec_requires).swap(spec_requires); exprt spec_ensures= static_cast<const exprt&>(declaration.find(ID_C_spec_ensures)); contract.add(ID_C_spec_ensures).swap(spec_ensures); } // Now do declarators, if any. for(ansi_c_declarationt::declaratorst::iterator d_it=declaration.declarators().begin(); d_it!=declaration.declarators().end(); d_it++) { c_storage_spect full_spec(declaration.full_type(*d_it)); full_spec|=c_storage_spec; declaration.set_is_inline(full_spec.is_inline); declaration.set_is_static(full_spec.is_static); declaration.set_is_extern(full_spec.is_extern); declaration.set_is_thread_local(full_spec.is_thread_local); declaration.set_is_register(full_spec.is_register); declaration.set_is_typedef(full_spec.is_typedef); declaration.set_is_weak(full_spec.is_weak); symbolt symbol; declaration.to_symbol(*d_it, symbol); current_symbol=symbol; // now check other half of type typecheck_type(symbol.type); if(!full_spec.alias.empty()) { if(symbol.value.is_not_nil()) { error().source_location=symbol.location; error() << "alias attribute cannot be used with a body" << eom; throw 0; } // alias function need not have been declared yet, thus // can't lookup symbol.value=symbol_exprt(full_spec.alias); symbol.is_macro=true; } if(full_spec.section.empty()) apply_asm_label(full_spec.asm_label, symbol); else { std::string asm_name; asm_name=id2string(full_spec.section)+"$$"; if(!full_spec.asm_label.empty()) asm_name+=id2string(full_spec.asm_label); else asm_name+=id2string(symbol.name); apply_asm_label(asm_name, symbol); } irep_idt identifier=symbol.name; d_it->set_name(identifier); typecheck_symbol(symbol); // add code contract (if any); we typecheck this after the // function body done above, so as to have parameter symbols // available symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); assert(s_it!=symbol_table.symbols.end()); symbolt &new_symbol=s_it->second; typecheck_spec_expr(contract, ID_C_spec_requires); typet ret_type=empty_typet(); if(new_symbol.type.id()==ID_code) ret_type=to_code_type(new_symbol.type).return_type(); assert(parameter_map.empty()); if(ret_type.id()!=ID_empty) parameter_map["__CPROVER_return_value"]=ret_type; typecheck_spec_expr(contract, ID_C_spec_ensures); parameter_map.clear(); if(contract.find(ID_C_spec_requires).is_not_nil()) new_symbol.type.add(ID_C_spec_requires)= contract.find(ID_C_spec_requires); if(contract.find(ID_C_spec_ensures).is_not_nil()) new_symbol.type.add(ID_C_spec_ensures)= contract.find(ID_C_spec_ensures); } } }