Skip to content

Commit 0fc148f

Browse files
authored
Merge pull request #7267 from tautschnig/bugfixes/7265-array-alignment
Remove well-alignedness assumption from pointer-into-array
2 parents 9884da6 + b19b412 commit 0fc148f

File tree

9 files changed

+162
-87
lines changed

9 files changed

+162
-87
lines changed

jbmc/src/java_bytecode/java_trace_validation.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ bool can_evaluate_to_constant(const exprt &expression)
7979
{
8080
return can_cast_expr<constant_exprt>(skip_typecast(expression)) ||
8181
can_cast_expr<symbol_exprt>(skip_typecast(expression)) ||
82-
can_cast_expr<plus_exprt>(skip_typecast(expression));
82+
can_cast_expr<plus_exprt>(skip_typecast(expression)) ||
83+
can_cast_expr<mult_exprt>(skip_typecast(expression));
8384
}
8485

8586
bool check_index_structure(const exprt &index_expr)

regression/cbmc/Pointer_Arithmetic19/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE new-smt-backend
22
main.c
33
--program-only
4-
ASSERT\(\{ 42, 43 \}\[POINTER_OFFSET\(p!0@1#2\) / \d+l*\] == 43\)$
4+
ASSERT\(byte_extract_little_endian\(\{ 42, 43 \}, POINTER_OFFSET\(p!0@1#2\), signed int\) == 43\)$
55
^EXIT=0$
66
^SIGNAL=0$
77
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--big-endian -D__BIG_ENDIAN__
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/Pointer_array7/main.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
4+
#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
5+
6+
# if defined(__avr32__) || defined(__hppa__) || defined(__m68k__) || \
7+
defined(__mips__) || defined(__powerpc__) || defined(__s390__) || \
8+
defined(__s390x__) || defined(__sparc__)
9+
10+
# define __BIG_ENDIAN__
11+
12+
# endif
13+
14+
#endif
15+
16+
int main()
17+
{
18+
uint16_t x[2];
19+
x[0] = 1;
20+
x[1] = 2;
21+
uint8_t *y = (uint8_t *)x;
22+
uint16_t z = *((uint16_t *)(y + 1));
23+
24+
#ifdef __BIG_ENDIAN__
25+
assert(z == 256u);
26+
#else
27+
assert(z == 512u);
28+
#endif
29+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--little-endian -D__LITTLE_ENDIAN__
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

regression/cbmc/address_space_size_limit3/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE broken-smt-backend
1+
CORE thorough-smt-backend
22
main.i
33
--32 --little-endian --object-bits 25 --pointer-check
44
^EXIT=10$

src/pointer-analysis/value_set_dereference.cpp

Lines changed: 82 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ exprt value_set_dereferencet::dereference(
142142
const exprt &pointer,
143143
bool display_points_to_sets)
144144
{
145-
if(pointer.type().id()!=ID_pointer)
146-
throw "dereference expected pointer type, but got "+
147-
pointer.type().pretty();
145+
PRECONDITION_WITH_DIAGNOSTICS(
146+
pointer.type().id() == ID_pointer,
147+
"dereference expected pointer type, but got " + pointer.type().pretty());
148148

149149
// we may get ifs due to recursive calls
150150
if(pointer.id()==ID_if)
@@ -465,8 +465,9 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
465465
return valuet();
466466
}
467467

468-
if(what.id()!=ID_object_descriptor)
469-
throw "unknown points-to: "+what.id_string();
468+
PRECONDITION_WITH_DIAGNOSTICS(
469+
what.id() == ID_object_descriptor,
470+
"unknown points-to: " + what.id_string());
470471

471472
const object_descriptor_exprt &o=to_object_descriptor_expr(what);
472473

@@ -477,24 +478,28 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
477478
std::cout << "O: " << format(root_object) << '\n';
478479
#endif
479480

480-
valuet result;
481-
482481
if(root_object.id() == ID_null_object)
483482
{
484-
if(o.offset().is_zero())
485-
result.pointer = null_pointer_exprt{pointer_type};
486-
else
487-
return valuet{};
483+
if(!o.offset().is_zero())
484+
return {};
485+
486+
valuet result;
487+
result.pointer = null_pointer_exprt{pointer_type};
488+
return result;
488489
}
489490
else if(root_object.id()==ID_dynamic_object)
490491
{
492+
valuet result;
493+
491494
// constraint that it actually is a dynamic object
492495
// this is also our guard
493496
result.pointer_guard = is_dynamic_object_exprt(pointer_expr);
494497

495498
// can't remove here, turn into *p
496499
result.value = dereference_exprt{pointer_expr};
497500
result.pointer = pointer_expr;
501+
502+
return result;
498503
}
499504
else if(root_object.id()==ID_integer_address)
500505
{
@@ -514,8 +519,10 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
514519
pointer_offset(pointer_expr),
515520
to_array_type(memory_symbol.type).element_type());
516521

522+
valuet result;
517523
result.value=index_expr;
518524
result.pointer = address_of_exprt{index_expr};
525+
return result;
519526
}
520527
else if(dereference_type_compare(
521528
to_array_type(memory_symbol.type).element_type(),
@@ -526,28 +533,32 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
526533
symbol_expr,
527534
pointer_offset(pointer_expr),
528535
to_array_type(memory_symbol.type).element_type());
536+
537+
valuet result;
529538
result.value=typecast_exprt(index_expr, dereference_type);
530539
result.pointer =
531540
typecast_exprt{address_of_exprt{index_expr}, pointer_type};
541+
return result;
532542
}
533543
else
534544
{
535545
// We need to use byte_extract.
536546
// Won't do this without a commitment to an endianness.
537547

538548
if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS)
539-
{
540-
}
541-
else
542-
{
543-
result.value = make_byte_extract(
544-
symbol_expr, pointer_offset(pointer_expr), dereference_type);
545-
result.pointer = address_of_exprt{result.value};
546-
}
549+
return {};
550+
551+
valuet result;
552+
result.value = make_byte_extract(
553+
symbol_expr, pointer_offset(pointer_expr), dereference_type);
554+
result.pointer = address_of_exprt{result.value};
555+
return result;
547556
}
548557
}
549558
else
550559
{
560+
valuet result;
561+
551562
// something generic -- really has to be a symbol
552563
address_of_exprt object_pointer(object);
553564

@@ -565,8 +576,6 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
565576
const typet &object_type = object.type();
566577
const typet &root_object_type = root_object.type();
567578

568-
exprt root_object_subexpression=root_object;
569-
570579
if(
571580
dereference_type_compare(object_type, dereference_type, ns) &&
572581
o.offset().is_zero())
@@ -577,89 +586,81 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
577586
result.value = typecast_exprt::conditional_cast(object, dereference_type);
578587
result.pointer =
579588
typecast_exprt::conditional_cast(object_pointer, pointer_type);
589+
590+
return result;
580591
}
581-
else if(
592+
593+
// this is relative to the root object
594+
exprt offset;
595+
if(o.offset().is_constant())
596+
offset = o.offset();
597+
else
598+
offset = simplify_expr(pointer_offset(pointer_expr), ns);
599+
600+
if(
582601
root_object_type.id() == ID_array &&
583602
dereference_type_compare(
584603
to_array_type(root_object_type).element_type(), dereference_type, ns) &&
585604
pointer_offset_bits(to_array_type(root_object_type).element_type(), ns) ==
586-
pointer_offset_bits(dereference_type, ns))
605+
pointer_offset_bits(dereference_type, ns) &&
606+
offset.is_constant())
587607
{
588608
// We have an array with a subtype that matches
589609
// the dereferencing type.
590-
exprt offset;
591-
592-
// this should work as the object is essentially the root object
593-
if(o.offset().is_constant())
594-
offset=o.offset();
595-
else
596-
offset=pointer_offset(pointer_expr);
597610

598611
// are we doing a byte?
599612
auto element_size =
600613
pointer_offset_size(to_array_type(root_object_type).element_type(), ns);
614+
CHECK_RETURN(element_size.has_value());
615+
CHECK_RETURN(*element_size > 0);
601616

602-
if(!element_size.has_value() || *element_size == 0)
603-
{
604-
throw "unknown or invalid type size of:\n" +
605-
to_array_type(root_object_type).element_type().pretty();
606-
}
607-
608-
exprt element_size_expr = from_integer(*element_size, offset.type());
609-
610-
exprt adjusted_offset =
611-
simplify_expr(div_exprt{offset, element_size_expr}, ns);
617+
const auto offset_int =
618+
numeric_cast_v<mp_integer>(to_constant_expr(offset));
612619

613-
index_exprt index_expr{root_object, adjusted_offset};
614-
result.value =
615-
typecast_exprt::conditional_cast(index_expr, dereference_type);
616-
result.pointer = typecast_exprt::conditional_cast(
617-
address_of_exprt{index_expr}, pointer_type);
618-
}
619-
else
620-
{
621-
// try to build a member/index expression - do not use byte_extract
622-
auto subexpr = get_subexpression_at_offset(
623-
root_object_subexpression, o.offset(), dereference_type, ns);
624-
if(subexpr.has_value())
625-
simplify(subexpr.value(), ns);
626-
if(
627-
subexpr.has_value() &&
628-
subexpr.value().id() != ID_byte_extract_little_endian &&
629-
subexpr.value().id() != ID_byte_extract_big_endian)
620+
if(offset_int % *element_size == 0)
630621
{
631-
// Successfully found a member, array index, or combination thereof
632-
// that matches the desired type and offset:
633-
result.value = subexpr.value();
622+
index_exprt index_expr{
623+
root_object,
624+
from_integer(
625+
offset_int / *element_size,
626+
to_array_type(root_object_type).index_type())};
627+
result.value =
628+
typecast_exprt::conditional_cast(index_expr, dereference_type);
634629
result.pointer = typecast_exprt::conditional_cast(
635-
address_of_exprt{skip_typecast(subexpr.value())}, pointer_type);
630+
address_of_exprt{index_expr}, pointer_type);
631+
636632
return result;
637633
}
634+
}
638635

639-
// we extract something from the root object
640-
result.value=o.root_object();
636+
// try to build a member/index expression - do not use byte_extract
637+
auto subexpr = get_subexpression_at_offset(
638+
root_object, o.offset(), dereference_type, ns);
639+
if(subexpr.has_value())
640+
simplify(subexpr.value(), ns);
641+
if(
642+
subexpr.has_value() &&
643+
subexpr.value().id() != ID_byte_extract_little_endian &&
644+
subexpr.value().id() != ID_byte_extract_big_endian)
645+
{
646+
// Successfully found a member, array index, or combination thereof
647+
// that matches the desired type and offset:
648+
result.value = subexpr.value();
641649
result.pointer = typecast_exprt::conditional_cast(
642-
address_of_exprt{skip_typecast(o.root_object())}, pointer_type);
650+
address_of_exprt{skip_typecast(subexpr.value())}, pointer_type);
651+
return result;
652+
}
643653

644-
// this is relative to the root object
645-
exprt offset;
646-
if(o.offset().id()==ID_unknown)
647-
offset=pointer_offset(pointer_expr);
648-
else
649-
offset=o.offset();
654+
// we extract something from the root object
655+
result.value = o.root_object();
656+
result.pointer = typecast_exprt::conditional_cast(
657+
address_of_exprt{skip_typecast(o.root_object())}, pointer_type);
650658

651-
if(memory_model(result.value, dereference_type, offset, ns))
652-
{
653-
// ok, done
654-
}
655-
else
656-
{
657-
return valuet(); // give up, no way that this is ok
658-
}
659-
}
660-
}
659+
if(!memory_model(result.value, dereference_type, offset, ns))
660+
return {}; // give up, no way that this is ok
661661

