@@ -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;
@@ -1076,6 +1093,113 @@ void goto_checkt::pointer_validity_check(
10761093 }
10771094}
10781095
1096+ goto_checkt::conditionst
1097+ goto_checkt::address_check (const exprt &address, const exprt &size)
1098+ {
1099+ if (!enable_pointer_check)
1100+ return {};
1101+
1102+ PRECONDITION (address.type ().id () == ID_pointer);
1103+ const auto &pointer_type = to_pointer_type (address.type ());
1104+
1105+ local_bitvector_analysist::flagst flags =
1106+ local_bitvector_analysis->get (t, address);
1107+
1108+ // For Java, we only need to check for null
1109+ if (mode == ID_java)
1110+ {
1111+ if (flags.is_unknown () || flags.is_null ())
1112+ {
1113+ notequal_exprt not_eq_null (address, null_pointer_exprt (pointer_type));
1114+
1115+ return {conditiont (not_eq_null, " reference is null" )};
1116+ }
1117+ else
1118+ return {};
1119+ }
1120+ else
1121+ {
1122+ conditionst conditions;
1123+ exprt::operandst alloc_disjuncts;
1124+
1125+ for (const auto &a : allocations)
1126+ {
1127+ typecast_exprt int_ptr (address, a.first .type ());
1128+
1129+ binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
1130+
1131+ plus_exprt ub (int_ptr, size, int_ptr.type ());
1132+
1133+ binary_relation_exprt ub_check (ub, ID_le, plus_exprt (a.first , a.second ));
1134+
1135+ alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
1136+ }
1137+
1138+ const exprt allocs = disjunction (alloc_disjuncts);
1139+
1140+ if (flags.is_unknown () || flags.is_null ())
1141+ {
1142+ conditions.push_back (conditiont (
1143+ or_exprt (allocs, not_exprt (null_pointer (address))), " pointer NULL" ));
1144+ }
1145+
1146+ if (flags.is_unknown ())
1147+ {
1148+ conditions.push_back (conditiont (
1149+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1150+ " pointer invalid" ));
1151+ }
1152+
1153+ if (flags.is_uninitialized ())
1154+ {
1155+ conditions.push_back (conditiont (
1156+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1157+ " pointer uninitialized" ));
1158+ }
1159+
1160+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1161+ {
1162+ conditions.push_back (conditiont (
1163+ or_exprt (allocs, not_exprt (deallocated (address, ns))),
1164+ " deallocated dynamic object" ));
1165+ }
1166+
1167+ if (flags.is_unknown () || flags.is_dynamic_local ())
1168+ {
1169+ conditions.push_back (conditiont (
1170+ or_exprt (allocs, not_exprt (dead_object (address, ns))), " dead object" ));
1171+ }
1172+
1173+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1174+ {
1175+ const or_exprt dynamic_bounds (
1176+ dynamic_object_lower_bound (address, ns, nil_exprt ()),
1177+ dynamic_object_upper_bound (address, ns, size));
1178+
1179+ conditions.push_back (conditiont (
1180+ or_exprt (
1181+ allocs,
1182+ implies_exprt (malloc_object (address, ns), not_exprt (dynamic_bounds))),
1183+ " pointer outside dynamic object bounds" ));
1184+ }
1185+
1186+ if (
1187+ flags.is_unknown () || flags.is_dynamic_local () ||
1188+ flags.is_static_lifetime ())
1189+ {
1190+ const or_exprt object_bounds (
1191+ object_lower_bound (address, ns, nil_exprt ()),
1192+ object_upper_bound (address, ns, size));
1193+
1194+ conditions.push_back (conditiont (
1195+ or_exprt (allocs, dynamic_object (address), not_exprt (object_bounds)),
1196+ " dereference failure: pointer outside object bounds" ));
1197+ }
1198+
1199+ return conditions;
1200+ }
1201+ }
1202+
10791203std::string goto_checkt::array_name (const exprt &expr)
10801204{
10811205 return ::array_name (ns, expr);
@@ -1494,6 +1618,27 @@ void goto_checkt::check(const exprt &expr)
14941618 check_rec (expr, guard, false );
14951619}
14961620
1621+ // / expand the r_ok and w_ok predicates
1622+ void goto_checkt::rw_ok_check (exprt &expr)
1623+ {
1624+ for (auto &op : expr.operands ())
1625+ rw_ok_check (op);
1626+
1627+ if (expr.id () == ID_r_ok || expr.id () == ID_w_ok)
1628+ {
1629+ // these get an address as first argument and a size as second
1630+ DATA_INVARIANT (
1631+ expr.operands ().size () == 2 , " r/w_ok must have two operands" );
1632+
1633+ const auto conditions = address_check (expr.op0 (), expr.op1 ());
1634+ exprt::operandst conjuncts;
1635+ for (const auto &c : conditions)
1636+ conjuncts.push_back (c.assertion );
1637+
1638+ expr = conjunction (conjuncts);
1639+ }
1640+ }
1641+
14971642void goto_checkt::goto_check (
14981643 goto_functiont &goto_function,
14991644 const irep_idt &_mode)
@@ -1643,6 +1788,9 @@ void goto_checkt::goto_check(
16431788 else if (i.is_assert ())
16441789 {
16451790 bool is_user_provided=i.source_location .get_bool (" user-provided" );
1791+
1792+ rw_ok_check (i.guard );
1793+
16461794 if ((is_user_provided && !enable_assertions &&
16471795 i.source_location .get_property_class ()!=" error label" ) ||
16481796 (!is_user_provided && !enable_built_in_assertions))
0 commit comments