@@ -86,6 +86,19 @@ class goto_checkt
8686 bool address);
8787 void check (const exprt &expr);
8888
89+ struct conditiont
90+ {
91+ conditiont (const exprt &_assertion, const std::string &_description)
92+ : assertion(_assertion), description(_description)
93+ {
94+ }
95+
96+ exprt assertion;
97+ std::string description;
98+ };
99+
100+ using conditionst = std::list<conditiont>;
101+
89102 void bounds_check (const index_exprt &expr, const guardt &guard);
90103 void div_by_zero_check (const div_exprt &expr, const guardt &guard);
91104 void mod_by_zero_check (const mod_exprt &expr, const guardt &guard);
@@ -97,10 +110,12 @@ class goto_checkt
97110 const guardt &guard,
98111 const exprt &access_lb,
99112 const exprt &access_ub);
113+ conditionst address_check (const exprt &address, const exprt &size);
100114 void integer_overflow_check (const exprt &expr, const guardt &guard);
101115 void conversion_check (const exprt &expr, const guardt &guard);
102116 void float_overflow_check (const exprt &expr, const guardt &guard);
103117 void nan_check (const exprt &expr, const guardt &guard);
118+ void rw_ok_check (exprt &expr);
104119
105120 std::string array_name (const exprt &expr);
106121
@@ -139,6 +154,8 @@ class goto_checkt
139154 typedef optionst::value_listt error_labelst;
140155 error_labelst error_labels;
141156
157+ // the first element of the pair is the base address,
158+ // and the second is the size of the region
142159 typedef std::pair<exprt, exprt> allocationt;
143160 typedef std::list<allocationt> allocationst;
144161 allocationst allocations;
@@ -1092,6 +1109,118 @@ void goto_checkt::pointer_validity_check(
10921109 }
10931110}
10941111
1112+ goto_checkt::conditionst
1113+ goto_checkt::address_check (const exprt &address, const exprt &size)
1114+ {
1115+ if (!enable_pointer_check)
1116+ return {};
1117+
1118+ PRECONDITION (address.type ().id () == ID_pointer);
1119+ const auto &pointer_type = to_pointer_type (address.type ());
1120+
1121+ local_bitvector_analysist::flagst flags =
1122+ local_bitvector_analysis->get (t, address);
1123+
1124+ // For Java, we only need to check for null
1125+ if (mode == ID_java)
1126+ {
1127+ if (flags.is_unknown () || flags.is_null ())
1128+ {
1129+ notequal_exprt not_eq_null (address, null_pointer_exprt (pointer_type));
1130+
1131+ return {conditiont (not_eq_null, " reference is null" )};
1132+ }
1133+ else
1134+ return {};
1135+ }
1136+ else
1137+ {
1138+ conditionst conditions;
1139+ exprt::operandst alloc_disjuncts;
1140+
1141+ for (const auto &a : allocations)
1142+ {
1143+ typecast_exprt int_ptr (address, a.first .type ());
1144+
1145+ binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
1146+
1147+ plus_exprt ub (int_ptr, size, int_ptr.type ());
1148+
1149+ binary_relation_exprt ub_check (ub, ID_le, plus_exprt (a.first , a.second ));
1150+
1151+ alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
1152+ }
1153+
1154+ const exprt allocs = disjunction (alloc_disjuncts);
1155+
1156+ if (flags.is_unknown () || flags.is_null ())
1157+ {
1158+ conditions.push_back (conditiont (
1159+ or_exprt (allocs, not_exprt (null_pointer (address))), " pointer NULL" ));
1160+ }
1161+
1162+ if (flags.is_unknown ())
1163+ {
1164+ conditions.push_back (conditiont (
1165+ not_exprt (invalid_pointer (address)),
1166+ " pointer invalid" ));
1167+ }
1168+
1169+ if (flags.is_uninitialized ())
1170+ {
1171+ conditions.push_back (conditiont (
1172+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1173+ " pointer uninitialized" ));
1174+ }
1175+
1176+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1177+ {
1178+ conditions.push_back (conditiont (
1179+ not_exprt (deallocated (address, ns)),
1180+ " deallocated dynamic object" ));
1181+ }
1182+
1183+ if (flags.is_unknown () || flags.is_dynamic_local ())
1184+ {
1185+ conditions.push_back (conditiont (
1186+ not_exprt (dead_object (address, ns)), " dead object" ));
1187+ }
1188+
1189+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1190+ {
1191+ const or_exprt dynamic_bounds_violation (
1192+ dynamic_object_lower_bound (address, ns, nil_exprt ()),
1193+ dynamic_object_upper_bound (address, ns, size));
1194+
1195+ conditions.push_back (conditiont (
1196+ implies_exprt (malloc_object (address, ns), not_exprt (dynamic_bounds_violation)),
1197+ " pointer outside dynamic object bounds" ));
1198+ }
1199+
1200+ if (
1201+ flags.is_unknown () || flags.is_dynamic_local () ||
1202+ flags.is_static_lifetime ())
1203+ {
1204+ const or_exprt object_bounds_violation (
1205+ object_lower_bound (address, ns, nil_exprt ()),
1206+ object_upper_bound (address, ns, size));
1207+
1208+ conditions.push_back (conditiont (
1209+ implies_exprt (not_exprt (dynamic_object (address)), not_exprt (object_bounds_violation)),
1210+ " dereference failure: pointer outside object bounds" ));
1211+ }
1212+
1213+ if (flags.is_unknown () || flags.is_integer_address ())
1214+ {
1215+ conditions.push_back (conditiont (
1216+ implies_exprt (integer_address (address), allocs),
1217+ " invalid integer address" ));
1218+ }
1219+
1220+ return conditions;
1221+ }
1222+ }
1223+
10951224std::string goto_checkt::array_name (const exprt &expr)
10961225{
10971226 return ::array_name (ns, expr);
@@ -1510,6 +1639,27 @@ void goto_checkt::check(const exprt &expr)
15101639 check_rec (expr, guard, false );
15111640}
15121641
1642+ // / expand the r_ok and w_ok predicates
1643+ void goto_checkt::rw_ok_check (exprt &expr)
1644+ {
1645+ for (auto &op : expr.operands ())
1646+ rw_ok_check (op);
1647+
1648+ if (expr.id () == ID_r_ok || expr.id () == ID_w_ok)
1649+ {
1650+ // these get an address as first argument and a size as second
1651+ DATA_INVARIANT (
1652+ expr.operands ().size () == 2 , " r/w_ok must have two operands" );
1653+
1654+ const auto conditions = address_check (expr.op0 (), expr.op1 ());
1655+ exprt::operandst conjuncts;
1656+ for (const auto &c : conditions)
1657+ conjuncts.push_back (c.assertion );
1658+
1659+ expr = conjunction (conjuncts);
1660+ }
1661+ }
1662+
15131663void goto_checkt::goto_check (
15141664 goto_functiont &goto_function,
15151665 const irep_idt &_mode)
@@ -1659,6 +1809,9 @@ void goto_checkt::goto_check(
16591809 else if (i.is_assert ())
16601810 {
16611811 bool is_user_provided=i.source_location .get_bool (" user-provided" );
1812+
1813+ rw_ok_check (i.guard );
1814+
16621815 if ((is_user_provided && !enable_assertions &&
16631816 i.source_location .get_property_class ()!=" error label" ) ||
16641817 (!is_user_provided && !enable_built_in_assertions))
0 commit comments