@@ -202,7 +202,18 @@ class goto_checkt
202
202
// / \return true if the given expression is a pointer primitive
203
203
bool is_pointer_primitive (const exprt &expr);
204
204
205
- conditionst address_check (const exprt &address, const exprt &size);
205
+ optionalt<goto_checkt::conditiont>
206
+ get_pointer_is_null_condition (const exprt &address, const exprt &size);
207
+ conditionst get_pointer_points_to_valid_memory_conditions (
208
+ const exprt &address,
209
+ const exprt &size);
210
+ exprt is_in_bounds_of_some_explicit_allocation (
211
+ const exprt &pointer,
212
+ const exprt &size);
213
+
214
+ conditionst get_pointer_dereferenceable_conditions (
215
+ const exprt &address,
216
+ const exprt &size);
206
217
void integer_overflow_check (const exprt &, const guardt &);
207
218
void conversion_check (const exprt &, const guardt &);
208
219
void float_overflow_check (const exprt &, const guardt &);
@@ -1181,7 +1192,7 @@ void goto_checkt::pointer_validity_check(
1181
1192
size = size_of_expr_opt.value ();
1182
1193
}
1183
1194
1184
- auto conditions = address_check (pointer, size);
1195
+ auto conditions = get_pointer_dereferenceable_conditions (pointer, size);
1185
1196
1186
1197
for (const auto &c : conditions)
1187
1198
{
@@ -1225,7 +1236,7 @@ void goto_checkt::pointer_primitive_check(
1225
1236
? from_integer (1 , size_type ())
1226
1237
: size_of_expr_opt.value ();
1227
1238
1228
- const conditionst &conditions = address_check (pointer, size);
1239
+ const conditionst &conditions = get_pointer_dereferenceable_conditions (pointer, size);
1229
1240
1230
1241
exprt::operandst conjuncts;
1231
1242
@@ -1253,123 +1264,17 @@ bool goto_checkt::is_pointer_primitive(const exprt &expr)
1253
1264
expr.id () == ID_w_ok || expr.id () == ID_is_dynamic_object;
1254
1265
}
1255
1266
1256
- goto_checkt::conditionst
1257
- goto_checkt::address_check (const exprt &address, const exprt &size)
1267
+ goto_checkt::conditionst goto_checkt::get_pointer_dereferenceable_conditions (
1268
+ const exprt &address,
1269
+ const exprt &size)
1258
1270
{
1259
- PRECONDITION (local_bitvector_analysis);
1260
- PRECONDITION (address.type ().id () == ID_pointer);
1261
- const auto &pointer_type = to_pointer_type (address.type ());
1262
-
1263
- local_bitvector_analysist::flagst flags =
1264
- local_bitvector_analysis->get (current_target, address);
1265
-
1266
- // For Java, we only need to check for null
1267
- if (mode == ID_java)
1271
+ auto conditions =
1272
+ get_pointer_points_to_valid_memory_conditions (address, size);
1273
+ if (auto maybe_null_condition = get_pointer_is_null_condition (address, size))
1268
1274
{
1269
- if (flags.is_unknown () || flags.is_null ())
1270
- {
1271
- notequal_exprt not_eq_null (address, null_pointer_exprt (pointer_type));
1272
-
1273
- return {conditiont (not_eq_null, " reference is null" )};
1274
- }
1275
- else
1276
- return {};
1277
- }
1278
- else
1279
- {
1280
- conditionst conditions;
1281
- exprt::operandst alloc_disjuncts;
1282
-
1283
- for (const auto &a : allocations)
1284
- {
1285
- typecast_exprt int_ptr (address, a.first .type ());
1286
-
1287
- binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
1288
-
1289
- plus_exprt ub{int_ptr, size};
1290
-
1291
- binary_relation_exprt ub_check (ub, ID_le, plus_exprt (a.first , a.second ));
1292
-
1293
- alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
1294
- }
1295
-
1296
- const exprt in_bounds_of_some_explicit_allocation =
1297
- disjunction (alloc_disjuncts);
1298
-
1299
- const bool unknown = flags.is_unknown () || flags.is_uninitialized ();
1300
-
1301
- if (unknown || flags.is_null ())
1302
- {
1303
- conditions.push_back (conditiont (
1304
- or_exprt (
1305
- in_bounds_of_some_explicit_allocation,
1306
- not_exprt (null_pointer (address))),
1307
- " pointer NULL" ));
1308
- }
1309
-
1310
- if (unknown)
1311
- {
1312
- conditions.push_back (conditiont{
1313
- not_exprt{is_invalid_pointer_exprt{address}}, " pointer invalid" });
1314
- }
1315
-
1316
- if (unknown || flags.is_dynamic_heap ())
1317
- {
1318
- conditions.push_back (conditiont (
1319
- or_exprt (
1320
- in_bounds_of_some_explicit_allocation,
1321
- not_exprt (deallocated (address, ns))),
1322
- " deallocated dynamic object" ));
1323
- }
1324
-
1325
- if (unknown || flags.is_dynamic_local ())
1326
- {
1327
- conditions.push_back (conditiont (
1328
- or_exprt (
1329
- in_bounds_of_some_explicit_allocation,
1330
- not_exprt (dead_object (address, ns))),
1331
- " dead object" ));
1332
- }
1333
-
1334
- if (unknown || flags.is_dynamic_heap ())
1335
- {
1336
- const or_exprt object_bounds_violation (
1337
- object_lower_bound (address, nil_exprt ()),
1338
- object_upper_bound (address, size));
1339
-
1340
- conditions.push_back (conditiont (
1341
- or_exprt (
1342
- in_bounds_of_some_explicit_allocation,
1343
- implies_exprt (
1344
- dynamic_object (address), not_exprt (object_bounds_violation))),
1345
- " pointer outside dynamic object bounds" ));
1346
- }
1347
-
1348
- if (unknown || flags.is_dynamic_local () || flags.is_static_lifetime ())
1349
- {
1350
- const or_exprt object_bounds_violation (
1351
- object_lower_bound (address, nil_exprt ()),
1352
- object_upper_bound (address, size));
1353
-
1354
- conditions.push_back (conditiont (
1355
- or_exprt (
1356
- in_bounds_of_some_explicit_allocation,
1357
- implies_exprt (
1358
- not_exprt (dynamic_object (address)),
1359
- not_exprt (object_bounds_violation))),
1360
- " pointer outside object bounds" ));
1361
- }
1362
-
1363
- if (unknown || flags.is_integer_address ())
1364
- {
1365
- conditions.push_back (conditiont (
1366
- implies_exprt (
1367
- integer_address (address), in_bounds_of_some_explicit_allocation),
1368
- " invalid integer address" ));
1369
- }
1370
-
1371
- return conditions;
1275
+ conditions.push_front (*maybe_null_condition);
1372
1276
}
1277
+ return conditions;
1373
1278
}
1374
1279
1375
1280
std::string goto_checkt::array_name (const exprt &expr)
@@ -1855,8 +1760,8 @@ optionalt<exprt> goto_checkt::rw_ok_check(exprt expr)
1855
1760
DATA_INVARIANT (
1856
1761
expr.operands ().size () == 2 , " r/w_ok must have two operands" );
1857
1762
1858
- const auto conditions =
1859
- address_check ( to_binary_expr (expr).op0 (), to_binary_expr (expr).op1 ());
1763
+ const auto conditions = get_pointer_dereferenceable_conditions (
1764
+ to_binary_expr (expr).op0 (), to_binary_expr (expr).op1 ());
1860
1765
1861
1766
exprt::operandst conjuncts;
1862
1767
@@ -2228,6 +2133,140 @@ void goto_checkt::goto_check(
2228
2133
remove_skip (goto_program);
2229
2134
}
2230
2135
2136
+ goto_checkt::conditionst
2137
+ goto_checkt::get_pointer_points_to_valid_memory_conditions (
2138
+ const exprt &address,
2139
+ const exprt &size)
2140
+ {
2141
+ PRECONDITION (local_bitvector_analysis);
2142
+ PRECONDITION (address.type ().id () == ID_pointer);
2143
+ local_bitvector_analysist::flagst flags =
2144
+ local_bitvector_analysis->get (current_target, address);
2145
+
2146
+ conditionst conditions;
2147
+
2148
+ if (mode == ID_java)
2149
+ {
2150
+ // The following conditions don’t apply to Java
2151
+ return conditions;
2152
+ }
2153
+
2154
+ const exprt in_bounds_of_some_explicit_allocation =
2155
+ is_in_bounds_of_some_explicit_allocation (address, size);
2156
+
2157
+ const bool unknown = flags.is_unknown () || flags.is_uninitialized ();
2158
+
2159
+ if (unknown)
2160
+ {
2161
+ conditions.push_back (conditiont{
2162
+ not_exprt{is_invalid_pointer_exprt{address}}, " pointer invalid" });
2163
+ }
2164
+
2165
+ if (unknown || flags.is_dynamic_heap ())
2166
+ {
2167
+ conditions.push_back (conditiont (
2168
+ or_exprt (
2169
+ in_bounds_of_some_explicit_allocation,
2170
+ not_exprt (deallocated (address, ns))),
2171
+ " deallocated dynamic object" ));
2172
+ }
2173
+
2174
+ if (unknown || flags.is_dynamic_local ())
2175
+ {
2176
+ conditions.push_back (conditiont (
2177
+ or_exprt (
2178
+ in_bounds_of_some_explicit_allocation,
2179
+ not_exprt (dead_object (address, ns))),
2180
+ " dead object" ));
2181
+ }
2182
+
2183
+ if (unknown || flags.is_dynamic_heap ())
2184
+ {
2185
+ const or_exprt object_bounds_violation (
2186
+ object_lower_bound (address, nil_exprt ()),
2187
+ object_upper_bound (address, size));
2188
+
2189
+ conditions.push_back (conditiont (
2190
+ or_exprt (
2191
+ in_bounds_of_some_explicit_allocation,
2192
+ implies_exprt (
2193
+ dynamic_object (address), not_exprt (object_bounds_violation))),
2194
+ " pointer outside dynamic object bounds" ));
2195
+ }
2196
+
2197
+ if (unknown || flags.is_dynamic_local () || flags.is_static_lifetime ())
2198
+ {
2199
+ const or_exprt object_bounds_violation (
2200
+ object_lower_bound (address, nil_exprt ()),
2201
+ object_upper_bound (address, size));
2202
+
2203
+ conditions.push_back (conditiont (
2204
+ or_exprt (
2205
+ in_bounds_of_some_explicit_allocation,
2206
+ implies_exprt (
2207
+ not_exprt (dynamic_object (address)),
2208
+ not_exprt (object_bounds_violation))),
2209
+ " pointer outside object bounds" ));
2210
+ }
2211
+
2212
+ if (unknown || flags.is_integer_address ())
2213
+ {
2214
+ conditions.push_back (conditiont (
2215
+ implies_exprt (
2216
+ integer_address (address), in_bounds_of_some_explicit_allocation),
2217
+ " invalid integer address" ));
2218
+ }
2219
+
2220
+ return conditions;
2221
+ }
2222
+
2223
+ optionalt<goto_checkt::conditiont> goto_checkt::get_pointer_is_null_condition (
2224
+ const exprt &address,
2225
+ const exprt &size)
2226
+ {
2227
+ PRECONDITION (local_bitvector_analysis);
2228
+ PRECONDITION (address.type ().id () == ID_pointer);
2229
+ const auto &pointer_type = to_pointer_type (address.type ());
2230
+ local_bitvector_analysist::flagst flags =
2231
+ local_bitvector_analysis->get (current_target, address);
2232
+ if (mode == ID_java)
2233
+ {
2234
+ if (flags.is_unknown () || flags.is_null ())
2235
+ {
2236
+ notequal_exprt not_eq_null (address, null_pointer_exprt{pointer_type});
2237
+ return {conditiont{not_eq_null, " reference is null" }};
2238
+ }
2239
+ }
2240
+ else if (flags.is_unknown () || flags.is_uninitialized () || flags.is_null ())
2241
+ {
2242
+ return {conditiont{
2243
+ or_exprt{is_in_bounds_of_some_explicit_allocation (address, size),
2244
+ not_exprt (null_pointer (address))},
2245
+ " pointer NULL" }};
2246
+ }
2247
+ return {};
2248
+ }
2249
+
2250
+ exprt goto_checkt::is_in_bounds_of_some_explicit_allocation (
2251
+ const exprt &pointer,
2252
+ const exprt &size)
2253
+ {
2254
+ exprt::operandst alloc_disjuncts;
2255
+ for (const auto &a : allocations)
2256
+ {
2257
+ typecast_exprt int_ptr (pointer, a.first .type ());
2258
+
2259
+ binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
2260
+
2261
+ plus_exprt ub{int_ptr, size};
2262
+
2263
+ binary_relation_exprt ub_check (ub, ID_le, plus_exprt (a.first , a.second ));
2264
+
2265
+ alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
2266
+ }
2267
+ return disjunction (alloc_disjuncts);
2268
+ }
2269
+
2231
2270
void goto_check (
2232
2271
const irep_idt &function_identifier,
2233
2272
goto_functionst::goto_functiont &goto_function,
0 commit comments