@@ -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;
@@ -1092,6 +1109,118 @@ void goto_checkt::pointer_validity_check(
1092
1109
}
1093
1110
}
1094
1111
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
+
1095
1224
std::string goto_checkt::array_name (const exprt &expr)
1096
1225
{
1097
1226
return ::array_name (ns, expr);
@@ -1510,6 +1639,27 @@ void goto_checkt::check(const exprt &expr)
1510
1639
check_rec (expr, guard, false );
1511
1640
}
1512
1641
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
+
1513
1663
void goto_checkt::goto_check (
1514
1664
goto_functiont &goto_function,
1515
1665
const irep_idt &_mode)
@@ -1659,6 +1809,9 @@ void goto_checkt::goto_check(
1659
1809
else if (i.is_assert ())
1660
1810
{
1661
1811
bool is_user_provided=i.source_location .get_bool (" user-provided" );
1812
+
1813
+ rw_ok_check (i.guard );
1814
+
1662
1815
if ((is_user_provided && !enable_assertions &&
1663
1816
i.source_location .get_property_class ()!=" error label" ) ||
1664
1817
(!is_user_provided && !enable_built_in_assertions))
0 commit comments