@@ -202,7 +202,18 @@ class goto_checkt
202202 // / \return true if the given expression is a pointer primitive
203203 bool is_pointer_primitive (const exprt &expr);
204204
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);
206217 void integer_overflow_check (const exprt &, const guardt &);
207218 void conversion_check (const exprt &, const guardt &);
208219 void float_overflow_check (const exprt &, const guardt &);
@@ -1181,7 +1192,7 @@ void goto_checkt::pointer_validity_check(
11811192 size = size_of_expr_opt.value ();
11821193 }
11831194
1184- auto conditions = address_check (pointer, size);
1195+ auto conditions = get_pointer_dereferenceable_conditions (pointer, size);
11851196
11861197 for (const auto &c : conditions)
11871198 {
@@ -1225,7 +1236,7 @@ void goto_checkt::pointer_primitive_check(
12251236 ? from_integer (1 , size_type ())
12261237 : size_of_expr_opt.value ();
12271238
1228- const conditionst &conditions = address_check (pointer, size);
1239+ const conditionst &conditions = get_pointer_dereferenceable_conditions (pointer, size);
12291240
12301241 exprt::operandst conjuncts;
12311242
@@ -1253,123 +1264,17 @@ bool goto_checkt::is_pointer_primitive(const exprt &expr)
12531264 expr.id () == ID_w_ok || expr.id () == ID_is_dynamic_object;
12541265}
12551266
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)
12581270{
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))
12681274 {
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);
13721276 }
1277+ return conditions;
13731278}
13741279
13751280std::string goto_checkt::array_name (const exprt &expr)
@@ -1855,8 +1760,8 @@ optionalt<exprt> goto_checkt::rw_ok_check(exprt expr)
18551760 DATA_INVARIANT (
18561761 expr.operands ().size () == 2 , " r/w_ok must have two operands" );
18571762
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 ());
18601765
18611766 exprt::operandst conjuncts;
18621767
@@ -2228,6 +2133,140 @@ void goto_checkt::goto_check(
22282133 remove_skip (goto_program);
22292134}
22302135
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+
22312270void goto_check (
22322271 const irep_idt &function_identifier,
22332272 goto_functionst::goto_functiont &goto_function,
0 commit comments