Skip to content

Commit 47601df

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

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

src/analyses/goto_check.cpp

Lines changed: 147 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,109 @@ 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+
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+
10791202
std::string goto_checkt::array_name(const exprt &expr)
10801203
{
10811204
return ::array_name(ns, expr);
@@ -1494,6 +1617,27 @@ void goto_checkt::check(const exprt &expr)
14941617
check_rec(expr, guard, false);
14951618
}
14961619

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+
14971641
void goto_checkt::goto_check(
14981642
goto_functiont &goto_function,
14991643
const irep_idt &_mode)
@@ -1643,6 +1787,9 @@ void goto_checkt::goto_check(
16431787
else if(i.is_assert())
16441788
{
16451789
bool is_user_provided=i.source_location.get_bool("user-provided");
1790+
1791+
rw_ok_check(i.guard);
1792+
16461793
if((is_user_provided && !enable_assertions &&
16471794
i.source_location.get_property_class()!="error label") ||
16481795
(!is_user_provided && !enable_built_in_assertions))

0 commit comments

Comments
 (0)