Skip to content

Commit e5a2fb2

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 2e6200a commit e5a2fb2

File tree

5 files changed

+64
-6
lines changed

5 files changed

+64
-6
lines changed

regression/cbmc/extern6/main.c

Lines changed: 12 additions & 0 deletions
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

Lines changed: 9 additions & 0 deletions
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

Lines changed: 33 additions & 0 deletions
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>
@@ -129,6 +132,36 @@ bool ansi_c_languaget::typecheck(
129132
return true;
130133
}
131134

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

src/linking/static_lifetime_init.cpp

Lines changed: 2 additions & 6 deletions
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>
@@ -54,11 +53,8 @@ static std::optional<codet> static_lifetime_init(
5453

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

6460
if(

src/util/lower_byte_operators.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,14 @@ static exprt unpack_array_vector_no_known_bounds(
510510
? to_vector_type(src.type()).size()
511511
: to_array_type(src.type()).size();
512512

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

0 commit comments

Comments
 (0)