Skip to content

Commit c3b72e4

Browse files
authored
Merge pull request #7394 from tautschnig/bugfixes/array-out-of-bounds
get_subexpression_at_offset: do not permit out-of-bounds access
2 parents 3e490c9 + 941030e commit c3b72e4

File tree

4 files changed

+23
-33
lines changed

4 files changed

+23
-33
lines changed

jbmc/src/java_bytecode/java_trace_validation.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -285,18 +285,7 @@ static void check_rhs_assumptions(
285285
// check byte extract rhs structure
286286
else if(const auto byte = expr_try_dynamic_cast<byte_extract_exprt>(rhs))
287287
{
288-
DATA_CHECK_WITH_DIAGNOSTICS(
289-
vm,
290-
byte->operands().size() == 2,
291-
"RHS",
292-
rhs.pretty(),
293-
"Expecting a byte extract with two operands.");
294-
DATA_CHECK_WITH_DIAGNOSTICS(
295-
vm,
296-
can_cast_expr<constant_exprt>(simplify_expr(byte->op(), ns)),
297-
"RHS",
298-
rhs.pretty(),
299-
"Expecting a byte extract with constant value.");
288+
check_rhs_assumptions(simplify_expr(byte->op(), ns), ns, vm);
300289
DATA_CHECK_WITH_DIAGNOSTICS(
301290
vm,
302291
can_cast_expr<constant_exprt>(simplify_expr(byte->offset(), ns)),
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
--verbosity 10
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$
77
--
88
^warning: ignoring
9-
--
10-
assert(s) fails with field sensitivity, but passes without

src/solvers/flattening/boolbv_get.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,11 @@ exprt boolbvt::bv_get_unbounded_array(const exprt &expr) const
297297
exprt size=simplify_expr(get(size_expr), ns);
298298

299299
// get the numeric value, unless it's infinity
300-
mp_integer size_mpint = 0;
300+
const auto size_opt = numeric_cast<mp_integer>(size);
301301

302-
if(size.is_not_nil() && size.id() != ID_infinity)
303-
{
304-
const auto size_opt = numeric_cast<mp_integer>(size);
305-
if(size_opt.has_value() && *size_opt >= 0)
306-
size_mpint = *size_opt;
307-
}
308-
309-
// search array indices
302+
// search array indices, and only use those applicable to a particular model
303+
// (array theory may have seen other indices, which might only be live under a
304+
// different model)
310305

311306
typedef std::map<mp_integer, exprt> valuest;
312307
valuest values;
@@ -336,7 +331,9 @@ exprt boolbvt::bv_get_unbounded_array(const exprt &expr) const
336331
{
337332
const auto index_mpint = numeric_cast<mp_integer>(index_value);
338333

339-
if(index_mpint.has_value())
334+
if(
335+
index_mpint.has_value() && *index_mpint >= 0 &&
336+
(!size_opt.has_value() || *index_mpint < *size_opt))
340337
{
341338
if(value.is_nil())
342339
values[*index_mpint] =
@@ -350,7 +347,7 @@ exprt boolbvt::bv_get_unbounded_array(const exprt &expr) const
350347

351348
exprt result;
352349

353-
if(values.size() != size_mpint)
350+
if(!size_opt.has_value() || values.size() != *size_opt)
354351
{
355352
result = array_list_exprt({}, to_array_type(type));
356353

@@ -370,17 +367,18 @@ exprt boolbvt::bv_get_unbounded_array(const exprt &expr) const
370367
result=exprt(ID_array, type);
371368

372369
// allocate operands
373-
std::size_t size_int = numeric_cast_v<std::size_t>(size_mpint);
370+
std::size_t size_int = numeric_cast_v<std::size_t>(*size_opt);
374371
result.operands().resize(size_int, exprt{ID_unknown});
375372

376373
// search uninterpreted functions
377374

378375
for(valuest::iterator it=values.begin();
379376
it!=values.end();
380377
it++)
381-
if(it->first>=0 && it->first<size_mpint)
382-
result.operands()[numeric_cast_v<std::size_t>(it->first)].swap(
383-
it->second);
378+
{
379+
result.operands()[numeric_cast_v<std::size_t>(it->first)].swap(
380+
it->second);
381+
}
384382
}
385383

386384
return result;

src/util/pointer_offset_size.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,17 +633,22 @@ optionalt<exprt> get_subexpression_at_offset(
633633

634634
// no arrays of non-byte-aligned, zero-, or unknown-sized objects
635635
if(
636-
elem_size_bits.has_value() && *elem_size_bits > 0 &&
637-
*elem_size_bits % config.ansi_c.char_width == 0 &&
636+
array_type.size().is_constant() && elem_size_bits.has_value() &&
637+
*elem_size_bits > 0 && *elem_size_bits % config.ansi_c.char_width == 0 &&
638638
*target_size_bits <= *elem_size_bits)
639639
{
640+
const mp_integer array_size =
641+
numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
640642
const mp_integer elem_size_bytes =
641643
*elem_size_bits / config.ansi_c.char_width;
644+
const mp_integer index = offset_bytes / elem_size_bytes;
642645
const auto offset_inside_elem = offset_bytes % elem_size_bytes;
643646
const auto target_size_bytes =
644647
*target_size_bits / config.ansi_c.char_width;
645648
// only recurse if the cell completely contains the target
646-
if(offset_inside_elem + target_size_bytes <= elem_size_bytes)
649+
if(
650+
index < array_size &&
651+
offset_inside_elem + target_size_bytes <= elem_size_bytes)
647652
{
648653
return get_subexpression_at_offset(
649654
index_exprt(

0 commit comments

Comments
 (0)