Skip to content

Commit ca539c9

Browse files
author
Daniel Kroening
committed
expand __CPROVER_r/w_ok in goto_check
1 parent 9c78d20 commit ca539c9

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

src/analyses/goto_check.cpp

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ 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),
93+
description(_description)
94+
{
95+
}
96+
97+
exprt assertion;
98+
std::string description;
99+
};
100+
101+
using conditionst=std::list<conditiont>;
102+
89103
void bounds_check(const index_exprt &expr, const guardt &guard);
90104
void div_by_zero_check(const div_exprt &expr, const guardt &guard);
91105
void mod_by_zero_check(const mod_exprt &expr, const guardt &guard);
@@ -97,10 +111,14 @@ class goto_checkt
97111
const guardt &guard,
98112
const exprt &access_lb,
99113
const exprt &access_ub);
114+
conditionst address_check(
115+
const exprt &address,
116+
const exprt &size);
100117
void integer_overflow_check(const exprt &expr, const guardt &guard);
101118
void conversion_check(const exprt &expr, const guardt &guard);
102119
void float_overflow_check(const exprt &expr, const guardt &guard);
103120
void nan_check(const exprt &expr, const guardt &guard);
121+
void rw_ok_check(exprt &expr);
104122

105123
std::string array_name(const exprt &expr);
106124

@@ -139,6 +157,8 @@ class goto_checkt
139157
typedef optionst::value_listt error_labelst;
140158
error_labelst error_labels;
141159

160+
// the first element of the pair is the base address,
161+
// and the second is the size of the region
142162
typedef std::pair<exprt, exprt> allocationt;
143163
typedef std::list<allocationt> allocationst;
144164
allocationst allocations;
@@ -1076,6 +1096,139 @@ void goto_checkt::pointer_validity_check(
10761096
}
10771097
}
10781098

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+
#if 0
1134+
exprt lb(int_ptr);
1135+
if(access_lb.is_not_nil())
1136+
{
1137+
if(!base_type_eq(lb.type(), access_lb.type(), ns))
1138+
lb=plus_exprt(lb, typecast_exprt(access_lb, lb.type()));
1139+
else
1140+
lb=plus_exprt(lb, access_lb);
1141+
}
1142+
1143+
binary_relation_exprt lb_check(a.first, ID_le, lb);
1144+
1145+
exprt ub(int_ptr);
1146+
if(access_ub.is_not_nil())
1147+
{
1148+
if(!base_type_eq(ub.type(), access_ub.type(), ns))
1149+
ub=plus_exprt(ub, typecast_exprt(access_ub, ub.type()));
1150+
else
1151+
ub=plus_exprt(ub, access_ub);
1152+
}
1153+
1154+
binary_relation_exprt ub_check(
1155+
ub, ID_le, plus_exprt(a.first, a.second));
1156+
1157+
alloc_disjuncts.push_back(and_exprt(lb_check, ub_check));
1158+
#endif
1159+
}
1160+
1161+
const exprt allocs=disjunction(alloc_disjuncts);
1162+
1163+
if(flags.is_unknown() || flags.is_null())
1164+
conditions.push_back(conditiont(
1165+
or_exprt(allocs, not_exprt(null_pointer(address))),
1166+
"pointer NULL"));
1167+
1168+
if(flags.is_unknown())
1169+
conditions.push_back(conditiont(
1170+
or_exprt(allocs, not_exprt(invalid_pointer(address))),
1171+
"pointer invalid"));
1172+
1173+
if(flags.is_uninitialized())
1174+
conditions.push_back(conditiont(
1175+
or_exprt(allocs, not_exprt(invalid_pointer(address))),
1176+
"pointer uninitialized"));
1177+
1178+
if(flags.is_unknown() || flags.is_dynamic_heap())
1179+
conditions.push_back(conditiont(
1180+
or_exprt(allocs, not_exprt(deallocated(address, ns))),
1181+
"deallocated dynamic object"));
1182+
1183+
if(flags.is_unknown() || flags.is_dynamic_local())
1184+
conditions.push_back(conditiont(
1185+
or_exprt(allocs, not_exprt(dead_object(address, ns))),
1186+
"dead object"));
1187+
1188+
if(flags.is_unknown() || flags.is_dynamic_heap())
1189+
{
1190+
#if 0
1191+
const or_exprt dynamic_bounds(
1192+
dynamic_object_lower_bound(address, ns, access_lb),
1193+
dynamic_object_upper_bound(address, dereference_type, ns, access_ub));
1194+
1195+
add_guarded_claim(
1196+
or_exprt(
1197+
allocs,
1198+
implies_exprt(
1199+
malloc_object(address, ns),
1200+
not_exprt(dynamic_bounds))),
1201+
"dereference failure: pointer outside dynamic object bounds",
1202+
"pointer dereference",
1203+
expr.find_source_location(),
1204+
expr,
1205+
guard);
1206+
#endif
1207+
}
1208+
1209+
if(flags.is_unknown() ||
1210+
flags.is_dynamic_local() ||
1211+
flags.is_static_lifetime())
1212+
{
1213+
#if 0
1214+
const or_exprt object_bounds(
1215+
object_lower_bound(address, ns, access_lb),
1216+
object_upper_bound(address, dereference_type, ns, access_ub));
1217+
1218+
add_guarded_claim(
1219+
or_exprt(allocs, dynamic_object(address), not_exprt(object_bounds)),
1220+
"dereference failure: pointer outside object bounds",
1221+
"pointer dereference",
1222+
expr.find_source_location(),
1223+
expr,
1224+
guard);
1225+
#endif
1226+
}
1227+
1228+
return conditions;
1229+
}
1230+
}
1231+
10791232
std::string goto_checkt::array_name(const exprt &expr)
10801233
{
10811234
return ::array_name(ns, expr);
@@ -1494,6 +1647,27 @@ void goto_checkt::check(const exprt &expr)
14941647
check_rec(expr, guard, false);
14951648
}
14961649

1650+
/// expand the r_ok and w_ok predicates
1651+
void goto_checkt::rw_ok_check(exprt &expr)
1652+
{
1653+
for(auto &op : expr.operands())
1654+
rw_ok_check(op);
1655+
1656+
if(expr.id()==ID_r_ok || expr.id()==ID_w_ok)
1657+
{
1658+
// these get an address as first argument and a size as second
1659+
DATA_INVARIANT(expr.operands().size()==2,
1660+
"r/w_ok must have two operands");
1661+
1662+
const auto conditions=address_check(expr.op0(), expr.op1());
1663+
exprt::operandst conjuncts;
1664+
for(const auto &c : conditions)
1665+
conjuncts.push_back(c.assertion);
1666+
1667+
expr=conjunction(conjuncts);
1668+
}
1669+
}
1670+
14971671
void goto_checkt::goto_check(
14981672
goto_functiont &goto_function,
14991673
const irep_idt &_mode)
@@ -1643,6 +1817,9 @@ void goto_checkt::goto_check(
16431817
else if(i.is_assert())
16441818
{
16451819
bool is_user_provided=i.source_location.get_bool("user-provided");
1820+
1821+
rw_ok_check(i.guard);
1822+
16461823
if((is_user_provided && !enable_assertions &&
16471824
i.source_location.get_property_class()!="error label") ||
16481825
(!is_user_provided && !enable_built_in_assertions))

0 commit comments

Comments
 (0)