662-
return result;
662+
return result;
663+
}
663664
}
664665

665666
static bool is_a_bv_type(const typet &type)

src/solvers/flattening/bv_pointers.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ optionalt<bvt> bv_pointerst::convert_address_of_rec(const exprt &expr)
264264
UNREACHABLE;
265265

266266
// get size
267-
auto size = pointer_offset_size(array_type.element_type(), ns);
268-
CHECK_RETURN(size.has_value() && *size >= 0);
267+
auto size = size_of_expr(array_type.element_type(), ns);
268+
CHECK_RETURN(size.has_value());
269269

270270
bv = offset_arithmetic(type, bv, *size, index);
271271
CHECK_RETURN(bv.size()==bits);
@@ -732,7 +732,7 @@ bvt bv_pointerst::convert_bitvector(const exprt &expr)
732732
to_typecast_expr(expr).op().type().id() == ID_pointer)
733733
{
734734
// pointer to int
735-
bvt op0 = convert_pointer_type(to_typecast_expr(expr).op());
735+
bvt op0 = convert_bv(to_typecast_expr(expr).op());
736736

737737
// squeeze it in!
738738
std::size_t width=boolbv_width(expr.type());
@@ -844,6 +844,28 @@ bvt bv_pointerst::offset_arithmetic(
844844
return offset_arithmetic(type, bv, factor, bv_index);
845845
}
846846

847+
bvt bv_pointerst::offset_arithmetic(
848+
const pointer_typet &type,
849+
const bvt &bv,
850+
const exprt &factor,
851+
const exprt &index)
852+
{
853+
bvt bv_factor = convert_bv(factor);
854+
bvt bv_index =
855+
convert_bv(typecast_exprt::conditional_cast(index, factor.type()));
856+
857+
bv_utilst::representationt rep = factor.type().id() == ID_signedbv
858+
? bv_utilst::representationt::SIGNED
859+
: bv_utilst::representationt::UNSIGNED;
860+
861+
bv_index = bv_utils.multiplier(bv_index, bv_factor, rep);
862+
863+
const std::size_t offset_bits = get_offset_width(type);
864+
bv_index = bv_utils.extension(bv_index, offset_bits, rep);
865+
866+
return offset_arithmetic(type, bv, 1, bv_index);
867+
}
868+
847869
bvt bv_pointerst::offset_arithmetic(
848870
const pointer_typet &type,
849871
const bvt &bv,

src/solvers/flattening/bv_pointers.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ class bv_pointerst:public boolbvt
6666
const mp_integer &factor,
6767
const exprt &index);
6868
NODISCARD
69+
bvt offset_arithmetic(
70+
const pointer_typet &type,
71+
const bvt &bv,
72+
const exprt &factor,
73+
const exprt &index);
74+
NODISCARD
6975
bvt offset_arithmetic(
7076
const pointer_typet &,
7177
const bvt &,

0 commit comments

Comments
 (0)