diff --git a/regression/cbmc/extern6/main.c b/regression/cbmc/extern6/main.c new file mode 100644 index 000000000000..074bdc22d47e --- /dev/null +++ b/regression/cbmc/extern6/main.c @@ -0,0 +1,12 @@ +extern int stuff[]; + +extern int a[]; +int a[] = {1, 2, 3}; + +int main() +{ + unsigned char idx; + long val = *(long *)(stuff + idx); + __CPROVER_assert(val == 13, "compare"); + return 0; +} diff --git a/regression/cbmc/extern6/test.desc b/regression/cbmc/extern6/test.desc new file mode 100644 index 000000000000..33728f2646dc --- /dev/null +++ b/regression/cbmc/extern6/test.desc @@ -0,0 +1,9 @@ +CORE broken-smt-backend +main.c + +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ +-- +^warning: ignoring +^Invariant check failed diff --git a/src/ansi-c/ansi_c_language.cpp b/src/ansi-c/ansi_c_language.cpp index 5c58cf621a72..1cbf0d61b060 100644 --- a/src/ansi-c/ansi_c_language.cpp +++ b/src/ansi-c/ansi_c_language.cpp @@ -8,8 +8,11 @@ Author: Daniel Kroening, kroening@kroening.com #include "ansi_c_language.h" +#include +#include #include #include +#include #include #include @@ -124,6 +127,36 @@ bool ansi_c_languaget::typecheck( return true; } + unchecked_replace_symbolt array_type_updates; + for(auto it = new_symbol_table.begin(); it != new_symbol_table.end(); ++it) + { + // C standard 6.9.2, paragraph 5 + // adjust the type of an external array without size to an array of size 1 + symbolt &symbol = it.get_writeable_symbol(); + if( + symbol.is_static_lifetime && !symbol.is_extern && !symbol.is_type && + !symbol.is_macro && symbol.type.id() == ID_array && + to_array_type(symbol.type).size().is_nil()) + { + symbol_exprt previous_expr = symbol.symbol_expr(); + to_array_type(symbol.type).size() = from_integer(1, size_type()); + array_type_updates.insert(previous_expr, symbol.symbol_expr()); + } + } + if(!array_type_updates.empty()) + { + // Apply type updates to initializers + for(auto it = new_symbol_table.begin(); it != new_symbol_table.end(); ++it) + { + if( + !it->second.is_type && !it->second.is_macro && + it->second.value.is_not_nil()) + { + array_type_updates(it.get_writeable_symbol().value); + } + } + } + remove_internal_symbols( new_symbol_table, message_handler, keep_file_local, keep); diff --git a/src/linking/static_lifetime_init.cpp b/src/linking/static_lifetime_init.cpp index c7a44367f2a0..f43fe8b7670f 100644 --- a/src/linking/static_lifetime_init.cpp +++ b/src/linking/static_lifetime_init.cpp @@ -8,7 +8,6 @@ Author: Daniel Kroening, kroening@kroening.com #include "static_lifetime_init.h" -#include #include #include #include @@ -53,11 +52,8 @@ static std::optional static_lifetime_init( if(symbol.type.id() == ID_array && to_array_type(symbol.type).size().is_nil()) { - // C standard 6.9.2, paragraph 5 - // adjust the type to an array of size 1 - symbolt &writable_symbol = symbol_table.get_writeable_ref(identifier); - writable_symbol.type = symbol.type; - writable_symbol.type.set(ID_size, from_integer(1, size_type())); + DATA_INVARIANT(symbol.is_extern, "arrays must have a size"); + return {}; } if( diff --git a/src/util/lower_byte_operators.cpp b/src/util/lower_byte_operators.cpp index 047814dc80c9..310fec1a3727 100644 --- a/src/util/lower_byte_operators.cpp +++ b/src/util/lower_byte_operators.cpp @@ -511,6 +511,14 @@ static exprt unpack_array_vector_no_known_bounds( ? to_vector_type(src.type()).size() : to_array_type(src.type()).size(); + if(array_vector_size.is_nil()) + { + return array_comprehension_exprt{ + std::move(array_comprehension_index), + std::move(body), + array_typet{bv_typet{bits_per_byte}, from_integer(0, size_type())}}; + } + return array_comprehension_exprt{ std::move(array_comprehension_index), std::move(body),