@@ -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;
@@ -1085,6 +1102,113 @@ void goto_checkt::pointer_validity_check(
1085
1102
}
1086
1103
}
1087
1104
1105
+ goto_checkt::conditionst
1106
+ goto_checkt::address_check (const exprt &address, const exprt &size)
1107
+ {
1108
+ if (!enable_pointer_check)
1109
+ return {};
1110
+
1111
+ PRECONDITION (address.type ().id () == ID_pointer);
1112
+ const auto &pointer_type = to_pointer_type (address.type ());
1113
+
1114
+ local_bitvector_analysist::flagst flags =
1115
+ local_bitvector_analysis->get (t, address);
1116
+
1117
+ // For Java, we only need to check for null
1118
+ if (mode == ID_java)
1119
+ {
1120
+ if (flags.is_unknown () || flags.is_null ())
1121
+ {
1122
+ notequal_exprt not_eq_null (address, null_pointer_exprt (pointer_type));
1123
+
1124
+ return {conditiont (not_eq_null, " reference is null" )};
1125
+ }
1126
+ else
1127
+ return {};
1128
+ }
1129
+ else
1130
+ {
1131
+ conditionst conditions;
1132
+ exprt::operandst alloc_disjuncts;
1133
+
1134
+ for (const auto &a : allocations)
1135
+ {
1136
+ typecast_exprt int_ptr (address, a.first .type ());
1137
+
1138
+ binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
1139
+
1140
+ plus_exprt ub (int_ptr, size, int_ptr.type ());
1141
+
1142
+ binary_relation_exprt ub_check (ub, ID_le, plus_exprt (a.first , a.second ));
1143
+
1144
+ alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
1145
+ }
1146
+
1147
+ const exprt allocs = disjunction (alloc_disjuncts);
1148
+
1149
+ if (flags.is_unknown () || flags.is_null ())
1150
+ {
1151
+ conditions.push_back (conditiont (
1152
+ or_exprt (allocs, not_exprt (null_pointer (address))), " pointer NULL" ));
1153
+ }
1154
+
1155
+ if (flags.is_unknown ())
1156
+ {
1157
+ conditions.push_back (conditiont (
1158
+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1159
+ " pointer invalid" ));
1160
+ }
1161
+
1162
+ if (flags.is_uninitialized ())
1163
+ {
1164
+ conditions.push_back (conditiont (
1165
+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1166
+ " pointer uninitialized" ));
1167
+ }
1168
+
1169
+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1170
+ {
1171
+ conditions.push_back (conditiont (
1172
+ or_exprt (allocs, not_exprt (deallocated (address, ns))),
1173
+ " deallocated dynamic object" ));
1174
+ }
1175
+
1176
+ if (flags.is_unknown () || flags.is_dynamic_local ())
1177
+ {
1178
+ conditions.push_back (conditiont (
1179
+ or_exprt (allocs, not_exprt (dead_object (address, ns))), " dead object" ));
1180
+ }
1181
+
1182
+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1183
+ {
1184
+ const or_exprt dynamic_bounds (
1185
+ dynamic_object_lower_bound (address, ns, nil_exprt ()),
1186
+ dynamic_object_upper_bound (address, ns, size));
1187
+
1188
+ conditions.push_back (conditiont (
1189
+ or_exprt (
1190
+ allocs,
1191
+ implies_exprt (malloc_object (address, ns), not_exprt (dynamic_bounds))),
1192
+ " pointer outside dynamic object bounds" ));
1193
+ }
1194
+
1195
+ if (
1196
+ flags.is_unknown () || flags.is_dynamic_local () ||
1197
+ flags.is_static_lifetime ())
1198
+ {
1199
+ const or_exprt object_bounds (
1200
+ object_lower_bound (address, ns, nil_exprt ()),
1201
+ object_upper_bound (address, ns, size));
1202
+
1203
+ conditions.push_back (conditiont (
1204
+ or_exprt (allocs, dynamic_object (address), not_exprt (object_bounds)),
1205
+ " dereference failure: pointer outside object bounds" ));
1206
+ }
1207
+
1208
+ return conditions;
1209
+ }
1210
+ }
1211
+
1088
1212
std::string goto_checkt::array_name (const exprt &expr)
1089
1213
{
1090
1214
return ::array_name (ns, expr);
@@ -1503,6 +1627,27 @@ void goto_checkt::check(const exprt &expr)
1503
1627
check_rec (expr, guard, false );
1504
1628
}
1505
1629
1630
+ // / expand the r_ok and w_ok predicates
1631
+ void goto_checkt::rw_ok_check (exprt &expr)
1632
+ {
1633
+ for (auto &op : expr.operands ())
1634
+ rw_ok_check (op);
1635
+
1636
+ if (expr.id () == ID_r_ok || expr.id () == ID_w_ok)
1637
+ {
1638
+ // these get an address as first argument and a size as second
1639
+ DATA_INVARIANT (
1640
+ expr.operands ().size () == 2 , " r/w_ok must have two operands" );
1641
+
1642
+ const auto conditions = address_check (expr.op0 (), expr.op1 ());
1643
+ exprt::operandst conjuncts;
1644
+ for (const auto &c : conditions)
1645
+ conjuncts.push_back (c.assertion );
1646
+
1647
+ expr = conjunction (conjuncts);
1648
+ }
1649
+ }
1650
+
1506
1651
void goto_checkt::goto_check (
1507
1652
goto_functiont &goto_function,
1508
1653
const irep_idt &_mode)
@@ -1652,6 +1797,9 @@ void goto_checkt::goto_check(
1652
1797
else if (i.is_assert ())
1653
1798
{
1654
1799
bool is_user_provided=i.source_location .get_bool (" user-provided" );
1800
+
1801
+ rw_ok_check (i.guard );
1802
+
1655
1803
if ((is_user_provided && !enable_assertions &&
1656
1804
i.source_location .get_property_class ()!=" error label" ) ||
1657
1805
(!is_user_provided && !enable_built_in_assertions))
0 commit comments