-
Notifications
You must be signed in to change notification settings - Fork 273
Support non-heap allocated flexible arrays #6661
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#include <assert.h> | ||
#include <stdio.h> | ||
|
||
typedef int T[]; | ||
|
||
struct f | ||
{ | ||
int w; | ||
T x; | ||
}; | ||
|
||
static struct f before = {0xdeadbeef}; | ||
static struct f f = {4, {0, 1, 2, 3, 4}}; | ||
static struct f after = {0xcafecafe}; | ||
|
||
struct St | ||
{ | ||
char c; | ||
int d[]; | ||
}; | ||
struct St s = {'a', {11, 5}}; | ||
|
||
int main() | ||
{ | ||
int i; | ||
for(i = 0; i < f.w; ++i) | ||
{ | ||
if(f.x[i] != i) | ||
{ | ||
assert(0); | ||
} | ||
} | ||
assert(sizeof(f) == sizeof(struct f)); | ||
assert(before.w == 0xdeadbeef); | ||
assert(after.w == 0xcafecafe); | ||
printf("%llx\n", &before); | ||
printf("%llx\n", &f); | ||
printf("%llx\n", &after); | ||
|
||
unsigned char c; | ||
c = c && 1; | ||
assert(c == 0 || c == 1); | ||
assert(s.d[1] == 5); | ||
s.d[1] += c; | ||
assert(s.d[1] < 8); | ||
assert(s.d[0] == 11); | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CORE | ||
main.c | ||
|
||
^VERIFICATION SUCCESSFUL$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test demonstrates support for flexible array members with non-heap allocated | ||
objects. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,8 +9,6 @@ Author: Daniel Kroening, [email protected] | |
/// \file | ||
/// ANSI-C Conversion / Type Checking | ||
|
||
#include "c_typecheck_base.h" | ||
|
||
#include <util/arith_tools.h> | ||
#include <util/byte_operators.h> | ||
#include <util/c_types.h> | ||
|
@@ -22,6 +20,8 @@ Author: Daniel Kroening, [email protected] | |
#include <util/string_constant.h> | ||
|
||
#include "anonymous_member.h" | ||
#include "c_typecheck_base.h" | ||
#include "type2name.h" | ||
|
||
void c_typecheck_baset::do_initializer( | ||
exprt &initializer, | ||
|
@@ -240,13 +240,12 @@ void c_typecheck_baset::do_initializer(symbolt &symbol) | |
typecheck_expr(symbol.value); | ||
do_initializer(symbol.value, symbol.type, true); | ||
|
||
// need to adjust size? | ||
if( | ||
!symbol.is_macro && symbol.type.id() == ID_array && | ||
to_array_type(symbol.type).size().is_nil()) | ||
{ | ||
// A flexible array may have been initialized, which entails a type change. | ||
// Note that the type equality test is important: we want to preserve | ||
// annotations like typedefs or const-ness when the type is otherwise the | ||
// same. | ||
if(!symbol.is_macro && symbol.type != symbol.value.type()) | ||
symbol.type = symbol.value.type(); | ||
} | ||
} | ||
|
||
if(symbol.is_macro) | ||
|
@@ -428,8 +427,6 @@ exprt::operandst::const_iterator c_typecheck_baset::do_designated_initializer( | |
} | ||
dest->operands().resize( | ||
numeric_cast_v<std::size_t>(index) + 1, *zero); | ||
|
||
// todo: adjust type! | ||
} | ||
else | ||
{ | ||
|
@@ -1007,11 +1004,49 @@ exprt c_typecheck_baset::do_initializer_list( | |
increment_designator(current_designator); | ||
} | ||
|
||
// make sure we didn't mess up index computation | ||
if(full_type.id()==ID_struct) | ||
{ | ||
assert(result.operands().size()== | ||
to_struct_type(full_type).components().size()); | ||
const struct_typet &full_struct_type = to_struct_type(full_type); | ||
const struct_typet::componentst &components = full_struct_type.components(); | ||
// make sure we didn't mess up index computation | ||
CHECK_RETURN(result.operands().size() == components.size()); | ||
|
||
if( | ||
!components.empty() && | ||
components.back().type().get_bool(ID_C_flexible_array_member)) | ||
{ | ||
const auto array_size = numeric_cast<mp_integer>( | ||
to_array_type(components.back().type()).size()); | ||
array_exprt &init_array = to_array_expr(result.operands().back()); | ||
if( | ||
!array_size.has_value() || | ||
(*array_size <= 1 && init_array.operands().size() != *array_size)) | ||
{ | ||
struct_typet actual_struct_type = full_struct_type; | ||
array_typet &actual_array_type = | ||
to_array_type(actual_struct_type.components().back().type()); | ||
actual_array_type.size() = from_integer( | ||
init_array.operands().size(), actual_array_type.index_type()); | ||
actual_array_type.set(ID_C_flexible_array_member, true); | ||
init_array.type() = actual_array_type; | ||
|
||
// mimic bits of typecheck_compound_type to produce a new struct tag | ||
actual_struct_type.remove(ID_tag); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mildly a shame to have to mimic/duplicate bits of code... but maybe lifting out the duplicated parts into utilities is even messier if the mimicking isn't complete duplication. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did wonder, but cutting out just this bit seemed like it would create a utility function that can only be used in very peculiar circumstances. |
||
type_symbolt compound_symbol{actual_struct_type}; | ||
compound_symbol.mode = mode; | ||
compound_symbol.location = value.source_location(); | ||
std::string typestr = type2name(compound_symbol.type, *this); | ||
compound_symbol.base_name = "#anon#" + typestr; | ||
compound_symbol.name = "tag-#anon#" + typestr; | ||
irep_idt tag_identifier = compound_symbol.name; | ||
|
||
// We might already have the same anonymous struct, which is fine as it | ||
// will be exactly the same type. | ||
symbol_table.insert(std::move(compound_symbol)); | ||
|
||
result.type() = struct_tag_typet{tag_identifier}; | ||
} | ||
} | ||
} | ||
|
||
if(full_type.id()==ID_array && | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any point in introducing a
to_C_flexible_array_type
or something to make this a bit more structured? I always get a bit nervous when there's a bunch of setup being done in non-constructor/utility function code :-)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the main reason for this being messy is that it adjusts an existing type. So I'll leave it as is for now.