From 97df4f557831d4cb19e244beeda661ca478e66a6 Mon Sep 17 00:00:00 2001 From: Natalia Glagoleva Date: Fri, 25 Mar 2016 10:38:19 -0700 Subject: [PATCH] c++ compatibility: To generate C++ compatible code add --lang-cpp to cmith command line. Previously you'd also need to add --no-consts --no-volatiles. Consts and volatiles are supported now, with limitation: "--match-exact-qualifiers --no-vol-struct-union-fields --no-const-struct-union-fields" are auto-added. New switch: --const-struct-union-fields|--no-const-struct-union-fields Note: Mixing signed and unsigned int pointers isn't supported anymore. Explicit casts were emitted for these cases, but casts need to take CVqualifiers into account. --- src/CGOptions.cpp | 11 ++ src/CGOptions.h | 6 + src/CVQualifiers.cpp | 56 +++++- src/Constant.cpp | 8 +- src/Probabilities.cpp | 4 +- src/RandomProgramGenerator.cpp | 15 ++ src/Type.cpp | 311 +++++++++++++++++++++++++-------- src/Type.h | 25 ++- 8 files changed, 347 insertions(+), 89 deletions(-) diff --git a/src/CGOptions.cpp b/src/CGOptions.cpp index e3cd12761..9d4cb8957 100644 --- a/src/CGOptions.cpp +++ b/src/CGOptions.cpp @@ -191,6 +191,7 @@ DEFINE_GETTER_SETTER_BOOL(use_embedded_assigns); DEFINE_GETTER_SETTER_BOOL(use_comma_exprs); DEFINE_GETTER_SETTER_BOOL(take_union_field_addr); DEFINE_GETTER_SETTER_BOOL(vol_struct_union_fields); +DEFINE_GETTER_SETTER_BOOL(const_struct_union_fields); DEFINE_GETTER_SETTER_BOOL(lang_cpp); void @@ -299,12 +300,22 @@ CGOptions::set_default_settings(void) use_comma_exprs(true); take_union_field_addr(true); vol_struct_union_fields(true); + const_struct_union_fields(true); addr_taken_of_locals(true); lang_cpp(false); set_default_builtin_kinds(); } +// Add options necessary for cpp +void +CGOptions::fix_options_for_cpp(void) +{ + match_exact_qualifiers(true); + vol_struct_union_fields(false); // makes implementation of volatile structs easier + const_struct_union_fields(false); // restriction of current implementation; TODO +} + /* looking for the platform info file in the working directory and load platform specific information. If not found, use diff --git a/src/CGOptions.h b/src/CGOptions.h index d2c164600..188b22afa 100644 --- a/src/CGOptions.h +++ b/src/CGOptions.h @@ -444,6 +444,9 @@ class CGOptions { static bool vol_struct_union_fields(void); static bool vol_struct_union_fields(bool p); + static bool const_struct_union_fields(void); + static bool const_struct_union_fields(bool p); + static int int_size(void); static void int_size(int p) { int_size_ = p;} @@ -459,6 +462,8 @@ class CGOptions { static void disable_builtin_kinds(const string &kinds); static bool enabled_builtin(const string &ks); + static void fix_options_for_cpp(void); + private: static bool enabled_builtin_kind(const string &kind); @@ -598,6 +603,7 @@ class CGOptions { static int pointer_size_; static bool take_union_field_addr_; static bool vol_struct_union_fields_; + static bool const_struct_union_fields_; static Reducer* reducer_; // flag to indicate language diff --git a/src/CVQualifiers.cpp b/src/CVQualifiers.cpp index 8f40fe320..4389ff8e4 100644 --- a/src/CVQualifiers.cpp +++ b/src/CVQualifiers.cpp @@ -284,6 +284,26 @@ CVQualifiers::random_qualifiers(const Type* t, Effect::Access access, return random_qualifiers(t, access, cg_context, no_volatile, RegularConstProb, RegularVolatileProb); } +static bool is_volatile_ok_on_one_level(const Type* t) +{ + if (!CGOptions::lang_cpp()) return true; + bool volatile_ok = (t->eType != eStruct && t->eType != eUnion) || (t->has_assign_ops()); + // Union with a struct field: we can't make it volatile, or we won't be able to assign to/from that field + if (volatile_ok && (t->eType == eUnion)){ + for (const auto& field : t->fields){ + if (field->eType == eStruct){ + volatile_ok = false; + break; + } + else if (field->eType == eUnion){ + volatile_ok = is_volatile_ok_on_one_level(field); + if (!volatile_ok) break; + } + } + } + return volatile_ok; +} + CVQualifiers CVQualifiers::random_qualifiers(const Type* t, Effect::Access access, const CGContext &cg_context, bool no_volatile, unsigned int const_prob, unsigned int volatile_prob) @@ -298,22 +318,42 @@ CVQualifiers::random_qualifiers(const Type* t, Effect::Access access, const CGCo const Effect &effect_context = cg_context.get_effect_context(); // set random volatile/const properties for each level of indirection for pointers + // First set up the vectors with correct number of qualifiers: + unsigned level = 0; const Type* tmp = t->ptr_type; while (tmp) { - DEPTH_GUARD_BY_DEPTH_RETURN(2, ret_qfer); - isVolatile = rnd_flipcoin(volatile_prob); - ERROR_GUARD(ret_qfer); + ++level; + is_consts.push_back(false); + is_volatiles.push_back(false); + tmp = tmp->ptr_type; + } + // Then make the random properties (properties need to be in reverse order): + tmp = t->ptr_type; + while (tmp) { + bool volatile_ok = is_volatile_ok_on_one_level(tmp); + if (volatile_ok){ + DEPTH_GUARD_BY_DEPTH_RETURN(2, ret_qfer); + isVolatile = rnd_flipcoin(volatile_prob); + ERROR_GUARD(ret_qfer); + } + else{ + DEPTH_GUARD_BY_DEPTH_RETURN(1, ret_qfer); + isVolatile = false; + } isConst = rnd_flipcoin(const_prob); ERROR_GUARD(ret_qfer); if (isVolatile && isConst && !CGOptions::allow_const_volatile()) { isConst = false; } - is_consts.push_back(isConst); - is_volatiles.push_back(isVolatile); + assert(level > 0); + is_consts[level-1] = isConst; + is_volatiles[level-1] = isVolatile; + --level; tmp = tmp->ptr_type; } + // set random volatile/const properties for variable itself - bool volatile_ok = effect_context.is_side_effect_free(); + bool volatile_ok = effect_context.is_side_effect_free() && is_volatile_ok_on_one_level(t); bool const_ok = (access != Effect::WRITE); isVolatile = false; @@ -688,8 +728,8 @@ CVQualifiers::get_all_qualifiers(vector &quals, unsigned int const qual_enumerator.add_bool_elem("volatile_prob", volatile_prob); Enumerator *i; for (i = qual_enumerator.begin(); i != qual_enumerator.end(); i = i->next()) { - bool isConst = i->get_elem("const_prob"); - bool isVolatile = i->get_elem("volatile_prob"); + bool isConst = i->get_elem("const_prob") != 0; + bool isVolatile = i->get_elem("volatile_prob") != 0; vector consts; vector volatiles; diff --git a/src/Constant.cpp b/src/Constant.cpp index 37c4e2d7b..dcd152ef6 100644 --- a/src/Constant.cpp +++ b/src/Constant.cpp @@ -527,18 +527,20 @@ Constant::get_type(void) const void Constant::Output(std::ostream &out) const { - output_cast(out); //enclose negative numbers in parenthesis to avoid syntax errors such as "--8" if (!value.empty() && value[0] == '-') { - out << "(" << value << ")"; + output_cast(out); + out << "(" << value << ")"; } else if (type->eType == ePointer && equals(0)){ + // don't output cast for NULL: if (CGOptions::lang_cpp()) { out << "NULL"; } else { out << "(void*)" << value; } } else { - out << value; + output_cast(out); + out << value; } } diff --git a/src/Probabilities.cpp b/src/Probabilities.cpp index d6047d436..d82e6d529 100644 --- a/src/Probabilities.cpp +++ b/src/Probabilities.cpp @@ -565,7 +565,7 @@ Probabilities::initialize_single_probs() else m[pFieldVolatileProb] = 0; - if (CGOptions::consts()) + if (CGOptions::consts() && CGOptions::const_struct_union_fields()) m[pFieldConstProb] = 20; else m[pFieldConstProb] = 0; @@ -873,7 +873,7 @@ Probabilities::check_extra_filter(ProbName pname, int v) { assert(v >= 0); std::map::iterator i = extra_filters_.find(pname); - if (i != extra_filters_.end()) + if (i != extra_filters_.end() && ((*i).second != NULL)) return (*i).second->filter(v); else return false; diff --git a/src/RandomProgramGenerator.cpp b/src/RandomProgramGenerator.cpp index 60db95af3..e643d9b22 100644 --- a/src/RandomProgramGenerator.cpp +++ b/src/RandomProgramGenerator.cpp @@ -260,6 +260,7 @@ static void print_advanced_help() cout << " --arg-unions | --no-arg-unions: enable | disable unions being used as args (enabled by default)." << endl << endl; cout << " --take-union-field-addr | --take-no-union-field-addr: allow | disallow addresses of union fields to be taken (allowed by default)." << endl << endl; cout << " --vol-struct-union-fields | --no-vol-struct-union-fields: enable | disable volatile struct/union fields (enabled by default)" << endl << endl; + cout << " --const-struct-union-fields | --no-const-struct-union-fields: enable | disable const struct/union fields (enabled by default)" << endl << endl; // delta related options cout << " --delta-monitor [simple]: specify the type of delta monitor. Only [simple] type is supported now." << endl << endl; @@ -1361,6 +1362,16 @@ main(int argc, char **argv) continue; } + if (strcmp(argv[i], "--const-struct-union-fields") == 0) { + CGOptions::const_struct_union_fields(true); + continue; + } + + if (strcmp(argv[i], "--no-const-struct-union-fields") == 0) { + CGOptions::const_struct_union_fields(false); + continue; + } + if (strcmp (argv[i], "--no-hash-value-printf") == 0) { CGOptions::hash_value_printf(false); continue; @@ -1415,6 +1426,10 @@ main(int argc, char **argv) exit(-1); } + if (CGOptions::lang_cpp()) { + CGOptions::fix_options_for_cpp(); + } + if (CGOptions::has_conflict()) { cout << "error: options conflict - " << CGOptions::conflict_msg() << std::endl; exit(-1); diff --git a/src/Type.cpp b/src/Type.cpp index 3e9f140e9..f0be6f66e 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -194,7 +194,7 @@ NonVoidNonVolatileTypeFilter::get_type() class ChooseRandomTypeFilter : public Filter { public: - ChooseRandomTypeFilter(bool for_field_var); + ChooseRandomTypeFilter(bool for_field_var = false, bool struct_has_assign_ops = false); virtual ~ChooseRandomTypeFilter(); @@ -203,13 +203,15 @@ class ChooseRandomTypeFilter : public Filter Type *get_type(); bool for_field_var_; - + bool struct_has_assign_ops_; private: mutable Type *typ_; }; -ChooseRandomTypeFilter::ChooseRandomTypeFilter(bool for_field_var) - : for_field_var_(for_field_var) +ChooseRandomTypeFilter::ChooseRandomTypeFilter(bool for_field_var, bool struct_has_assign_ops) + : for_field_var_(for_field_var), + struct_has_assign_ops_(struct_has_assign_ops), + typ_(NULL) { } @@ -232,6 +234,11 @@ ChooseRandomTypeFilter::filter(int v) const return true; } + // Struct without assignment ops can not be made a field of a struct with assign ops + // with current implementation of these ops + if (for_field_var_ && struct_has_assign_ops_ && !typ_->has_assign_ops()) { + return true; + } if (for_field_var_ && typ_->get_struct_depth() >= CGOptions::max_nested_struct_level()) { return true; } @@ -247,6 +254,24 @@ ChooseRandomTypeFilter::get_type() /////////////////////////////////////////////////////////////////////////////// +// Helper functions + +/////////////////////////////////////////////////////////////////////////////// + +static bool checkImplicitNontrivialAssignOps(vector fields) +{ + if (!CGOptions::lang_cpp()) return false; + for (auto& field : fields){ + if (field->has_implicit_nontrivial_assign_ops()){ + assert((field->eType == eStruct) || (field->eType == eUnion)); + return true; + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + // -------------------------------------------------------------- /* constructor for simple types ********************************************************/ @@ -254,42 +279,31 @@ Type::Type(eSimpleType simple_type) : eType(eSimple), ptr_type(0), simple_type(simple_type), + sid(0), // not used for simple types used(false), printed(false), - packed_(false) -{ - // Nothing else to do. -} - -// -------------------------------------------------------------- - /* copy constructor - *******************************************************/ -#if 0 -Type::Type(const Type &t) : - eType(t.eType), - ptr_type(t.ptr_type), - simple_type(t.simple_type), - dimensions(t.dimensions), - fields(t.fields), - used(t.used), - printed(t.printed) + packed_(false), + has_assign_ops_(false), + has_implicit_nontrivial_assign_ops_(false) { // Nothing else to do. } -#endif // -------------------------------------------------------------- /* constructor for struct or union types *******************************************************/ Type::Type(vector& struct_fields, bool isStruct, bool packed, - vector &qfers, vector &fields_length) : + vector &qfers, vector &fields_length, bool hasAssignOps, bool hasImplicitNontrivialAssignOps) : ptr_type(0), fields(struct_fields), used(false), printed(false), packed_(packed), qfers_(qfers), - bitfields_length_(fields_length) + bitfields_length_(fields_length), + simple_type(MAX_SIMPLE_TYPES), // not a valid simple type + has_assign_ops_(hasAssignOps), + has_implicit_nontrivial_assign_ops_(hasImplicitNontrivialAssignOps) { static unsigned int sequence = 0; if (isStruct) @@ -307,7 +321,10 @@ Type::Type(const Type* t) : ptr_type(t), used(false), printed(false), - packed_(false) + packed_(false), + simple_type(MAX_SIMPLE_TYPES), // not a valid simple type + has_assign_ops_(false), + has_implicit_nontrivial_assign_ops_(false) { // Nothing else to do. } @@ -342,6 +359,8 @@ Type::get_simple_type(eSimpleType st) { static bool inited = false; + assert(st != MAX_SIMPLE_TYPES); + if (!inited) { for (int i = 0; i < MAX_SIMPLE_TYPES; ++i) { Type::simple_types[i] = 0; @@ -519,6 +538,30 @@ Type::get_all_ok_struct_union_types(vector &ok_types, bool no_const, boo } } +bool +Type::if_struct_will_have_assign_ops() +{ + bool hasAssignOps = false; + // randomly choose if the struct will have assign operators (for C++): + if (CGOptions::lang_cpp()){ + hasAssignOps = rnd_flipcoin(RegularVolatileProb); + } + return hasAssignOps; +} + +// To have volatile unions in C++. I am not sure if we need those +// (If not, will be enough to return false here) +bool +Type::if_union_will_have_assign_ops() +{ + bool hasAssignOps = false; + // randomly choose if the union will have assign operators (for C++): + if (CGOptions::lang_cpp()){ + hasAssignOps = rnd_flipcoin(RegularVolatileProb); + } + return hasAssignOps; +} + const Type* Type::choose_random_struct_union_type(vector &ok_types) { @@ -652,12 +695,13 @@ Type::make_one_bitfield(vector &random_fields, vector void Type::make_full_bitfields_struct_fields(size_t field_cnt, vector &random_fields, vector &qualifiers, - vector &fields_length) + vector &fields_length, + bool structHasAssignOps) { for (size_t i=0; i &r void Type::make_one_struct_field(vector &random_fields, vector &qualifiers, - vector &fields_length) + vector &fields_length, + bool structHasAssignOps) { - ChooseRandomTypeFilter f(/*for_field_var*/true); + ChooseRandomTypeFilter f(/*for_field_var*/true, structHasAssignOps); unsigned int i = rnd_upto(AllTypes.size(), &f); ERROR_RETURN(); const Type* type = AllTypes[i]; @@ -690,26 +735,34 @@ Type::make_one_union_field(vector &fields, vector &qf } else { size_t i; - vector ok_types; - // filter out struct types containing bit-fields. Their layout is implementation - // defined, we don't want to mess with them in unions for now - for (i=0; ihas_bitfields()) { - ok_types.push_back(AllTypes[i]); - } - } - - // find of struct types - vector struct_types; - for (size_t i=0; ieType == eStruct) { - struct_types.push_back(ok_types[i]); + vector ok_nonstruct_types; + vector struct_types; + // vector union_types; + for (i = 0; i < AllTypes.size(); i++) { + if ((AllTypes[i]->eType == eStruct) || (AllTypes[i]->eType == eUnion)){ + // filter out structs and unions containing bit-fields. Their layout is implementation + // defined, we don't want to mess with them in unions for now + if (!AllTypes[i]->has_bitfields()) { + // filter out structs/unions with assign operators (C++ only) + if (!(AllTypes[i]->has_implicit_nontrivial_assign_ops())) { + if (AllTypes[i]->eType == eStruct){ + struct_types.push_back(AllTypes[i]); + } + else{ // union + // no union in union currently + // union_types.push_back(AllTypes[i]); + } + } + } + } + else{ + ok_nonstruct_types.push_back(AllTypes[i]); + } } - } const Type* type = NULL; do { - // 10% chance to be struct field - if (!struct_types.empty() && pure_rnd_flipcoin(10)) { + // 15% chance to be struct field + if (!struct_types.empty() && pure_rnd_flipcoin(15)) { type = struct_types[pure_rnd_upto(struct_types.size())]; assert(type->eType == eStruct); } @@ -718,11 +771,9 @@ Type::make_one_union_field(vector &fields, vector &qf type = find_pointer_type(&get_simple_type(eChar), true); } else { - unsigned int i = pure_rnd_upto(ok_types.size()); - const Type* t = ok_types[i]; - // no union in union? - if (t->eType == eUnion || - (t->eType == eSimple && SIMPLE_TYPES_PROB_FILTER->filter(t->simple_type))) { + unsigned int i = pure_rnd_upto(ok_nonstruct_types.size()); + const Type* t = ok_nonstruct_types[i]; + if (t->eType == eSimple && SIMPLE_TYPES_PROB_FILTER->filter(t->simple_type)) { continue; } type = t; @@ -740,7 +791,8 @@ Type::make_one_union_field(vector &fields, vector &qf void Type::make_normal_struct_fields(size_t field_cnt, vector &random_fields, vector &qualifiers, - vector &fields_length) + vector &fields_length, + bool structHasAssignOps) { for (size_t i=0; i &random_fi make_one_bitfield(random_fields, qualifiers, fields_length); } else { - make_one_struct_field(random_fields, qualifiers, fields_length); + make_one_struct_field(random_fields, qualifiers, fields_length, structHasAssignOps); } } } @@ -786,7 +838,7 @@ Type::init_fields_enumerator(Enumerator &enumerator, for (int i = 0; i < field_cnt; ++i) { std::ostringstream ss; ss << "bitfield" << i; - bool is_bitfield = bitfield_enumerator.get_elem(ss.str()); + bool is_bitfield = bitfield_enumerator.get_elem(ss.str()) != 0; if (is_bitfield) { std::ostringstream ss1, ss2, ss3; ss1 << "bitfield_sign" << i; @@ -846,7 +898,7 @@ Type::make_one_bitfield_by_enum(Enumerator &enumerator, ss2 << "bitfield_qualifier" << index; ss3 << "bitfield_length" << index; - bool sign = enumerator.get_elem(ss1.str()); + bool sign = enumerator.get_elem(ss1.str()) != 0; // we cannot allow too many structs, // so randomly choose the sign of fields. if (pure_rnd_flipcoin(50)) @@ -931,10 +983,11 @@ Type::make_all_struct_types_with_bitfields(Enumerator &enumerator, int bitfields_cnt = 0; int normal_fields_cnt = 0; + bool hasAssignOps = if_struct_will_have_assign_ops(); for (int i = 0; i < field_cnt; ++i) { std::ostringstream ss; ss << "bitfield" << i; - bool is_bitfield = bitfields_enumerator.get_elem(ss.str()); + bool is_bitfield = bitfields_enumerator.get_elem(ss.str()) != 0; bool rv = false; if (is_bitfield) { rv = make_one_bitfield_by_enum(enumerator, all_bitfield_quals, fields, quals, fields_length, i, last_is_zero); @@ -952,8 +1005,9 @@ Type::make_all_struct_types_with_bitfields(Enumerator &enumerator, ((bitfields_cnt == field_cnt) || (normal_fields_cnt == field_cnt))) return; - bool packed = enumerator.get_elem("packed"); - Type* new_type = new Type(fields, true, packed, quals, fields_length); + bool packed = enumerator.get_elem("packed") != 0; + bool hasImplicitNontrivialAssignOps = hasAssignOps || checkImplicitNontrivialAssignOps(fields); + Type* new_type = new Type(fields, true, packed, quals, fields_length, hasAssignOps, hasImplicitNontrivialAssignOps); new_type->used = true; accum_types.push_back(new_type); } @@ -1070,12 +1124,12 @@ Type::make_random_struct_type(void) vector fields_length; bool is_bitfields = CGOptions::bitfields() && rnd_flipcoin(BitFieldsCreationProb); ERROR_GUARD(NULL); - + bool hasAssignOps = if_struct_will_have_assign_ops(); //if (CGOptions::bitfields()) if (is_bitfields) - make_full_bitfields_struct_fields(field_cnt, random_fields, qualifiers, fields_length); + make_full_bitfields_struct_fields(field_cnt, random_fields, qualifiers, fields_length, hasAssignOps); else - make_normal_struct_fields(field_cnt, random_fields, qualifiers, fields_length); + make_normal_struct_fields(field_cnt, random_fields, qualifiers, fields_length, hasAssignOps); ERROR_GUARD(NULL); @@ -1090,8 +1144,8 @@ Type::make_random_struct_type(void) ERROR_GUARD(NULL); } } - - Type* new_type = new Type(random_fields, true, packed, qualifiers, fields_length); + bool hasImplicitNontrivialAssignOps = hasAssignOps || checkImplicitNontrivialAssignOps(random_fields); + Type* new_type = new Type(random_fields, true, packed, qualifiers, fields_length, hasAssignOps, hasImplicitNontrivialAssignOps); return new_type; } @@ -1101,6 +1155,7 @@ Type::make_random_union_type(void) size_t max_cnt = CGOptions::max_union_fields(); size_t field_cnt = rnd_upto(max_cnt) + 1; ERROR_GUARD(NULL); + bool hasAssignOps = if_union_will_have_assign_ops(); vector fields; vector qfers; @@ -1110,7 +1165,8 @@ Type::make_random_union_type(void) make_one_union_field(fields, qfers, lens); assert(!fields.back()->has_bitfields()); } - Type* new_type = new Type(fields, false, false, qfers, lens); + bool hasImplicitNontrivialAssignOps = hasAssignOps || checkImplicitNontrivialAssignOps(fields); + Type* new_type = new Type(fields, false, false, qfers, lens, hasAssignOps, hasImplicitNontrivialAssignOps); return new_type; } @@ -1430,12 +1486,14 @@ Type::is_convertable(const Type* t) const return true; } if (ptr_type->eType == eSimple && t->ptr_type->eType == eSimple) { - if (ptr_type->simple_type == eFloat && t->ptr_type->simple_type == eFloat) - return true; - else if (CGOptions::strict_float() && - ((ptr_type->simple_type == eFloat && t->ptr_type->simple_type != eFloat) || + if (ptr_type->simple_type == t->ptr_type->simple_type) + return true; + else if (CGOptions::strict_float() && + ((ptr_type->simple_type == eFloat && t->ptr_type->simple_type != eFloat) || (ptr_type->simple_type != eFloat && t->ptr_type->simple_type == eFloat))) return false; + else if (CGOptions::lang_cpp()) + return false; // or we need an explicit cast here else return ptr_type->SizeInBytes() == t->ptr_type->SizeInBytes(); } @@ -1589,10 +1647,10 @@ Type::SelectLType(bool no_volatile, eAssignOps op) ERROR_GUARD(NULL); // choose a struct type as LHS type - if (!type) { + if (!type && (op == eSimpleAssign)) { vector ok_struct_types; get_all_ok_struct_union_types(ok_struct_types, true, no_volatile, false, true); - if ((ok_struct_types.size() > 0) && (op == eSimpleAssign) && rnd_flipcoin(StructAsLTypeProb)) { + if ((ok_struct_types.size() > 0) && rnd_flipcoin(StructAsLTypeProb)) { type = Type::choose_random_struct_union_type(ok_struct_types); } } @@ -1681,6 +1739,107 @@ Type::get_type_sizeof_string(std::string &s) const s = ss.str(); } +// If this is C++, create assign operators for volatile structs: +// Semantically this should work, though for bit fields it's probably not what was intended. +//volatile struct S0& operator=(const volatile struct S0& val) volatile { +// if (this == &val) { +// return *this; +// } +// f0 = val.f0; +// f1 = val.f1; +// return *this; +//} +// As a result of generating this, have to generate 'default' assignment operator as well +void OutputStructAssignOp(Type* type, std::ostream &out, bool vol) +{ + if (CGOptions::lang_cpp()){ + if (type->has_assign_ops() && (type->eType == eTypeDesc::eStruct)){ + out << " "; + if (vol){ + out << "volatile "; + } + type->Output(out); out << "& operator=(const "; + if (vol){ + out << "volatile "; + } + type->Output(out); out << "& val) "; + if (vol){ + out << "volatile "; + } + out << "{"; really_outputln(out); + out << " if (this == &val) {"; really_outputln(out); + out << " return *this;"; really_outputln(out); + out << " }"; really_outputln(out); + // for all fields: + for (size_t i = 0, j = 0; ifields.size(); i++) { + int length = type->bitfields_length_[i]; + if (length != 0){ + out << " "; + out << " f" << j << "= val.f" << j << ";"; + really_outputln(out); + ++j; + } + } + + out << " return *this;"; really_outputln(out); + out << " }"; really_outputln(out); + } + } +} + +// To have volatile unions in C++ they need assignment operators: +//union U1& operator=(const union U1& val){ +// if (this == &val) { +// return *this; +// } +// memcpy(this, &val, sizeof(union U1)); +// return *this; +//} +//volatile union U1& operator=(const volatile union U1& val) volatile { +// if (this == &val) { +// return *this; +// } +// memcpy((union U1*)this, (const union U1*)(&val), sizeof(union U1)); +// return *this; +//} + +void OutputUnionAssignOps(Type* type, std::ostream &out, bool vol) +{ + if (CGOptions::lang_cpp()){ + if (type->has_assign_ops() && (type->eType == eTypeDesc::eUnion)){ + + out << " "; + if (vol){ + out << "volatile "; + } + type->Output(out); out << "& operator=(const "; + if (vol){ + out << "volatile "; + } + type->Output(out); out << "& val) "; + if (vol){ + out << "volatile "; + } + out << "{"; really_outputln(out); + out << " if (this == &val) {"; really_outputln(out); + out << " return *this;"; really_outputln(out); + out << " }"; really_outputln(out); + + + out << " memcpy(("; + type->Output(out); + out << "*)this, (const "; + type->Output(out); + out << "*)(&val), sizeof("; + type->Output(out); + out << ")); "; really_outputln(out); + + out << " return *this;"; really_outputln(out); + out << " }"; really_outputln(out); + } + } +} + // --------------------------------------------------------------------- /* print struct definition (fields etc) *************************************************************/ @@ -1739,6 +1898,16 @@ void OutputStructUnion(Type* type, std::ostream &out) } really_outputln(out); } + + if (type->eType == eStruct){ + OutputStructAssignOp(type, out, false); + OutputStructAssignOp(type, out, true); + } + else{ + OutputUnionAssignOps(type, out, false); + OutputUnionAssignOps(type, out, true); + } + out << "};"; really_outputln(out); if (type->packed_) { @@ -1778,7 +1947,7 @@ OutputStructUnionDeclarations(std::ostream &out) std::string Type::printf_directive(void) const { - string ret; + string ret = ""; size_t i; switch (eType) { case eSimple: diff --git a/src/Type.h b/src/Type.h index a0fbe4ae9..6d4579db3 100644 --- a/src/Type.h +++ b/src/Type.h @@ -117,6 +117,9 @@ class Type static void get_all_ok_struct_union_types(vector &ok_types, bool no_const, bool no_volatile, bool need_int_field, bool bStruct); + static bool if_struct_will_have_assign_ops(); + static bool if_union_will_have_assign_ops(); + bool has_int_field() const; bool signed_overflow_possible() const; @@ -177,17 +180,19 @@ class Type static void make_one_struct_field(vector &random_fields, vector &qualifiers, - vector &fields_length); - + vector &fields_length, + bool structHasAssignOps); static void make_one_union_field(vector &fields, vector &qfers, vector &lens); static void make_full_bitfields_struct_fields(size_t field_cnt, vector &random_fields, vector &qualifiers, - vector &fields_length); + vector &fields_length, + bool structHasAssignOps); static void make_normal_struct_fields(size_t field_cnt, vector &random_fields, vector &qualifiers, - vector &fields_length); + vector &fields_length, + bool structHasAssignOps); // make a random pointer type static Type* make_random_pointer_type(void); @@ -211,7 +216,7 @@ class Type explicit Type(eSimpleType simple_type); Type(vector& fields, bool isStruct, bool packed, - vector &qfers, vector &fields_length); + vector &qfers, vector &fields_length, bool hasAssignOps, bool hasImplicitNontrivialAssignOps); Type(vector& array_dims, eSimpleType st); explicit Type(const Type* t); ~Type(void); @@ -250,6 +255,10 @@ class Type bool contain_pointer_field(void) const; bool is_const_struct_union() const; bool is_volatile_struct_union() const; + bool has_assign_ops() const { return has_assign_ops_; } + bool has_implicit_nontrivial_assign_ops() const { + return has_implicit_nontrivial_assign_ops_; + } bool is_int(void) const { return eType == eSimple && simple_type != eVoid;} bool is_aggregate(void) const { return eType == eStruct || eType == eUnion;} bool match(const Type* t, enum eMatchType mt) const; @@ -270,6 +279,11 @@ class Type bool used; // whether any variable declared with this type bool printed; // whether this struct/union has been printed in the random program const bool packed_; // whether this struct/union should be packed + bool has_assign_ops_; // assign ops are needed if we have: + // struct S0 foo; volatile struct S0 bar; ... foo=bar; + bool has_implicit_nontrivial_assign_ops_; // if a struct has a struct with assign ops as a field, + // than the former struct also has assign ops; + // also true if struct itself has assign ops vector qfers_; // conresponds to each element of fields // It's a tradeoff between the current implementation and the // need of struct's level type qualifiers. @@ -288,6 +302,7 @@ class Type void GenerateAllTypes(void); const Type * get_int_type(void); void OutputStructUnionDeclarations(std::ostream &); +void OutputStructAssignOps(Type* type, std::ostream &out, bool vol); void OutputStructUnion(Type* type, std::ostream &out); ///////////////////////////////////////////////////////////////////////////////