irep_idt cpp_namet::get_base_name() const { const subt &sub=get_sub(); // find last "::" unsigned base=0; for(unsigned i=0; i<sub.size(); i++) { if(sub[i].id()=="::") base=i+1; } if(base>=sub.size()) return irep_idt(); if(sub[base].id()==ID_name) return sub[base].get(ID_identifier); else if(base+1<sub.size() && sub[base].id()==ID_operator) return "operator"+sub[base+1].id_string(); else if(base+1<sub.size() && sub[base].id()=="~" && sub[base+1].id()==ID_name) return "~"+sub[base+1].get_string(ID_identifier); return irep_idt(); }
std::pair<irep_idt, irep_idt> ssa_exprt::build_identifier( const exprt &expr, const irep_idt &l0, const irep_idt &l1, const irep_idt &l2) { std::ostringstream oss; std::ostringstream l1_object_oss; build_ssa_identifier_rec(expr, l0, l1, l2, oss, l1_object_oss); return std::make_pair(irep_idt(oss.str()), irep_idt(l1_object_oss.str())); }
string_constantt::string_constantt(): exprt(ID_string_constant) { set_value(irep_idt()); type()=typet(ID_array); type().subtype()=char_type(); }
var_mapt::var_infot & var_mapt::operator()( const irep_idt &symbol, const irep_idt &suffix, const typet &type) { assert(symbol!=irep_idt()); std::string full_identifier= id2string(symbol)+id2string(suffix); std::pair<id_mapt::iterator, bool> result; result=id_map.insert(std::pair<irep_idt, var_infot>( full_identifier, var_infot())); if(result.second) // inserted? { result.first->second.full_identifier=full_identifier; result.first->second.symbol=symbol; result.first->second.suffix=suffix; result.first->second.type=type; init(result.first->second); } return result.first->second; }
bool refined_string_typet::is_c_string_type(const typet &type) { if (type.id() == ID_struct) { irep_idt tag = to_struct_type(type).get_tag(); return (tag == irep_idt("__CPROVER_string")); } else return false; }
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 replace_location( source_locationt &dest, const source_locationt &new_location) { // we copy, and then adjust for property_id, property_class // and comment, if necessary irep_idt comment=dest.get_comment(); irep_idt property_class=dest.get_property_class(); irep_idt property_id=dest.get_property_id(); dest=new_location; if(comment!=irep_idt()) dest.set_comment(comment); if(property_class!=irep_idt()) dest.set_property_class(property_class); if(property_id!=irep_idt()) dest.set_property_id(property_id); }
bool refined_string_typet::is_java_deref_string_type(const typet &type) { if(type.id() == ID_struct) { irep_idt tag = to_struct_type(type).get_tag(); return (tag == irep_idt("java.lang.String")); } else return false; }
bool refined_string_typet::is_java_char_sequence_type(const typet &type) { if(type.id() == ID_pointer) { pointer_typet pt = to_pointer_type(type); typet subtype = pt.subtype(); if(subtype.id() == ID_struct) { irep_idt tag = to_struct_type(subtype).get_tag(); return (tag == irep_idt("java.lang.CharSequence")); } else return false; } else return false; }
exprt get_failed_symbol( const symbol_exprt &expr, const namespacet &ns) { const symbolt &symbol=ns.lookup(expr); irep_idt failed_symbol_id=symbol.type.get("#failed_symbol"); if(failed_symbol_id==irep_idt()) return nil_exprt(); const symbolt &failed_symbol=ns.lookup(failed_symbol_id); return symbol_exprt(failed_symbol_id, failed_symbol.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()) 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); } }
void java_bytecode_parse_treet::membert::output(std::ostream &out) const { out << " "; if(is_static) out << "static "; if(is_native) out << "native "; out << name; if(is_method) { out << "\n"; out << " {" << "\n"; for(instructionst::const_iterator i_it=instructions.begin(); i_it!=instructions.end(); i_it++) { if(i_it->source_location.get_line()!=irep_idt()) out << " // " << i_it->source_location << "\n"; out << " " << i_it->address << ": "; out << i_it->statement; for(std::vector<exprt>::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++) { if(a_it!=i_it->args.begin()) out << ","; out << " " << *a_it; } out << "\n"; } out << " }" << "\n"; } else { out << ";"; } out << "\n"; }
irep_idt cpp_namet::get_base_name() const { assert(is_simple_name()); const subt &sub=get_sub(); if(sub.size()==1 && sub.front().id()==ID_name) return sub.front().get(ID_identifier); else if(sub.size()==2 && sub.front().id()==ID_operator) return "operator"+sub[1].id_string(); else if(sub.size()==2 && sub[0].id()=="~" && sub[1].id()==ID_name) return sub[0].id_string()+sub[1].get_string(ID_identifier); else assert(false); return irep_idt(); }
bool goto_program_dereferencet::has_failed_symbol( const exprt &expr, const symbolt *&symbol) { if(expr.id()==ID_symbol) { if(expr.get_bool("#invalid_object")) return false; const symbolt &ptr_symbol=ns.lookup(expr); const irep_idt &failed_symbol= ptr_symbol.type.get("#failed_symbol"); if(failed_symbol==irep_idt()) return false; return !ns.lookup(failed_symbol, symbol); } return false; }
void ansi_c_declaratort::build(irept &src) { typet *p=static_cast<typet *>(&src); // walk down subtype until we hit symbol or "abstract" while(true) { typet &t=*p; if(t.id()==ID_symbol) { set_base_name(t.get(ID_C_base_name)); add_source_location()=t.source_location(); t.make_nil(); break; } else if(t.id()==irep_idt() || t.is_nil()) { //std::cerr << "D: " << src.pretty() << std::endl; assert(0); } else if(t.id()==ID_abstract) { t.make_nil(); break; } else if(t.id()==ID_merged_type) { // we always walk down the _last_ member of a merged type assert(!t.subtypes().empty()); p=&(t.subtypes().back()); } else p=&t.subtype(); } type()=static_cast<const typet &>(src); value().make_nil(); }
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= get_fresh_aux_symbol( code_type.return_type(), "remove_function_pointers", "tmp_return_val", function_call.source_location(), irep_idt(), symbol_table); 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 goto_inlinet::parameter_destruction( const source_locationt &source_location, const irep_idt &function_name, const code_typet &code_type, goto_programt &dest) { const code_typet::parameterst ¶meter_types= code_type.parameters(); // iterates over the types of the parameters for(code_typet::parameterst::const_iterator it=parameter_types.begin(); it!=parameter_types.end(); it++) { const code_typet::parametert ¶meter=*it; const irep_idt &identifier=parameter.get_identifier(); if(identifier==irep_idt()) { error().source_location=source_location; error() << "no identifier for function parameter" << eom; throw 0; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett dead=dest.add_instruction(); dead->make_dead(); dead->code=code_deadt(symbol.symbol_expr()); dead->code.add_source_location()=source_location; dead->source_location=source_location; dead->function=function_name; } } }
void c_typecheck_baset::typecheck_code_type(code_typet &type) { // the return type is still 'subtype()' type.return_type()=type.subtype(); type.remove_subtype(); code_typet::parameterst ¶meters=type.parameters(); // if we don't have any parameters, we assume it's (...) if(parameters.empty()) { type.make_ellipsis(); } else // we do have parameters { // is the last one ellipsis? if(type.parameters().back().id()==ID_ellipsis) { type.make_ellipsis(); type.parameters().pop_back(); } parameter_map.clear(); for(auto ¶m : type.parameters()) { // turn the declarations into parameters if(param.id()==ID_declaration) { ansi_c_declarationt &declaration= to_ansi_c_declaration(param); code_typet::parametert parameter; // first fix type typet &type=parameter.type(); type=declaration.full_type(declaration.declarator()); std::list<codet> tmp_clean_code; tmp_clean_code.swap(clean_code); // ignore side-effects typecheck_type(type); tmp_clean_code.swap(clean_code); adjust_function_parameter(type); // adjust the identifier irep_idt identifier=declaration.declarator().get_name(); // abstract or not? if(identifier==irep_idt()) { // abstract parameter.add_source_location()=declaration.type().source_location(); } else { // make visible now, later parameters might use it parameter_map[identifier]=type; parameter.set_base_name(declaration.declarator().get_base_name()); parameter.add_source_location()= declaration.declarator().source_location(); } // put the parameter in place of the declaration param.swap(parameter); } } parameter_map.clear(); if(parameters.size()==1 && follow(parameters[0].type()).id()==ID_empty) { // if we just have one parameter of type void, remove it parameters.clear(); } } typecheck_type(type.return_type()); // 6.7.6.3: // "A function declarator shall not specify a return type that // is a function type or an array type." const typet &return_type=follow(type.return_type()); if(return_type.id()==ID_array) { error().source_location=type.source_location(); error() << "function must not return array" << eom; throw 0; } if(return_type.id()==ID_code) { error().source_location=type.source_location(); error() << "function must not return function type" << eom; throw 0; } }
unsigned floatbv_typet::get_f() const { const irep_idt &f=get(ID_f); assert(f!=irep_idt()); return unsafe_string2unsigned(id2string(f)); }
unsigned fixedbv_typet::get_integer_bits() const { const irep_idt integer_bits=get(ID_integer_bits); assert(integer_bits!=irep_idt()); return unsafe_string2unsigned(id2string(integer_bits)); }
exprt boolbvt::bv_get_rec( const bvt &bv, const std::vector<bool> &unknown, std::size_t offset, const typet &type) const { if(type.id()==ID_symbol) return bv_get_rec(bv, unknown, offset, ns.follow(type)); std::size_t width=boolbv_width(type); assert(bv.size()==unknown.size()); assert(bv.size()>=offset+width); if(type.id()==ID_bool) { if(!unknown[offset]) { switch(prop.l_get(bv[offset]).get_value()) { case tvt::tv_enumt::TV_FALSE: return false_exprt(); case tvt::tv_enumt::TV_TRUE: return true_exprt(); default: return false_exprt(); // default } } return nil_exprt(); } bvtypet bvtype=get_bvtype(type); if(bvtype==IS_UNKNOWN) { if(type.id()==ID_array) { const typet &subtype=type.subtype(); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { exprt::operandst op; op.reserve(width/sub_width); for(std::size_t new_offset=0; new_offset<width; new_offset+=sub_width) { op.push_back( bv_get_rec(bv, unknown, offset+new_offset, subtype)); } exprt dest=exprt(ID_array, type); dest.operands().swap(op); return dest; } } else if(type.id()==ID_struct_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_struct_tag_type(type))); } else if(type.id()==ID_union_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_union_tag_type(type))); } else if(type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); std::size_t new_offset=0; exprt::operandst op; op.reserve(components.size()); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=ns.follow(it->type()); op.push_back(nil_exprt()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { op.back()=bv_get_rec(bv, unknown, offset+new_offset, subtype); new_offset+=sub_width; } } struct_exprt dest(type); dest.operands().swap(op); return dest; } else if(type.id()==ID_union) { const union_typet &union_type=to_union_type(type); const union_typet::componentst &components=union_type.components(); assert(!components.empty()); // Any idea that's better than just returning the first component? std::size_t component_nr=0; union_exprt value(union_type); value.set_component_name( components[component_nr].get_name()); const typet &subtype=components[component_nr].type(); value.op()=bv_get_rec(bv, unknown, offset, subtype); return value; } else if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width%sub_width==0) { std::size_t size=width/sub_width; exprt value(ID_vector, type); value.operands().resize(size); for(std::size_t i=0; i<size; i++) value.operands()[i]= bv_get_rec(bv, unknown, i*sub_width, subtype); return value; } } else if(type.id()==ID_complex) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width==sub_width*2) { exprt value(ID_complex, type); value.operands().resize(2); value.op0()=bv_get_rec(bv, unknown, 0*sub_width, subtype); value.op1()=bv_get_rec(bv, unknown, 1*sub_width, subtype); return value; } } } std::string value; for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++) { char ch; if(unknown[bit_nr]) ch='0'; else switch(prop.l_get(bv[bit_nr]).get_value()) { case tvt::tv_enumt::TV_FALSE: ch='0'; break; case tvt::tv_enumt::TV_TRUE: ch='1'; break; case tvt::tv_enumt::TV_UNKNOWN: ch='0'; break; default: assert(false); } value=ch+value; } switch(bvtype) { case IS_UNKNOWN: if(type.id()==ID_string) { mp_integer int_value=binary2integer(value, false); irep_idt s; if(int_value>=string_numbering.size()) s=irep_idt(); else s=string_numbering[int_value.to_long()]; return constant_exprt(s, type); } break; case IS_RANGE: { mp_integer int_value=binary2integer(value, false); mp_integer from=string2integer(type.get_string(ID_from)); constant_exprt value_expr(type); value_expr.set_value(integer2string(int_value+from)); return value_expr; } break; default: case IS_C_ENUM: constant_exprt value_expr(type); value_expr.set_value(value); return value_expr; } return nil_exprt(); }
void legacy_message_streamt::error_parse_line( unsigned level, const std::string &line) { std::string error_msg=line; if(has_prefix(line, "file ")) { const char *tptr=line.c_str(); int state=0; std::string file, line_no, column, _error_msg, function; tptr+=5; char previous=0; while(*tptr!=0) { if(strncmp(tptr, " line ", 6)==0 && state!=4) { state=1; tptr+=6; continue; } else if(strncmp(tptr, " column ", 8)==0 && state!=4) { state=2; tptr+=8; continue; } else if(strncmp(tptr, " function ", 10)==0 && state!=4) { state=3; tptr+=10; continue; } else if(*tptr==':' && state!=4) { if(tptr[1]==' ' && previous!=':') { state=4; tptr++; while(*tptr==' ') tptr++; continue; } } if(state==0) // file file+=*tptr; else if(state==1) // line number line_no+=*tptr; else if(state==2) // column column+=*tptr; else if(state==3) // function function+=*tptr; else if(state==4) // error message _error_msg+=*tptr; previous=*tptr; tptr++; } if(state==4) { saved_error_location.id(irep_idt()); saved_error_location.set_line(line_no); saved_error_location.set_file(file); saved_error_location.set_column(column); error_msg=_error_msg; saved_error_location.set_function(function); } } else if(has_prefix(line, "In file included from ")) { } else { const char *tptr=line.c_str(); int state=0; std::string file, line_no; while(*tptr!=0) { if(state==0) { if(*tptr==':') state++; else file+=*tptr; } else if(state==1) { if(*tptr==':') state++; else if(isdigit(*tptr)) line_no+=*tptr; else state=3; } tptr++; } if(state==2) { saved_error_location.id(irep_idt()); saved_error_location.set_line(line_no); saved_error_location.set_file(file); saved_error_location.set_function(""); saved_error_location.set_column(""); } } if(message_handler!=NULL) message_handler->print( level, error_msg, sequence_number++, saved_error_location); }
exprt convert_float_literal(const std::string &src) { mp_integer significand; mp_integer exponent; bool is_float, is_long, is_imaginary; bool is_decimal, is_float80, is_float128; // GCC extensions unsigned base; parse_float(src, significand, exponent, base, is_float, is_long, is_imaginary, is_decimal, is_float80, is_float128); exprt result=exprt(ID_constant); result.set(ID_C_cformat, src); // In ANSI-C, float literals are double by default, // unless marked with 'f'. // All of these can be complex as well. // This can be overriden with // config.ansi_c.single_precision_constant. if(is_float) result.type()=float_type(); else if(is_long) result.type()=long_double_type(); else if(is_float80) { result.type()=ieee_float_spect(64, 15).to_type(); result.type().set(ID_C_c_type, ID_long_double); } else if(is_float128) { result.type()=ieee_float_spect::quadruple_precision().to_type(); result.type().set(ID_C_c_type, ID_gcc_float128); } else { // default if(config.ansi_c.single_precision_constant) result.type()=float_type(); // default else result.type()=double_type(); // default } if(is_decimal) { // TODO - should set ID_gcc_decimal32/ID_gcc_decimal64/ID_gcc_decimal128, // but these aren't handled anywhere } if(config.ansi_c.use_fixed_for_float) { unsigned width=result.type().get_int(ID_width); unsigned fraction_bits; const irep_idt integer_bits=result.type().get(ID_integer_bits); assert(width!=0); if(integer_bits==irep_idt()) fraction_bits=width/2; // default else fraction_bits=width-safe_string2int(id2string(integer_bits)); mp_integer factor=mp_integer(1)<<fraction_bits; mp_integer value=significand*factor; if(value!=0) { if(exponent<0) value/=power(base, -exponent); else { value*=power(base, exponent); if(value>=power(2, width-1)) { // saturate: use "biggest value" value=power(2, width-1)-1; } else if(value<=-power(2, width-1)-1) { // saturate: use "smallest value" value=-power(2, width-1); } } } result.set(ID_value, integer2binary(value, width)); } else { ieee_floatt a; a.spec=to_floatbv_type(result.type()); if(base==10) a.from_base10(significand, exponent); else if(base==2) // hex a.build(significand, exponent); else assert(false); result.set(ID_value, integer2binary(a.pack(), a.spec.width())); } if(is_imaginary) { complex_typet complex_type; complex_type.subtype()=result.type(); exprt complex_expr(ID_complex, complex_type); complex_expr.operands().resize(2); complex_expr.op0()=gen_zero(result.type()); complex_expr.op1()=result; return complex_expr; } return result; }
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; } } }
void c_typecheck_baset::typecheck_compound_body( struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); struct_union_typet::componentst old_components; old_components.swap(components); // We get these as declarations! for(auto &decl : old_components) { // the arguments are member declarations or static assertions assert(decl.id()==ID_declaration); ansi_c_declarationt &declaration= to_ansi_c_declaration(static_cast<exprt &>(decl)); if(declaration.get_is_static_assert()) { struct_union_typet::componentt new_component; new_component.id(ID_static_assert); new_component.add_source_location()=declaration.source_location(); new_component.operands().swap(declaration.operands()); assert(new_component.operands().size()==2); components.push_back(new_component); } else { // do first half of type typecheck_type(declaration.type()); make_already_typechecked(declaration.type()); for(const auto &declarator : declaration.declarators()) { struct_union_typet::componentt new_component; new_component.add_source_location()= declarator.source_location(); new_component.set(ID_name, declarator.get_base_name()); new_component.set(ID_pretty_name, declarator.get_base_name()); new_component.type()=declaration.full_type(declarator); typecheck_type(new_component.type()); if(!is_complete_type(new_component.type()) && (new_component.type().id()!=ID_array || !to_array_type(new_component.type()).is_incomplete())) { error().source_location=new_component.type().source_location(); error() << "incomplete type not permitted here" << eom; throw 0; } components.push_back(new_component); } } } unsigned anon_member_counter=0; // scan for anonymous members, and name them for(auto &member : components) { if(member.get_name()!=irep_idt()) continue; member.set_name("$anon"+std::to_string(anon_member_counter++)); member.set_anonymous(true); } // scan for duplicate members { std::unordered_set<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { error().source_location=it->source_location(); error() << "duplicate member '" << it->get_name() << '\'' << eom; throw 0; } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct || type.id()==ID_union) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &c_type=it->type(); if(c_type.id()==ID_array && to_array_type(c_type).is_incomplete()) { // needs to be last member if(type.id()==ID_struct && it!=--components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; throw 0; } // make it zero-length c_type.id(ID_array); c_type.set(ID_size, from_integer(0, index_type())); } } } // We may add some minimal padding inside and at // the end of structs and // as additional member for unions. if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); else if(type.id()==ID_union) add_padding(to_union_type(type), *this); // Now remove zero-width bit-fields, these are just // for adjusting alignment. for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // blank { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()==0) it=components.erase(it); else it++; } // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { error().source_location=it->source_location(); error() << "failed _Static_assert" << eom; throw 0; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
void c_typecheck_baset::typecheck_array_type(array_typet &type) { exprt &size=type.size(); source_locationt source_location=size.find_source_location(); // check subtype typecheck_type(type.subtype()); // we don't allow void as subtype if(follow(type.subtype()).id()==ID_empty) { error().source_location=type.source_location(); error() << "array of voids" << eom; throw 0; } // check size, if any if(size.is_not_nil()) { typecheck_expr(size); make_index_type(size); // The size need not be a constant! // We simplify it, for the benefit of array initialisation. exprt tmp_size=size; add_rounding_mode(tmp_size); simplify(tmp_size, *this); if(tmp_size.is_constant()) { mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "failed to convert constant: " << tmp_size.pretty() << eom; throw 0; } if(s<0) { error().source_location=source_location; error() << "array size must not be negative, " "but got " << s << eom; throw 0; } size=tmp_size; } else if(tmp_size.id()==ID_infinity) { size=tmp_size; } else if(tmp_size.id()==ID_symbol && tmp_size.type().get_bool(ID_C_constant)) { // We allow a constant variable as array size, assuming // it won't change. // This criterion can be tricked: // Of course we can modify a 'const' symbol, e.g., // using a pointer type cast. Interestingly, // at least gcc 4.2.1 makes the very same mistake! size=tmp_size; } else { // not a constant and not infinity assert(current_symbol_id!=irep_idt()); const symbolt &base_symbol=lookup(current_symbol_id); // Need to pull out! We insert new symbol. source_locationt source_location=size.find_source_location(); unsigned count=0; irep_idt temp_identifier; std::string suffix; do { suffix="$array_size"+std::to_string(count); temp_identifier=id2string(base_symbol.name)+suffix; count++; } while(symbol_table.symbols.find(temp_identifier)!= symbol_table.symbols.end()); // add the symbol to symbol table auxiliary_symbolt new_symbol; new_symbol.name=temp_identifier; new_symbol.pretty_name=id2string(base_symbol.pretty_name)+suffix; new_symbol.base_name=id2string(base_symbol.base_name)+suffix; new_symbol.type=size.type(); new_symbol.type.set(ID_C_constant, true); new_symbol.is_type=false; new_symbol.is_static_lifetime=false; new_symbol.value.make_nil(); new_symbol.location=source_location; symbol_table.add(new_symbol); // produce the code that declares and initializes the symbol symbol_exprt symbol_expr; symbol_expr.set_identifier(temp_identifier); symbol_expr.type()=new_symbol.type; code_declt declaration(symbol_expr); declaration.add_source_location()=source_location; code_assignt assignment; assignment.lhs()=symbol_expr; assignment.rhs()=size; assignment.add_source_location()=source_location; // store the code clean_code.push_back(declaration); clean_code.push_back(assignment); // fix type size=symbol_expr; } } }
void goto_checkt::goto_check(goto_functiont &goto_function) { { const symbolt *init_symbol; if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) mode=init_symbol->mode; } assertions.clear(); local_bitvector_analysist local_bitvector_analysis_obj(goto_function); local_bitvector_analysis=&local_bitvector_analysis_obj; goto_programt &goto_program=goto_function.body; Forall_goto_program_instructions(it, goto_program) { t=it; goto_programt::instructiont &i=*it; new_code.clear(); // we clear all recorded assertions if // 1) we want to generate all assertions or // 2) the instruction is a branch target if(retain_trivial || i.is_target()) assertions.clear(); check(i.guard); // magic ERROR label? for(optionst::value_listt::const_iterator l_it=error_labels.begin(); l_it!=error_labels.end(); l_it++) { if(std::find(i.labels.begin(), i.labels.end(), *l_it)!=i.labels.end()) { goto_program_instruction_typet type= enable_assert_to_assume?ASSUME:ASSERT; goto_programt::targett t=new_code.add_instruction(type); t->guard=false_exprt(); t->source_location=i.source_location; t->source_location.set_property_class("error label"); t->source_location.set_comment("error label "+*l_it); t->source_location.set("user-provided", true); } } if(i.is_other()) { const irep_idt &statement=i.code.get(ID_statement); if(statement==ID_expression) { check(i.code); } else if(statement==ID_printf) { forall_operands(it, i.code) check(*it); } } else if(i.is_assign()) { const code_assignt &code_assign=to_code_assign(i.code); check(code_assign.lhs()); check(code_assign.rhs()); // the LHS might invalidate any assertion invalidate(code_assign.lhs()); } else if(i.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(i.code); // for Java, need to check whether 'this' is null // on non-static method invocations if(mode==ID_java && enable_pointer_check && !code_function_call.arguments().empty() && code_function_call.function().type().id()==ID_code && to_code_type(code_function_call.function().type()).has_this()) { exprt pointer=code_function_call.arguments()[0]; local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "this is null on method invokation", "pointer dereference", i.source_location, pointer, guardt()); } } forall_operands(it, code_function_call) check(*it); // the call might invalidate any assertion assertions.clear(); } else if(i.is_return()) { if(i.code.operands().size()==1) { check(i.code.op0()); // the return value invalidate any assertion invalidate(i.code.op0()); } } else if(i.is_throw()) { if(i.code.get_statement()==ID_expression && i.code.operands().size()==1 && i.code.op0().operands().size()==1) { // must not throw NULL exprt pointer=i.code.op0().op0(); if(pointer.type().subtype().get(ID_identifier)!="java::java.lang.AssertionError") { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "throwing null", "pointer dereference", i.source_location, pointer, guardt()); } } // this has no successor assertions.clear(); } else if(i.is_assert()) { if(i.source_location.get_bool("user-provided") && i.source_location.get_property_class()!="error label" && !enable_assertions) i.type=SKIP; } else if(i.is_assume()) { if(!enable_assumptions) i.type=SKIP; } else if(i.is_dead()) { if(enable_pointer_check) { assert(i.code.operands().size()==1); const symbol_exprt &variable=to_symbol_expr(i.code.op0()); // is it dirty? if(local_bitvector_analysis->dirty(variable)) { // need to mark the dead variable as dead goto_programt::targett t=new_code.add_instruction(ASSIGN); exprt address_of_expr=address_of_exprt(variable); exprt lhs=ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr(); if(!base_type_eq(lhs.type(), address_of_expr.type(), ns)) address_of_expr.make_typecast(lhs.type()); exprt rhs=if_exprt( side_effect_expr_nondett(bool_typet()), address_of_expr, lhs, lhs.type()); t->source_location=i.source_location; t->code=code_assignt(lhs, rhs); t->code.add_source_location()=i.source_location; } } } else if(i.is_end_function()) { if(i.function==goto_functionst::entry_point() && enable_memory_leak_check) { const symbolt &leak=ns.lookup(CPROVER_PREFIX "memory_leak"); const symbol_exprt leak_expr=leak.symbol_expr(); // add self-assignment to get helpful counterexample output goto_programt::targett t=new_code.add_instruction(); t->make_assignment(); t->code=code_assignt(leak_expr, leak_expr); source_locationt source_location; source_location.set_function(i.function); equal_exprt eq(leak_expr, gen_zero(ns.follow(leak.type))); add_guarded_claim( eq, "dynamically allocated memory never freed", "memory-leak", source_location, eq, guardt()); } } for(goto_programt::instructionst::iterator i_it=new_code.instructions.begin(); i_it!=new_code.instructions.end(); i_it++) { if(i_it->source_location.is_nil()) { i_it->source_location.id(irep_idt()); if(it->source_location.get_file()!=irep_idt()) i_it->source_location.set_file(it->source_location.get_file()); if(it->source_location.get_line()!=irep_idt()) i_it->source_location.set_line(it->source_location.get_line()); if(it->source_location.get_function()!=irep_idt()) i_it->source_location.set_function(it->source_location.get_function()); if(it->source_location.get_column()!=irep_idt()) i_it->source_location.set_column(it->source_location.get_column()); } if(i_it->function==irep_idt()) i_it->function=it->function; } // insert new instructions -- make sure targets are not moved while(!new_code.instructions.empty()) { goto_program.insert_before_swap(it, new_code.instructions.front()); new_code.instructions.pop_front(); it++; } }
std::string type2name(const typet &type) { std::string result; // qualifiers first if(type.get_bool(ID_C_constant)) result+="c"; if(type.get_bool(ID_C_restricted)) result+="r"; if(type.get_bool(ID_C_volatile)) result+="v"; if(type.id()==irep_idt()) throw "Empty type encountered."; else if(type.id()==ID_empty) result+="V"; else if(type.id()==ID_signedbv) result+="S" + type.get_string(ID_width); else if(type.id()==ID_unsignedbv) result+="U" + type.get_string(ID_width); else if(type.id()==ID_bool) result+="B"; else if(type.id()==ID_integer) result+="I"; else if(type.id()==ID_real) result+="R"; else if(type.id()==ID_complex) result+="C"; else if(type.id()==ID_floatbv) result+="F" + type.get_string(ID_width); else if(type.id()==ID_fixedbv) result+="X" + type.get_string(ID_width); else if(type.id()==ID_natural) result+="N"; else if(type.id()==ID_pointer) result+="*"; else if(type.id()==ID_reference) result+="&"; else if(type.id()==ID_code) { const code_typet &t=to_code_type(type); const code_typet::argumentst arguments=t.arguments(); result+="P("; for(code_typet::argumentst::const_iterator it=arguments.begin(); it!=arguments.end(); it++) { result+=type2name(it->type()); result+="'" + id2string(it->get_identifier()) + "'|"; } result.resize(result.size()-1); result+=")"; } else if(type.id()==ID_array) { const array_typet &t=to_array_type(type); if(t.size().is_nil()) result+="ARR?"; else result+="ARR"+t.size().get_string(ID_value); } else if(type.id()==ID_symbol) { result+="SYM#"+type.get_string(ID_identifier)+"#"; } else if(type.id()==ID_struct || type.id()==ID_union) { if(type.id()==ID_struct) result+="ST"; if(type.id()==ID_union) result+="UN"; const struct_union_typet &t=to_struct_union_type(type); const struct_union_typet::componentst &components = t.components(); result+="["; for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it!=components.begin()) result+="|"; result+=type2name(it->type()); result+="'"+it->get_string(ID_name)+"'|"; } result+="]"; } else if(type.id()==ID_incomplete_struct) result +="ST?"; else if(type.id()==ID_incomplete_union) result +="UN?"; else if(type.id()==ID_c_enum) result +="EN"+type.get_string(ID_width); else if(type.id()==ID_incomplete_c_enum) result +="EN?"; else if(type.id()==ID_c_bitfield) result+="BF"+type.get_string(ID_size); else if(type.id()==ID_vector) result+="VEC"+type.get_string(ID_size); else throw (std::string("Unknown type '") + type.id_string() + "' encountered."); if(type.has_subtype()) { result+="{"; result+=type2name(type.subtype()); result+="}"; } if(type.has_subtypes()) { result+="$"; forall_subtypes(it, type) { result+=type2name(*it); result+="|"; }
exprt convert_float_literal(const std::string &src) { mp_integer significand; mp_integer exponent; bool is_float, is_long, is_fixed, is_accum; unsigned base; parse_float(src, significand, exponent, base, is_float, is_long, is_fixed, is_accum); exprt result=exprt(ID_constant); result.set(ID_C_cformat, src); // In ANSI-C, float literals are double by default // unless marked with 'f'. if(is_float) { result.type()=float_type(); result.type().set(ID_C_cpp_type, ID_float); } else if(is_long) { result.type()=long_double_type(); result.type().set(ID_C_cpp_type, ID_long_double); } else if(is_fixed) { result.type()=fixed_type(); result.type().set(ID_C_cpp_type, ID_fixed); } else if(is_accum) { result.type()=accum_type(); result.type().set(ID_C_cpp_type, ID_accum); } else { result.type()=double_type(); // default result.type().set(ID_C_cpp_type, ID_double); } if(config.ansi_c.use_fixed_for_float || is_fixed || is_accum) { unsigned width=result.type().get_int(ID_width); unsigned fraction_bits; const irep_idt integer_bits=result.type().get(ID_integer_bits); assert(width!=0); if(is_fixed) { fraction_bits = width - 1; } else if(is_accum) { fraction_bits = width - 9; } else if(integer_bits==irep_idt()) fraction_bits=width/2; // default else fraction_bits=width-safe_string2int(id2string(integer_bits)); mp_integer factor=mp_integer(1)<<fraction_bits; mp_integer value=significand*factor; if(value!=0) { if(exponent<0) value/=power(base, -exponent); else { value*=power(base, exponent); if(value>=power(2, width-1)) { // saturate: use "biggest value" value=power(2, width-1)-1; } else if(value<=-power(2, width-1)-1) { // saturate: use "smallest value" value=-power(2, width-1); } } } result.set(ID_value, integer2binary(value, width)); } else { ieee_floatt a; a.spec=to_floatbv_type(result.type()); if(base==10) a.from_base10(significand, exponent); else if(base==2) // hex a.build(significand, exponent); else assert(false); result.set(ID_value, integer2binary(a.pack(), a.spec.width())); } return result; }
void build_goto_trace( const path_symex_statet &state, const decision_proceduret &decision_procedure, goto_tracet &goto_trace) { // follow the history in the state, // but in a forwards-fashion std::vector<path_symex_step_reft> steps; state.history.build_history(steps); unsigned step_nr; for(step_nr=0; step_nr<steps.size(); step_nr++) { const path_symex_stept &step=*steps[step_nr]; goto_trace_stept trace_step; assert(!step.pc.is_nil()); trace_step.pc=state.locs[step.pc].target; trace_step.thread_nr=step.thread_nr; trace_step.step_nr=step_nr; const goto_programt::instructiont &instruction=*trace_step.pc; switch(instruction.type) { case ASSIGN: trace_step.type=goto_trace_stept::ASSIGNMENT; trace_step.full_lhs=step.full_lhs; trace_step.full_lhs_value=decision_procedure.get(step.ssa_lhs); break; case DECL: trace_step.type=goto_trace_stept::DECL; trace_step.full_lhs=step.full_lhs; trace_step.lhs_object=ssa_exprt(step.full_lhs); trace_step.full_lhs_value=decision_procedure.get(step.ssa_lhs); break; case DEAD: trace_step.type=goto_trace_stept::DEAD; break; case ASSUME: trace_step.type=goto_trace_stept::ASSUME; break; case FUNCTION_CALL: trace_step.type=goto_trace_stept::FUNCTION_CALL; break; case END_FUNCTION: trace_step.type=goto_trace_stept::FUNCTION_RETURN; break; case START_THREAD: trace_step.type=goto_trace_stept::SPAWN; break; case ATOMIC_BEGIN: trace_step.type=goto_trace_stept::ATOMIC_BEGIN; break; case ATOMIC_END: trace_step.type=goto_trace_stept::ATOMIC_END; break; default: trace_step.type=goto_trace_stept::LOCATION; } goto_trace.add_step(trace_step); } // add assertion const goto_programt::instructiont &instruction= *state.get_instruction(); assert(instruction.is_assert()); { goto_trace_stept trace_step; trace_step.pc=state.get_instruction(); trace_step.thread_nr=state.get_current_thread(); trace_step.step_nr=step_nr; trace_step.type=goto_trace_stept::ASSERT; const irep_idt &comment= instruction.source_location.get_comment(); if(comment!=irep_idt()) trace_step.comment=id2string(comment); else trace_step.comment="assertion"; goto_trace.add_step(trace_step); } }