Skip to content

Commit e92c0cc

Browse files
authored
Merge pull request #6788 from tautschnig/bugfixes/6787-flexible-array
Flexible array members: make type checking aware and fix bounds checking
2 parents 2a64c19 + 22bd66f commit e92c0cc

File tree

4 files changed

+71
-4
lines changed

4 files changed

+71
-4
lines changed

regression/cbmc/struct17/main.c

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include <assert.h>
2+
3+
struct famt
4+
{
5+
char x;
6+
char vl[];
7+
};
8+
9+
extern struct famt vls;
10+
struct famt vls = {'a', {1, 2, 3, 4}};
11+
12+
int main()
13+
{
14+
assert(vls.vl[3] == 4);
15+
return 0;
16+
}

regression/cbmc/struct17/test.desc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
^CONVERSION ERROR$

src/ansi-c/c_typecheck_base.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,41 @@ void c_typecheck_baset::typecheck_redefinition_type(
262262
}
263263
}
264264

265+
static bool is_instantiation_of_flexible_array(
266+
const struct_typet &old_type,
267+
const struct_typet &new_type)
268+
{
269+
const struct_typet::componentst &old_components = old_type.components();
270+
const struct_typet::componentst &new_components = new_type.components();
271+
272+
if(old_components.size() != new_components.size())
273+
return false;
274+
275+
if(old_components.empty())
276+
return false;
277+
278+
for(std::size_t i = 0; i < old_components.size() - 1; ++i)
279+
{
280+
if(old_components[i].type() != new_components[i].type())
281+
return false;
282+
}
283+
284+
if(
285+
old_components.back().type().id() != ID_array ||
286+
new_components.back().type().id() != ID_array)
287+
{
288+
return false;
289+
}
290+
291+
const auto &old_array_type = to_array_type(old_components.back().type());
292+
const auto &new_array_type = to_array_type(new_components.back().type());
293+
294+
return old_array_type.element_type() == new_array_type.element_type() &&
295+
old_array_type.get_bool(ID_C_flexible_array_member) &&
296+
new_array_type.get_bool(ID_C_flexible_array_member) &&
297+
(old_array_type.size().is_nil() || old_array_type.size().is_zero());
298+
}
299+
265300
void c_typecheck_baset::typecheck_redefinition_non_type(
266301
symbolt &old_symbol,
267302
symbolt &new_symbol)
@@ -446,6 +481,13 @@ void c_typecheck_baset::typecheck_redefinition_non_type(
446481
// int (*f) (int)=0;
447482
// int (*f) ();
448483
}
484+
else if(
485+
final_old.id() == ID_struct && final_new.id() == ID_struct &&
486+
is_instantiation_of_flexible_array(
487+
to_struct_type(final_old), to_struct_type(final_new)))
488+
{
489+
old_symbol.type = new_symbol.type;
490+
}
449491
else
450492
{
451493
error().source_location=new_symbol.location;

src/ansi-c/goto_check_c.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -1649,14 +1649,14 @@ void goto_check_ct::bounds_check_index(
16491649
// that member, it behaves as if that member were replaced with the longest
16501650
// array (with the same element type) that would not make the structure
16511651
// larger than the object being accessed; [...]
1652-
const auto type_size_opt = size_of_expr(ode.root_object().type(), ns);
1652+
const auto type_size_opt =
1653+
pointer_offset_size(ode.root_object().type(), ns);
16531654
CHECK_RETURN(type_size_opt.has_value());
16541655

16551656
binary_relation_exprt inequality(
1656-
typecast_exprt::conditional_cast(
1657-
ode.offset(), type_size_opt.value().type()),
1657+
ode.offset(),
16581658
ID_lt,
1659-
type_size_opt.value());
1659+
from_integer(type_size_opt.value(), ode.offset().type()));
16601660

16611661
add_guarded_property(
16621662
inequality,

0 commit comments

Comments
 (0)