Skip to content

Commit 02099c5

Browse files
committed
C front-end: ensure array type updates are consistent
We must not end up in a situation where the symbol's array type is different from the type applied to symbol expressions in code. With the previous approach, support-function generation would alter the type after typechecking of code had already been completed. Instead, do as the C standard says: if the type is incomplete _at the end of a translation unit_, the (implicit) initializer makes it a one-element array. Fixes: #7608
1 parent 1ed7b2f commit 02099c5

File tree

5 files changed

+64
-6
lines changed

5 files changed

+64
-6
lines changed

regression/cbmc/extern6/main.c

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
extern int stuff[];
2+
3+
extern int a[];
4+
int a[] = {1, 2, 3};
5+
6+
int main()
7+
{
8+
unsigned char idx;
9+
long val = *(long *)(stuff + idx);
10+
__CPROVER_assert(val == 13, "compare");
11+
return 0;
12+
}

regression/cbmc/extern6/test.desc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE broken-smt-backend no-new-smt
2+
main.c
3+
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
^warning: ignoring
9+
^Invariant check failed

src/ansi-c/ansi_c_language.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ Author: Daniel Kroening, [email protected]
88

99
#include "ansi_c_language.h"
1010

11+
#include <util/arith_tools.h>
12+
#include <util/c_types.h>
1113
#include <util/config.h>
1214
#include <util/get_base_name.h>
15+
#include <util/replace_symbol.h>
1316
#include <util/symbol_table.h>
1417

1518
#include <linking/linking.h>
@@ -124,6 +127,36 @@ bool ansi_c_languaget::typecheck(
124127
return true;
125128
}
126129

130+
unchecked_replace_symbolt array_type_updates;
131+
for(auto it = new_symbol_table.begin(); it != new_symbol_table.end(); ++it)
132+
{
133+
// C standard 6.9.2, paragraph 5
134+
// adjust the type of an external array without size to an array of size 1
135+
symbolt &symbol = it.get_writeable_symbol();
136+
if(
137+
symbol.is_static_lifetime && !symbol.is_extern && !symbol.is_type &&
138+
!symbol.is_macro && symbol.type.id() == ID_array &&
139+
to_array_type(symbol.type).size().is_nil())
140+
{
141+
symbol_exprt previous_expr = symbol.symbol_expr();
142+
to_array_type(symbol.type).size() = from_integer(1, size_type());
143+
array_type_updates.insert(previous_expr, symbol.symbol_expr());
144+
}
145+
}
146+
if(!array_type_updates.empty())
147+
{
148+
// Apply type updates to initializers
149+
for(auto it = new_symbol_table.begin(); it != new_symbol_table.end(); ++it)
150+
{
151+
if(
152+
!it->second.is_type && !it->second.is_macro &&
153+
it->second.value.is_not_nil())
154+
{
155+
array_type_updates(it.get_writeable_symbol().value);
156+
}
157+
}
158+
}
159+
127160
remove_internal_symbols(
128161
new_symbol_table, message_handler, keep_file_local, keep);
129162

src/linking/static_lifetime_init.cpp

+2-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Author: Daniel Kroening, [email protected]
88

99
#include "static_lifetime_init.h"
1010

11-
#include <util/arith_tools.h>
1211
#include <util/c_types.h>
1312
#include <util/expr_initializer.h>
1413
#include <util/namespace.h>
@@ -53,11 +52,8 @@ static std::optional<codet> static_lifetime_init(
5352

5453
if(symbol.type.id() == ID_array && to_array_type(symbol.type).size().is_nil())
5554
{
56-
// C standard 6.9.2, paragraph 5
57-
// adjust the type to an array of size 1
58-
symbolt &writable_symbol = symbol_table.get_writeable_ref(identifier);
59-
writable_symbol.type = symbol.type;
60-
writable_symbol.type.set(ID_size, from_integer(1, size_type()));
55+
DATA_INVARIANT(symbol.is_extern, "arrays must have a size");
56+
return {};
6157
}
6258

6359
if(

src/util/lower_byte_operators.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,14 @@ static exprt unpack_array_vector_no_known_bounds(
511511
? to_vector_type(src.type()).size()
512512
: to_array_type(src.type()).size();
513513

514+
if(array_vector_size.is_nil())
515+
{
516+
return array_comprehension_exprt{
517+
std::move(array_comprehension_index),
518+
std::move(body),
519+
array_typet{bv_typet{bits_per_byte}, from_integer(0, size_type())}};
520+
}
521+
514522
return array_comprehension_exprt{
515523
std::move(array_comprehension_index),
516524
std::move(body),

0 commit comments

Comments
 (0)