Skip to content

Commit 3d2e0e8

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

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

src/analyses/goto_check.cpp

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ 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), description(_description)
93+
{
94+
}
95+
96+
exprt assertion;
97+
std::string description;
98+
};
99+
100+
using conditionst = std::list<conditiont>;
101+
89102
void bounds_check(const index_exprt &expr, const guardt &guard);
90103
void div_by_zero_check(const div_exprt &expr, const guardt &guard);
91104
void mod_by_zero_check(const mod_exprt &expr, const guardt &guard);
@@ -97,10 +110,12 @@ class goto_checkt
97110
const guardt &guard,
98111
const exprt &access_lb,
99112
const exprt &access_ub);
113+
conditionst address_check(const exprt &address, const exprt &size);
100114
void integer_overflow_check(const exprt &expr, const guardt &guard);
101115
void conversion_check(const exprt &expr, const guardt &guard);
102116
void float_overflow_check(const exprt &expr, const guardt &guard);
103117
void nan_check(const exprt &expr, const guardt &guard);
118+
void rw_ok_check(exprt &expr);
104119

105120
std::string array_name(const exprt &expr);
106121

@@ -139,6 +154,8 @@ class goto_checkt
139154
typedef optionst::value_listt error_labelst;
140155
error_labelst error_labels;
141156

157+
// the first element of the pair is the base address,
158+
// and the second is the size of the region
142159
typedef std::pair<exprt, exprt> allocationt;
143160
typedef std::list<allocationt> allocationst;
144161
allocationst allocations;
@@ -1076,6 +1093,113 @@ void goto_checkt::pointer_validity_check(
10761093
}
10771094
}
10781095

1096+
goto_checkt::conditionst
1097+
goto_checkt::address_check(const exprt &address, const exprt &size)
1098+
{
1099+
if(!enable_pointer_check)
1100+
return {};
1101+
1102+
PRECONDITION(address.type().id() == ID_pointer);
1103+
const auto &pointer_type = to_pointer_type(address.type());
1104+
1105+
local_bitvector_analysist::flagst flags =
1106+
local_bitvector_analysis->get(t, address);
1107+
1108+
// For Java, we only need to check for null
1109+
if(mode == ID_java)
1110+
{
1111+
if(flags.is_unknown() || flags.is_null())
1112+
{
1113+
notequal_exprt not_eq_null(address, null_pointer_exprt(pointer_type));
1114+
1115+
return {conditiont(not_eq_null, "reference is null")};
1116+
}
1117+
else
1118+
return {};
1119+
}
1120+
else
1121+
{
1122+
conditionst conditions;
1123+
exprt::operandst alloc_disjuncts;
1124+
1125+
for(const auto &a : allocations)
1126+
{
1127+
typecast_exprt int_ptr(address, a.first.type());
1128+
1129+
binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
1130+
1131+
plus_exprt ub(int_ptr, size, int_ptr.type());
1132+
1133+
binary_relation_exprt ub_check(ub, ID_le, plus_exprt(a.first, a.second));
1134+
1135+
alloc_disjuncts.push_back(and_exprt(lb_check, ub_check));
1136+
}
1137+
1138+
const exprt allocs = disjunction(alloc_disjuncts);
1139+
1140+
if(flags.is_unknown() || flags.is_null())
1141+
{
1142+
conditions.push_back(conditiont(
1143+
or_exprt(allocs, not_exprt(null_pointer(address))), "pointer NULL"));
1144+
}
1145+
1146+
if(flags.is_unknown())
1147+
{
1148+
conditions.push_back(conditiont(
1149+
or_exprt(allocs, not_exprt(invalid_pointer(address))),
1150+
"pointer invalid"));
1151+
}
1152+
1153+
if(flags.is_uninitialized())
1154+
{
1155+
conditions.push_back(conditiont(
1156+
or_exprt(allocs, not_exprt(invalid_pointer(address))),
1157+
"pointer uninitialized"));
1158+
}
1159+
1160+
if(flags.is_unknown() || flags.is_dynamic_heap())
1161+
{
1162+
conditions.push_back(conditiont(
1163+
or_exprt(allocs, not_exprt(deallocated(address, ns))),
1164+
"deallocated dynamic object"));
1165+
}
1166+
1167+
if(flags.is_unknown() || flags.is_dynamic_local())
1168+
{
1169+
conditions.push_back(conditiont(
1170+
or_exprt(allocs, not_exprt(dead_object(address, ns))), "dead object"));
1171+
}
1172+
1173+
if(flags.is_unknown() || flags.is_dynamic_heap())
1174+
{
1175+
const or_exprt dynamic_bounds(
1176+
dynamic_object_lower_bound(address, ns, nil_exprt()),
1177+
dynamic_object_upper_bound(address, ns, size));
1178+
1179+
conditions.push_back(conditiont(
1180+
or_exprt(
1181+
allocs,
1182+
implies_exprt(malloc_object(address, ns), not_exprt(dynamic_bounds))),
1183+
"pointer outside dynamic object bounds"));
1184+
}
1185+
1186+
if(
1187+
flags.is_unknown() || flags.is_dynamic_local() ||
1188+
flags.is_static_lifetime())
1189+
{
1190+
const or_exprt object_bounds(
1191+
object_lower_bound(address, ns, nil_exprt()),
1192+
object_upper_bound(address, ns, size));
1193+
1194+
conditions.push_back(conditiont(
1195+
or_exprt(allocs, dynamic_object(address), not_exprt(object_bounds)),
1196+
"dereference failure: pointer outside object bounds"));
1197+
}
1198+
1199+
return conditions;
1200+
}
1201+
}
1202+
10791203
std::string goto_checkt::array_name(const exprt &expr)
10801204
{
10811205
return ::array_name(ns, expr);
@@ -1494,6 +1618,27 @@ void goto_checkt::check(const exprt &expr)
14941618
check_rec(expr, guard, false);
14951619
}
14961620

1621+
/// expand the r_ok and w_ok predicates
1622+
void goto_checkt::rw_ok_check(exprt &expr)
1623+
{
1624+
for(auto &op : expr.operands())
1625+
rw_ok_check(op);
1626+
1627+
if(expr.id() == ID_r_ok || expr.id() == ID_w_ok)
1628+
{
1629+
// these get an address as first argument and a size as second
1630+
DATA_INVARIANT(
1631+
expr.operands().size() == 2, "r/w_ok must have two operands");
1632+
1633+
const auto conditions = address_check(expr.op0(), expr.op1());
1634+
exprt::operandst conjuncts;
1635+
for(const auto &c : conditions)
1636+
conjuncts.push_back(c.assertion);
1637+
1638+
expr = conjunction(conjuncts);
1639+
}
1640+
}
1641+
14971642
void goto_checkt::goto_check(
14981643
goto_functiont &goto_function,
14991644
const irep_idt &_mode)
@@ -1643,6 +1788,9 @@ void goto_checkt::goto_check(
16431788
else if(i.is_assert())
16441789
{
16451790
bool is_user_provided=i.source_location.get_bool("user-provided");
1791+
1792+
rw_ok_check(i.guard);
1793+
16461794
if((is_user_provided && !enable_assertions &&
16471795
i.source_location.get_property_class()!="error label") ||
16481796
(!is_user_provided && !enable_built_in_assertions))

0 commit comments

Comments
 (0)