@@ -1076,12 +1076,19 @@ exprt fill_in_array_expr(const array_exprt &expr, std::size_t string_max_length)
1076
1076
// / expression will be: `index==0 ? 24 : index==2 ? 42 : 12`
1077
1077
// / * for an array access `(g1?arr1:arr2)[x]` where `arr1 := {12}` and
1078
1078
// / `arr2 := {34}`, the constructed expression will be: `g1 ? 12 : 34`
1079
+ // / * for an access in an empty array `{ }[x]` returns a fresh symbol, this
1080
+ // / corresponds to a non-deterministic result
1079
1081
// / \param expr: an expression containing array accesses
1082
+ // / \param symbol_generator: function which given a prefix and a type generates
1083
+ // / a fresh symbol of the given type
1080
1084
// / \return an expression containing no array access
1081
- static void substitute_array_access (exprt &expr)
1085
+ static void substitute_array_access (
1086
+ exprt &expr,
1087
+ const std::function<symbol_exprt(const irep_idt &, const typet &)>
1088
+ &symbol_generator)
1082
1089
{
1083
1090
for (auto &op : expr.operands ())
1084
- substitute_array_access (op);
1091
+ substitute_array_access (op, symbol_generator );
1085
1092
1086
1093
if (expr.id ()==ID_index)
1087
1094
{
@@ -1110,9 +1117,9 @@ static void substitute_array_access(exprt &expr)
1110
1117
// Substitute recursively in branches of conditional expressions
1111
1118
if_exprt if_expr=to_if_expr (index_expr.array ());
1112
1119
exprt true_case=index_exprt (if_expr.true_case (), index_expr.index ());
1113
- substitute_array_access (true_case);
1120
+ substitute_array_access (true_case, symbol_generator );
1114
1121
exprt false_case=index_exprt (if_expr.false_case (), index_expr.index ());
1115
- substitute_array_access (false_case);
1122
+ substitute_array_access (false_case, symbol_generator );
1116
1123
expr=if_exprt (if_expr.cond (), true_case, false_case);
1117
1124
return ;
1118
1125
}
@@ -1124,13 +1131,17 @@ static void substitute_array_access(exprt &expr)
1124
1131
" above" ));
1125
1132
array_exprt &array_expr=to_array_expr (index_expr.array ());
1126
1133
1127
- // Empty arrays do not need to be substituted.
1134
+ const typet &char_type = index_expr.array ().type ().subtype ();
1135
+
1136
+ // Access to an empty array is undefined (non deterministic result)
1128
1137
if (array_expr.operands ().empty ())
1138
+ {
1139
+ expr = symbol_generator (" out_of_bound_access" , char_type);
1129
1140
return ;
1141
+ }
1130
1142
1131
1143
size_t last_index=array_expr.operands ().size ()-1 ;
1132
1144
1133
- const typet &char_type=index_expr.array ().type ().subtype ();
1134
1145
exprt ite=array_expr.operands ().back ();
1135
1146
1136
1147
if (ite.type ()!=char_type)
@@ -1342,6 +1353,12 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
1342
1353
const auto eom=messaget::eom;
1343
1354
static const std::string indent = " " ;
1344
1355
static const std::string indent2 = " " ;
1356
+ // clang-format off
1357
+ const auto gen_symbol = [&](const irep_idt &id, const typet &type)
1358
+ {
1359
+ return generator.fresh_symbol (id, type);
1360
+ };
1361
+ // clang-format on
1345
1362
1346
1363
stream << " string_refinementt::check_axioms:" << eom;
1347
1364
@@ -1383,7 +1400,8 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
1383
1400
negaxiom = simplify_expr (negaxiom, ns);
1384
1401
exprt with_concretized_arrays =
1385
1402
concretize_arrays_in_expression (negaxiom, max_string_length, ns);
1386
- substitute_array_access (with_concretized_arrays);
1403
+
1404
+ substitute_array_access (with_concretized_arrays, gen_symbol);
1387
1405
1388
1406
stream << indent << i << " .\n " ;
1389
1407
debug_check_axioms_step (
@@ -1439,7 +1457,7 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
1439
1457
exprt with_concrete_arrays =
1440
1458
concretize_arrays_in_expression (negaxiom, max_string_length, ns);
1441
1459
1442
- substitute_array_access (with_concrete_arrays);
1460
+ substitute_array_access (with_concrete_arrays, gen_symbol );
1443
1461
1444
1462
stream << indent << i << " .\n " ;
1445
1463
debug_check_axioms_step (
0 commit comments