From 22faee4ce7fc1ccb7b34283e39ceec123f0e79fd Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 3 Nov 2022 10:14:20 +0000 Subject: [PATCH] disallow flexible array members in unions This change yields an error if a flexible array member is used in a union. C11 allows them in structs, but not unions. --- .../union/union_flexible_array_member.c | 7 ++++ .../union/union_flexible_array_member.desc | 7 ++++ src/ansi-c/c_typecheck_type.cpp | 41 ++++++++++++++----- 3 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 regression/ansi-c/union/union_flexible_array_member.c create mode 100644 regression/ansi-c/union/union_flexible_array_member.desc diff --git a/regression/ansi-c/union/union_flexible_array_member.c b/regression/ansi-c/union/union_flexible_array_member.c new file mode 100644 index 00000000000..5533dbb562e --- /dev/null +++ b/regression/ansi-c/union/union_flexible_array_member.c @@ -0,0 +1,7 @@ +// C11 6.7.2.1 §18 allows flexible array members in structures, +// but not unions. + +union +{ + char flexible_array_member[]; +}; diff --git a/regression/ansi-c/union/union_flexible_array_member.desc b/regression/ansi-c/union/union_flexible_array_member.desc new file mode 100644 index 00000000000..a5090a1dbd9 --- /dev/null +++ b/regression/ansi-c/union/union_flexible_array_member.desc @@ -0,0 +1,7 @@ +CORE gcc-only +union_flexible_array_member.c + +^EXIT=1$ +^SIGNAL=0$ +^CONVERSION ERROR$ +-- diff --git a/src/ansi-c/c_typecheck_type.cpp b/src/ansi-c/c_typecheck_type.cpp index bde69b633b7..a36fe78f5e9 100644 --- a/src/ansi-c/c_typecheck_type.cpp +++ b/src/ansi-c/c_typecheck_type.cpp @@ -1007,24 +1007,24 @@ void c_typecheck_baset::typecheck_compound_body( } } - // We allow an incomplete (C99) array as _last_ member! - // Zero-length is allowed everywhere. - - if(type.id()==ID_struct || - type.id()==ID_union) + // We allow an incomplete array as _last_ member of a struct, + // C11 6.7.2.1 §18. These are called "flexible array members". + // Zero-length (a gcc extension) is allowed everywhere. + if(type.id() == ID_struct) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { - typet &c_type=it->type(); + typet &component_type = it->type(); - if(c_type.id()==ID_array && - to_array_type(c_type).is_incomplete()) + if( + component_type.id() == ID_array && + to_array_type(component_type).is_incomplete()) { // needs to be last member - if(type.id()==ID_struct && it!=--components.end()) + if(it != --components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; @@ -1032,8 +1032,27 @@ void c_typecheck_baset::typecheck_compound_body( } // make it zero-length - to_array_type(c_type).size() = from_integer(0, c_index_type()); - c_type.set(ID_C_flexible_array_member, true); + to_array_type(component_type).size() = from_integer(0, c_index_type()); + component_type.set(ID_C_flexible_array_member, true); + } + } + } + + // Flexible array members are not allowed in unions in ISO C. + // We allow this as an extension on Windows. + if(type.id() == ID_union && config.ansi_c.os != configt::ansi_ct::ost::OS_WIN) + { + for(const auto &component : components) + { + auto &component_type = component.type(); + + if( + component_type.id() == ID_array && + to_array_type(component_type).is_incomplete()) + { + throw invalid_source_file_exceptiont( + "flexible array members are not allowed in a union", + component.source_location()); } } }