Skip to content

Commit cfd387d

Browse files
Refactor address_check
1. Renames address_check to get_pointer_dereferenceable_conditions. The reasoning here is that the various _check functions should correspond to the --*-check options, whereas this function is a helper used by these 2. Split its implementation to separate the null check (which is done differently in Java than in C or languages with C-like semantics) and the other checks (which are not to be done in Java at all).
1 parent d5a0359 commit cfd387d

File tree

1 file changed

+158
-119
lines changed

1 file changed

+158
-119
lines changed

src/analyses/goto_check.cpp

Lines changed: 158 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,18 @@ class goto_checkt
202202
/// \return true if the given expression is a pointer primitive
203203
bool is_pointer_primitive(const exprt &expr);
204204

205-
conditionst address_check(const exprt &address, const exprt &size);
205+
optionalt<goto_checkt::conditiont>
206+
get_pointer_is_null_condition(const exprt &address, const exprt &size);
207+
conditionst get_pointer_points_to_valid_memory_conditions(
208+
const exprt &address,
209+
const exprt &size);
210+
exprt is_in_bounds_of_some_explicit_allocation(
211+
const exprt &pointer,
212+
const exprt &size);
213+
214+
conditionst get_pointer_dereferenceable_conditions(
215+
const exprt &address,
216+
const exprt &size);
206217
void integer_overflow_check(const exprt &, const guardt &);
207218
void conversion_check(const exprt &, const guardt &);
208219
void float_overflow_check(const exprt &, const guardt &);
@@ -1181,7 +1192,7 @@ void goto_checkt::pointer_validity_check(
11811192
size = size_of_expr_opt.value();
11821193
}
11831194

1184-
auto conditions = address_check(pointer, size);
1195+
auto conditions = get_pointer_dereferenceable_conditions(pointer, size);
11851196

