@@ -1160,6 +1160,179 @@ void bv_pointerst::do_postponed(
1160
1160
UNREACHABLE;
1161
1161
}
1162
1162
1163
+ void bv_pointerst::encode_object_bounds (bounds_mapt &dest)
1164
+ {
1165
+ const auto &objects = pointer_logic.objects ;
1166
+ std::size_t number = 0 ;
1167
+
1168
+ const bvt null_pointer = pointer_bits.at (pointer_logic.get_null_object ());
1169
+ const bvt &invalid_object =
1170
+ pointer_bits.at (pointer_logic.get_invalid_object ());
1171
+
1172
+ bvt conj;
1173
+ conj.reserve (objects.size ());
1174
+
1175
+ for (const exprt &expr : objects)
1176
+ {
1177
+ const auto size_expr = size_of_expr (expr.type (), ns);
1178
+
1179
+ if (!size_expr.has_value ())
1180
+ {
1181
+ ++number;
1182
+ continue ;
1183
+ }
1184
+
1185
+ bvt size_bv = convert_bv (*size_expr);
1186
+
1187
+ // NULL, INVALID have no size
1188
+ DATA_INVARIANT (
1189
+ number != pointer_logic.get_null_object (),
1190
+ " NULL object cannot have a size" );
1191
+ DATA_INVARIANT (
1192
+ number != pointer_logic.get_invalid_object (),
1193
+ " INVALID object cannot have a size" );
1194
+
1195
+ bvt object_bv;
1196
+ encode (number, object_bv);
1197
+
1198
+ // prepare comparison over integers
1199
+ bvt bv = object_bv;
1200
+ address_bv (bv, pointer_type (expr.type ()));
1201
+ DATA_INVARIANT (
1202
+ bv.size () == null_pointer.size (),
1203
+ " NULL pointer encoding does not have matching width" );
1204
+ DATA_INVARIANT (
1205
+ bv.size () == invalid_object.size (),
1206
+ " INVALID pointer encoding does not have matching width" );
1207
+ DATA_INVARIANT (
1208
+ size_bv.size () == bv.size (),
1209
+ " pointer encoding does not have matching width" );
1210
+
1211
+ // NULL, INVALID must not be within object bounds
1212
+ literalt null_lower_bound = bv_utils.rel (
1213
+ null_pointer, ID_lt, bv, bv_utilst::representationt::UNSIGNED);
1214
+
1215
+ literalt inv_obj_lower_bound = bv_utils.rel (
1216
+ invalid_object, ID_lt, bv, bv_utilst::representationt::UNSIGNED);
1217
+
1218
+ // compute the upper bound with the side effect of enforcing the
1219
+ // object addresses not to wrap around/overflow
1220
+ bvt obj_upper_bound = bv_utils.add_sub_no_overflow (
1221
+ bv, size_bv, false , bv_utilst::representationt::UNSIGNED);
1222
+
1223
+ literalt null_upper_bound = bv_utils.rel (
1224
+ null_pointer,
1225
+ ID_ge,
1226
+ obj_upper_bound,
1227
+ bv_utilst::representationt::UNSIGNED);
1228
+
1229
+ literalt inv_obj_upper_bound = bv_utils.rel (
1230
+ invalid_object,
1231
+ ID_ge,
1232
+ obj_upper_bound,
1233
+ bv_utilst::representationt::UNSIGNED);
1234
+
1235
+ // store bounds for re-use
1236
+ dest.insert ({number, {bv, obj_upper_bound}});
1237
+
1238
+ conj.push_back (prop.lor (null_lower_bound, null_upper_bound));
1239
+ conj.push_back (prop.lor (inv_obj_lower_bound, inv_obj_upper_bound));
1240
+
1241
+ ++number;
1242
+ }
1243
+
1244
+ if (!conj.empty ())
1245
+ prop.l_set_to_true (prop.land (conj));
1246
+ }
1247
+
1248
+ void bv_pointerst::do_postponed_typecast (
1249
+ const postponedt &postponed,
1250
+ const bounds_mapt &bounds)
1251
+ {
1252
+ if (postponed.expr .id () != ID_typecast)
1253
+ return ;
1254
+
1255
+ const pointer_typet &type = to_pointer_type (postponed.expr .type ());
1256
+ const std::size_t bits = boolbv_width.get_offset_width (type) +
1257
+ boolbv_width.get_object_width (type) +
1258
+ boolbv_width.get_address_width (type);
1259
+
1260
+ // given an integer (possibly representing an address) postponed.op,
1261
+ // compute the object and offset that it may refer to
1262
+ bvt saved_bv = postponed.op ;
1263
+
1264
+ bvt conj, oob_conj;
1265
+ conj.reserve (bounds.size () + 3 );
1266
+ oob_conj.reserve (bounds.size ());
1267
+
1268
+ for (const auto &bounds_entry : bounds)
1269
+ {
1270
+ std::size_t number = bounds_entry.first ;
1271
+
1272
+ // pointer must be within object bounds
1273
+ const bvt &lb = bounds_entry.second .first ;
1274
+ const bvt &ub = bounds_entry.second .second ;
1275
+
1276
+ literalt lower_bound =
1277
+ bv_utils.rel (saved_bv, ID_ge, lb, bv_utilst::representationt::UNSIGNED);
1278
+
1279
+ literalt upper_bound =
1280
+ bv_utils.rel (saved_bv, ID_lt, ub, bv_utilst::representationt::UNSIGNED);
1281
+
1282
+ // compute the offset within the object, and the corresponding
1283
+ // pointer bv
1284
+ bvt offset = bv_utils.sub (saved_bv, lb);
1285
+
1286
+ bvt bv;
1287
+ encode (number, bv);
1288
+ object_bv (bv, type);
1289
+ DATA_INVARIANT (
1290
+ offset.size () == boolbv_width.get_offset_width (type),
1291
+ " pointer encoding does not have matching width" );
1292
+ bv.insert (bv.end (), offset.begin (), offset.end ());
1293
+ bv.insert (bv.end (), saved_bv.begin (), saved_bv.end ());
1294
+ DATA_INVARIANT (
1295
+ bv.size () == bits, " pointer encoding does not have matching width" );
1296
+
1297
+ // if the integer address is within the object bounds, return an
1298
+ // adjusted offset
1299
+ literalt in_bounds = prop.land (lower_bound, upper_bound);
1300
+ conj.push_back (prop.limplies (in_bounds, bv_utils.equal (bv, postponed.bv )));
1301
+ oob_conj.push_back (!in_bounds);
1302
+ }
1303
+
1304
+ // append integer address as both offset and address
1305
+ bvt invalid_bv, null_bv;
1306
+ encode (pointer_logic.get_invalid_object (), invalid_bv);
1307
+ object_bv (invalid_bv, type);
1308
+ invalid_bv.insert (invalid_bv.end (), saved_bv.begin (), saved_bv.end ());
1309
+ invalid_bv.insert (invalid_bv.end (), saved_bv.begin (), saved_bv.end ());
1310
+ encode (pointer_logic.get_null_object (), null_bv);
1311
+ object_bv (null_bv, type);
1312
+ null_bv.insert (null_bv.end (), saved_bv.begin (), saved_bv.end ());
1313
+ null_bv.insert (null_bv.end (), saved_bv.begin (), saved_bv.end ());
1314
+
1315
+ // NULL is always NULL
1316
+ conj.push_back (prop.limplies (
1317
+ bv_utils.equal (saved_bv, pointer_bits.at (pointer_logic.get_null_object ())),
1318
+ bv_utils.equal (null_bv, postponed.bv )));
1319
+
1320
+ // INVALID is always INVALID
1321
+ conj.push_back (prop.limplies (
1322
+ bv_utils.equal (
1323
+ saved_bv, pointer_bits.at (pointer_logic.get_invalid_object ())),
1324
+ bv_utils.equal (invalid_bv, postponed.bv )));
1325
+
1326
+ // one of the objects or NULL or INVALID with an offset
1327
+ conj.push_back (prop.limplies (
1328
+ prop.land (oob_conj),
1329
+ prop.lor (
1330
+ bv_utils.equal (null_bv, postponed.bv ),
1331
+ bv_utils.equal (invalid_bv, postponed.bv ))));
1332
+
1333
+ prop.l_set_to_true (prop.land (conj));
1334
+ }
1335
+
1163
1336
void bv_pointerst::post_process ()
1164
1337
{
1165
1338
// post-processing arrays may yield further objects, do this first
@@ -1169,7 +1342,19 @@ void bv_pointerst::post_process()
1169
1342
it=postponed_list.begin ();
1170
1343
it!=postponed_list.end ();
1171
1344
it++)
1172
- do_postponed (*it);
1345
+ do_postponed_non_typecast (*it);
1346
+
1347
+ if (need_address_bounds)
1348
+ {
1349
+ // make sure NULL and INVALID are unique addresses
1350
+ bounds_mapt bounds;
1351
+ encode_object_bounds (bounds);
1352
+
1353
+ for (postponed_listt::const_iterator it = postponed_list.begin ();
1354
+ it != postponed_list.end ();
1355
+ it++)
1356
+ do_postponed_typecast (*it, bounds);
1357
+ }
1173
1358
1174
1359
// Clear the list to avoid re-doing in case of incremental usage.
1175
1360
postponed_list.clear ();
0 commit comments