@@ -86,6 +86,19 @@ class goto_checkt
86
86
bool address);
87
87
void check (const exprt &expr);
88
88
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
+
89
102
void bounds_check (const index_exprt &expr, const guardt &guard);
90
103
void div_by_zero_check (const div_exprt &expr, const guardt &guard);
91
104
void mod_by_zero_check (const mod_exprt &expr, const guardt &guard);
@@ -97,10 +110,12 @@ class goto_checkt
97
110
const guardt &guard,
98
111
const exprt &access_lb,
99
112
const exprt &access_ub);
113
+ conditionst address_check (const exprt &address, const exprt &size);
100
114
void integer_overflow_check (const exprt &expr, const guardt &guard);
101
115
void conversion_check (const exprt &expr, const guardt &guard);
102
116
void float_overflow_check (const exprt &expr, const guardt &guard);
103
117
void nan_check (const exprt &expr, const guardt &guard);
118
+ void rw_ok_check (exprt &expr);
104
119
105
120
std::string array_name (const exprt &expr);
106
121
@@ -139,6 +154,8 @@ class goto_checkt
139
154
typedef optionst::value_listt error_labelst;
140
155
error_labelst error_labels;
141
156
157
+ // the first element of the pair is the base address,
158
+ // and the second is the size of the region
142
159
typedef std::pair<exprt, exprt> allocationt;
143
160
typedef std::list<allocationt> allocationst;
144
161
allocationst allocations;
@@ -1076,6 +1093,113 @@ void goto_checkt::pointer_validity_check(
1076
1093
}
1077
1094
}
1078
1095
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
+
1079
1203
std::string goto_checkt::array_name (const exprt &expr)
1080
1204
{
1081
1205
return ::array_name (ns, expr);
@@ -1494,6 +1618,27 @@ void goto_checkt::check(const exprt &expr)
1494
1618
check_rec (expr, guard, false );
1495
1619
}
1496
1620
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
+
1497
1642
void goto_checkt::goto_check (
1498
1643
goto_functiont &goto_function,
1499
1644
const irep_idt &_mode)
@@ -1643,6 +1788,9 @@ void goto_checkt::goto_check(
1643
1788
else if (i.is_assert ())
1644
1789
{
1645
1790
bool is_user_provided=i.source_location .get_bool (" user-provided" );
1791
+
1792
+ rw_ok_check (i.guard );
1793
+
1646
1794
if ((is_user_provided && !enable_assertions &&
1647
1795
i.source_location .get_property_class ()!=" error label" ) ||
1648
1796
(!is_user_provided && !enable_built_in_assertions))
0 commit comments