Skip to content

Commit 93ed54f

Browse files
author
Daniel Kroening
committed
expand __CPROVER_r/w_ok in goto_check
1 parent afc1f35 commit 93ed54f

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;
@@ -1085,6 +1102,113 @@ void goto_checkt::pointer_validity_check(
10851102
}
10861103
}
10871104

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

1630+
/// expand the r_ok and w_ok predicates
1631+
void goto_checkt::rw_ok_check(exprt &expr)
1632+
{
1633+
for(auto &op : expr.operands())
1634+
rw_ok_check(op);
1635+
1636+
if(expr.id() == ID_r_ok || expr.id() == ID_w_ok)
1637+
{
1638+
// these get an address as first argument and a size as second
1639+
DATA_INVARIANT(
1640+
expr.operands().size() == 2, "r/w_ok must have two operands");
1641+
1642+
const auto conditions = address_check(expr.op0(), expr.op1());
1643+
exprt::operandst conjuncts;
1644+
for(const auto &c : conditions)
1645+
conjuncts.push_back(c.assertion);
1646+
1647+
expr = conjunction(conjuncts);
1648+
}
1649+
}
1650+
15061651
void goto_checkt::goto_check(
15071652
goto_functiont &goto_function,
15081653
const irep_idt &_mode)
@@ -1652,6 +1797,9 @@ void goto_checkt::goto_check(
16521797
else if(i.is_assert())
16531798
{
16541799
bool is_user_provided=i.source_location.get_bool("user-provided");
1800+
1801+
rw_ok_check(i.guard);
1802+
16551803
if((is_user_provided && !enable_assertions &&
16561804
i.source_location.get_property_class()!="error label") ||
16571805
(!is_user_provided && !enable_built_in_assertions))

0 commit comments

Comments
 (0)