@@ -86,6 +86,20 @@ 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),
93
+ description (_description)
94
+ {
95
+ }
96
+
97
+ exprt assertion;
98
+ std::string description;
99
+ };
100
+
101
+ using conditionst=std::list<conditiont>;
102
+
89
103
void bounds_check (const index_exprt &expr, const guardt &guard);
90
104
void div_by_zero_check (const div_exprt &expr, const guardt &guard);
91
105
void mod_by_zero_check (const mod_exprt &expr, const guardt &guard);
@@ -97,10 +111,14 @@ class goto_checkt
97
111
const guardt &guard,
98
112
const exprt &access_lb,
99
113
const exprt &access_ub);
114
+ conditionst address_check (
115
+ const exprt &address,
116
+ const exprt &size);
100
117
void integer_overflow_check (const exprt &expr, const guardt &guard);
101
118
void conversion_check (const exprt &expr, const guardt &guard);
102
119
void float_overflow_check (const exprt &expr, const guardt &guard);
103
120
void nan_check (const exprt &expr, const guardt &guard);
121
+ void rw_ok_check (exprt &expr);
104
122
105
123
std::string array_name (const exprt &expr);
106
124
@@ -139,6 +157,8 @@ class goto_checkt
139
157
typedef optionst::value_listt error_labelst;
140
158
error_labelst error_labels;
141
159
160
+ // the first element of the pair is the base address,
161
+ // and the second is the size of the region
142
162
typedef std::pair<exprt, exprt> allocationt;
143
163
typedef std::list<allocationt> allocationst;
144
164
allocationst allocations;
@@ -1076,6 +1096,109 @@ void goto_checkt::pointer_validity_check(
1076
1096
}
1077
1097
}
1078
1098
1099
+ goto_checkt::conditionst goto_checkt::address_check (
1100
+ const exprt &address,
1101
+ const exprt &size)
1102
+ {
1103
+ if (!enable_pointer_check)
1104
+ return {};
1105
+
1106
+ PRECONDITION (address.type ().id ()==ID_pointer);
1107
+ const auto &pointer_type=to_pointer_type (address.type ());
1108
+
1109
+ local_bitvector_analysist::flagst flags=
1110
+ local_bitvector_analysis->get (t, address);
1111
+
1112
+ // For Java, we only need to check for null
1113
+ if (mode==ID_java)
1114
+ {
1115
+ if (flags.is_unknown () || flags.is_null ())
1116
+ {
1117
+ notequal_exprt not_eq_null (address, null_pointer_exprt (pointer_type));
1118
+
1119
+ return { conditiont (not_eq_null, " reference is null" ) };
1120
+ }
1121
+ else
1122
+ return {};
1123
+ }
1124
+ else
1125
+ {
1126
+ conditionst conditions;
1127
+ exprt::operandst alloc_disjuncts;
1128
+
1129
+ for (const auto &a : allocations)
1130
+ {
1131
+ typecast_exprt int_ptr (address, a.first .type ());
1132
+
1133
+ binary_relation_exprt lb_check (a.first , ID_le, int_ptr);
1134
+
1135
+ plus_exprt ub (int_ptr, size, int_ptr.type ());
1136
+
1137
+ binary_relation_exprt ub_check (
1138
+ ub, ID_le, plus_exprt (a.first , a.second ));
1139
+
1140
+ alloc_disjuncts.push_back (and_exprt (lb_check, ub_check));
1141
+ }
1142
+
1143
+ const exprt allocs=disjunction (alloc_disjuncts);
1144
+
1145
+ if (flags.is_unknown () || flags.is_null ())
1146
+ conditions.push_back (conditiont (
1147
+ or_exprt (allocs, not_exprt (null_pointer (address))),
1148
+ " pointer NULL" ));
1149
+
1150
+ if (flags.is_unknown ())
1151
+ conditions.push_back (conditiont (
1152
+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1153
+ " pointer invalid" ));
1154
+
1155
+ if (flags.is_uninitialized ())
1156
+ conditions.push_back (conditiont (
1157
+ or_exprt (allocs, not_exprt (invalid_pointer (address))),
1158
+ " pointer uninitialized" ));
1159
+
1160
+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1161
+ conditions.push_back (conditiont (
1162
+ or_exprt (allocs, not_exprt (deallocated (address, ns))),
1163
+ " deallocated dynamic object" ));
1164
+
1165
+ if (flags.is_unknown () || flags.is_dynamic_local ())
1166
+ conditions.push_back (conditiont (
1167
+ or_exprt (allocs, not_exprt (dead_object (address, ns))),
1168
+ " dead object" ));
1169
+
1170
+ if (flags.is_unknown () || flags.is_dynamic_heap ())
1171
+ {
1172
+ const or_exprt dynamic_bounds (
1173
+ dynamic_object_lower_bound (address, ns, nil_exprt ()),
1174
+ dynamic_object_upper_bound (address, ns, size));
1175
+
1176
+ conditions.push_back (conditiont (
1177
+ or_exprt (
1178
+ allocs,
1179
+ implies_exprt (
1180
+ malloc_object (address, ns),
1181
+ not_exprt (dynamic_bounds))),
1182
+ " pointer outside dynamic object bounds" ));
1183
+ }
1184
+
1185
+ if (flags.is_unknown () ||
1186
+ flags.is_dynamic_local () ||
1187
+ flags.is_static_lifetime ())
1188
+ {
1189
+ const or_exprt object_bounds (
1190
+ object_lower_bound (address, ns, nil_exprt ()),
1191
+ object_upper_bound (address, ns, size));
1192
+
1193
+ conditions.push_back (conditiont (
1194
+ or_exprt (allocs, dynamic_object (address), not_exprt (object_bounds)),
1195
+ " dereference failure: pointer outside object bounds" ));
1196
+ }
1197
+
1198
+ return conditions;
1199
+ }
1200
+ }
1201
+
1079
1202
std::string goto_checkt::array_name (const exprt &expr)
1080
1203
{
1081
1204
return ::array_name (ns, expr);
@@ -1494,6 +1617,27 @@ void goto_checkt::check(const exprt &expr)
1494
1617
check_rec (expr, guard, false );
1495
1618
}
1496
1619
1620
+ // / expand the r_ok and w_ok predicates
1621
+ void goto_checkt::rw_ok_check (exprt &expr)
1622
+ {
1623
+ for (auto &op : expr.operands ())
1624
+ rw_ok_check (op);
1625
+
1626
+ if (expr.id ()==ID_r_ok || expr.id ()==ID_w_ok)
1627
+ {
1628
+ // these get an address as first argument and a size as second
1629
+ DATA_INVARIANT (expr.operands ().size ()==2 ,
1630
+ " r/w_ok must have two operands" );
1631
+
1632
+ const auto conditions=address_check (expr.op0 (), expr.op1 ());
1633
+ exprt::operandst conjuncts;
1634
+ for (const auto &c : conditions)
1635
+ conjuncts.push_back (c.assertion );
1636
+
1637
+ expr=conjunction (conjuncts);
1638
+ }
1639
+ }
1640
+
1497
1641
void goto_checkt::goto_check (
1498
1642
goto_functiont &goto_function,
1499
1643
const irep_idt &_mode)
@@ -1643,6 +1787,9 @@ void goto_checkt::goto_check(
1643
1787
else if (i.is_assert ())
1644
1788
{
1645
1789
bool is_user_provided=i.source_location .get_bool (" user-provided" );
1790
+
1791
+ rw_ok_check (i.guard );
1792
+
1646
1793
if ((is_user_provided && !enable_assertions &&
1647
1794
i.source_location .get_property_class ()!=" error label" ) ||
1648
1795
(!is_user_provided && !enable_built_in_assertions))
0 commit comments