Skip to content

Commit 732ce2a

Browse files
author
Daniel Kroening
committed
expand __CPROVER_r/w_ok in goto_check
1 parent acfea65 commit 732ce2a

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

src/analyses/goto_check.cpp

Lines changed: 153 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;
@@ -1092,6 +1109,118 @@ void goto_checkt::pointer_validity_check(
10921109
}
10931110
}
10941111

1112+
goto_checkt::conditionst
1113+
goto_checkt::address_check(const exprt &address, const exprt &size)
1114+
{
1115+
if(!enable_pointer_check)
1116+
return {};
1117+
1118+
PRECONDITION(address.type().id() == ID_pointer);
1119+
const auto &pointer_type = to_pointer_type(address.type());
1120+
1121+
local_bitvector_analysist::flagst flags =
1122+
local_bitvector_analysis->get(t, address);
1123+
1124+
// For Java, we only need to check for null
1125+
if(mode == ID_java)
1126+
{
1127+
if(flags.is_unknown() || flags.is_null())
1128+
{
1129+
notequal_exprt not_eq_null(address, null_pointer_exprt(pointer_type));
1130+
1131+
return {conditiont(not_eq_null, "reference is null")};
1132+
}
1133+
else
1134+
return {};
1135+
}
1136+
else
1137+
{
1138+
conditionst conditions;
1139+
exprt::operandst alloc_disjuncts;
1140+
1141+
for(const auto &a : allocations)
1142+
{
1143+
typecast_exprt int_ptr(address, a.first.type());
1144+
1145+
binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
1146+
1147+
plus_exprt ub(int_ptr, size, int_ptr.type());
1148+
1149+
binary_relation_exprt ub_check(ub, ID_le, plus_exprt(a.first, a.second));
1150+
1151+
alloc_disjuncts.push_back(and_exprt(lb_check, ub_check));
1152+
}
1153+
1154+
const exprt allocs = disjunction(alloc_disjuncts);
1155+
1156+
if(flags.is_unknown() || flags.is_null())
1157+
{
1158+
conditions.push_back(conditiont(
1159+
or_exprt(allocs, not_exprt(null_pointer(address))), "pointer NULL"));
1160+
}
1161+
1162+
if(flags.is_unknown())
1163+
{
1164+
conditions.push_back(conditiont(
1165+
not_exprt(invalid_pointer(address)),
1166+
"pointer invalid"));
1167+
}
1168+
1169+
if(flags.is_uninitialized())
1170+
{
1171+
conditions.push_back(conditiont(
1172+
or_exprt(allocs, not_exprt(invalid_pointer(address))),
1173+
"pointer uninitialized"));
1174+
}
1175+
1176+
if(flags.is_unknown() || flags.is_dynamic_heap())
1177+
{
1178+
conditions.push_back(conditiont(
1179+
not_exprt(deallocated(address, ns)),
1180+
"deallocated dynamic object"));
1181+
}
1182+
1183+
if(flags.is_unknown() || flags.is_dynamic_local())
1184+
{
1185+
conditions.push_back(conditiont(
1186+
not_exprt(dead_object(address, ns)), "dead object"));
1187+
}
1188+
1189+
if(flags.is_unknown() || flags.is_dynamic_heap())
1190+
{
1191+
const or_exprt dynamic_bounds_violation(
1192+
dynamic_object_lower_bound(address, ns, nil_exprt()),
1193+
dynamic_object_upper_bound(address, ns, size));
1194+
1195+
conditions.push_back(conditiont(
1196+
implies_exprt(malloc_object(address, ns), not_exprt(dynamic_bounds_violation)),
1197+
"pointer outside dynamic object bounds"));
1198+
}
1199+
1200+
if(
1201+
flags.is_unknown() || flags.is_dynamic_local() ||
1202+
flags.is_static_lifetime())
1203+
{
1204+
const or_exprt object_bounds_violation(
1205+
object_lower_bound(address, ns, nil_exprt()),
1206+
object_upper_bound(address, ns, size));
1207+
1208+
conditions.push_back(conditiont(
1209+
implies_exprt(not_exprt(dynamic_object(address)), not_exprt(object_bounds_violation)),
1210+
"dereference failure: pointer outside object bounds"));
1211+
}
1212+
1213+
if(flags.is_unknown() || flags.is_integer_address())
1214+
{
1215+
conditions.push_back(conditiont(
1216+
implies_exprt(integer_address(address), allocs),
1217+
"invalid integer address"));
1218+
}
1219+
1220+
return conditions;
1221+
}
1222+
}
1223+
10951224
std::string goto_checkt::array_name(const exprt &expr)
10961225
{
10971226
return ::array_name(ns, expr);
@@ -1510,6 +1639,27 @@ void goto_checkt::check(const exprt &expr)
15101639
check_rec(expr, guard, false);
15111640
}
15121641

1642+
/// expand the r_ok and w_ok predicates
1643+
void goto_checkt::rw_ok_check(exprt &expr)
1644+
{
1645+
for(auto &op : expr.operands())
1646+
rw_ok_check(op);
1647+
1648+
if(expr.id() == ID_r_ok || expr.id() == ID_w_ok)
1649+
{
1650+
// these get an address as first argument and a size as second
1651+
DATA_INVARIANT(
1652+
expr.operands().size() == 2, "r/w_ok must have two operands");
1653+
1654+
const auto conditions = address_check(expr.op0(), expr.op1());
1655+
exprt::operandst conjuncts;
1656+
for(const auto &c : conditions)
1657+
conjuncts.push_back(c.assertion);
1658+
1659+
expr = conjunction(conjuncts);
1660+
}
1661+
}
1662+
15131663
void goto_checkt::goto_check(
15141664
goto_functiont &goto_function,
15151665
const irep_idt &_mode)
@@ -1659,6 +1809,9 @@ void goto_checkt::goto_check(
16591809
else if(i.is_assert())
16601810
{
16611811
bool is_user_provided=i.source_location.get_bool("user-provided");
1812+
1813+
rw_ok_check(i.guard);
1814+
16621815
if((is_user_provided && !enable_assertions &&
16631816
i.source_location.get_property_class()!="error label") ||
16641817
(!is_user_provided && !enable_built_in_assertions))

0 commit comments

Comments
 (0)