11861197
for(const auto &c : conditions)
11871198
{
@@ -1225,7 +1236,7 @@ void goto_checkt::pointer_primitive_check(
12251236
? from_integer(1, size_type())
12261237
: size_of_expr_opt.value();
12271238

1228-
const conditionst &conditions = address_check(pointer, size);
1239+
const conditionst &conditions = get_pointer_dereferenceable_conditions(pointer, size);
12291240

12301241
exprt::operandst conjuncts;
12311242

@@ -1253,123 +1264,17 @@ bool goto_checkt::is_pointer_primitive(const exprt &expr)
12531264
expr.id() == ID_w_ok || expr.id() == ID_is_dynamic_object;
12541265
}
12551266

1256-
goto_checkt::conditionst
1257-
goto_checkt::address_check(const exprt &address, const exprt &size)
1267+
goto_checkt::conditionst goto_checkt::get_pointer_dereferenceable_conditions(
1268+
const exprt &address,
1269+
const exprt &size)
12581270
{
1259-
PRECONDITION(local_bitvector_analysis);
1260-
PRECONDITION(address.type().id() == ID_pointer);
1261-
const auto &pointer_type = to_pointer_type(address.type());
1262-
1263-
local_bitvector_analysist::flagst flags =
1264-
local_bitvector_analysis->get(current_target, address);
1265-
1266-
// For Java, we only need to check for null
1267-
if(mode == ID_java)
1271+
auto conditions =
1272+
get_pointer_points_to_valid_memory_conditions(address, size);
1273+
if(auto maybe_null_condition = get_pointer_is_null_condition(address, size))
12681274
{
1269-
if(flags.is_unknown() || flags.is_null())
1270-
{
1271-
notequal_exprt not_eq_null(address, null_pointer_exprt(pointer_type));
1272-
1273-
return {conditiont(not_eq_null, "reference is null")};
1274-
}
1275-
else
1276-
return {};
1277-
}
1278-
else
1279-
{
1280-
conditionst conditions;
1281-
exprt::operandst alloc_disjuncts;
1282-
1283-
for(const auto &a : allocations)
1284-
{
1285-
typecast_exprt int_ptr(address, a.first.type());
1286-
1287-
binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
1288-
1289-
plus_exprt ub{int_ptr, size};
1290-
1291-
binary_relation_exprt ub_check(ub, ID_le, plus_exprt(a.first, a.second));
1292-
1293-
alloc_disjuncts.push_back(and_exprt(lb_check, ub_check));
1294-
}
1295-
1296-
const exprt in_bounds_of_some_explicit_allocation =
1297-
disjunction(alloc_disjuncts);
1298-
1299-
const bool unknown = flags.is_unknown() || flags.is_uninitialized();
1300-
1301-
if(unknown || flags.is_null())
1302-
{
1303-
conditions.push_back(conditiont(
1304-
or_exprt(
1305-
in_bounds_of_some_explicit_allocation,
1306-
not_exprt(null_pointer(address))),
1307-
"pointer NULL"));
1308-
}
1309-
1310-
if(unknown)
1311-
{
1312-
conditions.push_back(conditiont{
1313-
not_exprt{is_invalid_pointer_exprt{address}}, "pointer invalid"});
1314-
}
1315-
1316-
if(unknown || flags.is_dynamic_heap())
1317-
{
1318-
conditions.push_back(conditiont(
1319-
or_exprt(
1320-
in_bounds_of_some_explicit_allocation,
1321-
not_exprt(deallocated(address, ns))),
1322-
"deallocated dynamic object"));
1323-
}
1324-
1325-
if(unknown || flags.is_dynamic_local())
1326-
{
1327-
conditions.push_back(conditiont(
1328-
or_exprt(
1329-
in_bounds_of_some_explicit_allocation,
1330-
not_exprt(dead_object(address, ns))),
1331-
"dead object"));
1332-
}
1333-
1334-
if(unknown || flags.is_dynamic_heap())
1335-
{
1336-
const or_exprt object_bounds_violation(
1337-
object_lower_bound(address, nil_exprt()),
1338-
object_upper_bound(address, size));
1339-
1340-
conditions.push_back(conditiont(
1341-
or_exprt(
1342-
in_bounds_of_some_explicit_allocation,
1343-
implies_exprt(
1344-
dynamic_object(address), not_exprt(object_bounds_violation))),
1345-
"pointer outside dynamic object bounds"));
1346-
}
1347-
1348-
if(unknown || flags.is_dynamic_local() || flags.is_static_lifetime())
1349-
{
1350-
const or_exprt object_bounds_violation(
1351-
object_lower_bound(address, nil_exprt()),
1352-
object_upper_bound(address, size));
1353-
1354-
conditions.push_back(conditiont(
1355-
or_exprt(
1356-
in_bounds_of_some_explicit_allocation,
1357-
implies_exprt(
1358-
not_exprt(dynamic_object(address)),
1359-
not_exprt(object_bounds_violation))),
1360-
"pointer outside object bounds"));
1361-
}
1362-
1363-
if(unknown || flags.is_integer_address())
1364-
{
1365-
conditions.push_back(conditiont(
1366-
implies_exprt(
1367-
integer_address(address), in_bounds_of_some_explicit_allocation),
1368-
"invalid integer address"));
1369-
}
1370-
1371-
return conditions;
1275+
conditions.push_front(*maybe_null_condition);
13721276
}
1277+
return conditions;
13731278
}
13741279

13751280
std::string goto_checkt::array_name(const exprt &expr)
@@ -1855,8 +1760,8 @@ optionalt<exprt> goto_checkt::rw_ok_check(exprt expr)
18551760
DATA_INVARIANT(
18561761
expr.operands().size() == 2, "r/w_ok must have two operands");
18571762

1858-
const auto conditions =
1859-
address_check(to_binary_expr(expr).op0(), to_binary_expr(expr).op1());
1763+
const auto conditions = get_pointer_dereferenceable_conditions(
1764+
to_binary_expr(expr).op0(), to_binary_expr(expr).op1());
18601765

18611766
exprt::operandst conjuncts;
18621767

@@ -2228,6 +2133,140 @@ void goto_checkt::goto_check(
22282133
remove_skip(goto_program);
22292134
}
22302135

2136+
goto_checkt::conditionst
2137+
goto_checkt::get_pointer_points_to_valid_memory_conditions(
2138+
const exprt &address,
2139+
const exprt &size)
2140+
{
2141+
PRECONDITION(local_bitvector_analysis);
2142+
PRECONDITION(address.type().id() == ID_pointer);
2143+
local_bitvector_analysist::flagst flags =
2144+
local_bitvector_analysis->get(current_target, address);
2145+
2146+
conditionst conditions;
2147+
2148+
if(mode == ID_java)
2149+
{
2150+
// The following conditions don’t apply to Java
2151+
return conditions;
2152+
}
2153+
2154+
const exprt in_bounds_of_some_explicit_allocation =
2155+
is_in_bounds_of_some_explicit_allocation(address, size);
2156+
2157+
const bool unknown = flags.is_unknown() || flags.is_uninitialized();
2158+
2159+
if(unknown)
2160+
{
2161+
conditions.push_back(conditiont{
2162+
not_exprt{is_invalid_pointer_exprt{address}}, "pointer invalid"});
2163+
}
2164+
2165+
if(unknown || flags.is_dynamic_heap())
2166+
{
2167+
conditions.push_back(conditiont(
2168+
or_exprt(
2169+
in_bounds_of_some_explicit_allocation,
2170+
not_exprt(deallocated(address, ns))),
2171+
"deallocated dynamic object"));
2172+
}
2173+
2174+
if(unknown || flags.is_dynamic_local())
2175+
{
2176+
conditions.push_back(conditiont(
2177+
or_exprt(
2178+
in_bounds_of_some_explicit_allocation,
2179+
not_exprt(dead_object(address, ns))),
2180+
"dead object"));
2181+
}
2182+
2183+
if(unknown || flags.is_dynamic_heap())
2184+
{
2185+
const or_exprt object_bounds_violation(
2186+
object_lower_bound(address, nil_exprt()),
2187+
object_upper_bound(address, size));
2188+
2189+
conditions.push_back(conditiont(
2190+
or_exprt(
2191+
in_bounds_of_some_explicit_allocation,
2192+
implies_exprt(
2193+
dynamic_object(address), not_exprt(object_bounds_violation))),
2194+
"pointer outside dynamic object bounds"));
2195+
}
2196+
2197+
if(unknown || flags.is_dynamic_local() || flags.is_static_lifetime())
2198+
{
2199+
const or_exprt object_bounds_violation(
2200+
object_lower_bound(address, nil_exprt()),
2201+
object_upper_bound(address, size));
2202+
2203+
conditions.push_back(conditiont(
2204+
or_exprt(
2205+
in_bounds_of_some_explicit_allocation,
2206+
implies_exprt(
2207+
not_exprt(dynamic_object(address)),
2208+
not_exprt(object_bounds_violation))),
2209+
"pointer outside object bounds"));
2210+
}
2211+
2212+
if(unknown || flags.is_integer_address())
2213+
{
2214+
conditions.push_back(conditiont(
2215+
implies_exprt(
2216+
integer_address(address), in_bounds_of_some_explicit_allocation),
2217+
"invalid integer address"));
2218+
}
2219+
2220+
return conditions;
2221+
}
2222+
2223+
optionalt<goto_checkt::conditiont> goto_checkt::get_pointer_is_null_condition(
2224+
const exprt &address,
2225+
const exprt &size)
2226+
{
2227+
PRECONDITION(local_bitvector_analysis);
2228+
PRECONDITION(address.type().id() == ID_pointer);
2229+
const auto &pointer_type = to_pointer_type(address.type());
2230+
local_bitvector_analysist::flagst flags =
2231+
local_bitvector_analysis->get(current_target, address);
2232+
if(mode == ID_java)
2233+
{
2234+
if(flags.is_unknown() || flags.is_null())
2235+
{
2236+
notequal_exprt not_eq_null(address, null_pointer_exprt{pointer_type});
2237+
return {conditiont{not_eq_null, "reference is null"}};
2238+
}
2239+
}
2240+
else if(flags.is_unknown() || flags.is_uninitialized() || flags.is_null())
2241+
{
2242+
return {conditiont{
2243+
or_exprt{is_in_bounds_of_some_explicit_allocation(address, size),
2244+
not_exprt(null_pointer(address))},
2245+
"pointer NULL"}};
2246+
}
2247+
return {};
2248+
}
2249+
2250+
exprt goto_checkt::is_in_bounds_of_some_explicit_allocation(
2251+
const exprt &pointer,
2252+
const exprt &size)
2253+
{
2254+
exprt::operandst alloc_disjuncts;
2255+
for(const auto &a : allocations)
2256+
{
2257+
typecast_exprt int_ptr(pointer, a.first.type());
2258+
2259+
binary_relation_exprt lb_check(a.first, ID_le, int_ptr);
2260+
2261+
plus_exprt ub{int_ptr, size};
2262+
2263+
binary_relation_exprt ub_check(ub, ID_le, plus_exprt(a.first, a.second));
2264+
2265+
alloc_disjuncts.push_back(and_exprt(lb_check, ub_check));
2266+
}
2267+
return disjunction(alloc_disjuncts);
2268+
}
2269+
22312270
void goto_check(
22322271
const irep_idt &function_identifier,
22332272
goto_functionst::goto_functiont &goto_function,

0 commit comments

Comments
 (0)