@@ -12,6 +12,8 @@ Author: Daniel Kroening, kroening@kroening.com
1212#include " pointer_offset_size.h"
1313
1414#include " arith_tools.h"
15+ #include " base_type.h"
16+ #include " byte_operators.h"
1517#include " c_types.h"
1618#include " invariant.h"
1719#include " namespace.h"
@@ -632,64 +634,87 @@ exprt build_sizeof_expr(
632634
633635exprt get_subexpression_at_offset (
634636 const exprt &expr,
635- mp_integer offset,
637+ const mp_integer & offset,
636638 const typet &target_type_raw,
639+ const irep_idt &byte_extract_op,
637640 const namespacet &ns)
638641{
639- exprt result = expr;
640- const typet &source_type=ns.follow (result.type ());
641- const typet &target_type=ns.follow (target_type_raw);
642+ if (offset == 0 && base_type_eq (expr.type (), target_type_raw, ns))
643+ {
644+ exprt result = expr;
645+
646+ if (expr.type () != target_type_raw)
647+ result.type () = target_type_raw;
642648
643- if (offset==0 && source_type==target_type)
644649 return result;
650+ }
651+
652+ const typet &source_type = ns.follow (expr.type ());
653+ const auto target_size = pointer_offset_bits (target_type_raw, ns);
654+ if (!target_size.has_value ())
655+ return nil_exprt ();
645656
646657 if (source_type.id ()==ID_struct)
647658 {
648- const auto &st=to_struct_type (source_type);
649- const struct_typet::componentst &components=st.components ();
650- member_offset_iterator offsets (st, ns);
651- while (offsets->first <components.size () &&
652- offsets->second !=-1 &&
653- offsets->second <=offset)
659+ const struct_typet &struct_type = to_struct_type (source_type);
660+
661+ mp_integer m_offset_bits = 0 ;
662+ for (const auto &component : struct_type.components ())
654663 {
655- auto nextit=offsets;
656- ++nextit;
657- if ((offsets->first +1 )==components.size () || offset<nextit->second )
664+ const auto m_size = pointer_offset_bits (component.type (), ns);
665+ if (!m_size.has_value ())
666+ return nil_exprt ();
667+
668+ if (
669+ offset * 8 >= m_offset_bits && m_offset_bits % 8 == 0 &&
670+ offset * 8 + *target_size <= m_offset_bits + *m_size)
658671 {
659- // This field might be, or might contain, the answer.
660- result=
661- member_exprt (
662- result,
663- components[offsets->first ].get_name (),
664- components[offsets->first ].type ());
665- return
666- get_subexpression_at_offset (
667- result, offset-offsets->second , target_type, ns);
672+ const member_exprt member (expr, component.get_name (), component.type ());
673+ return get_subexpression_at_offset (
674+ member,
675+ offset - m_offset_bits / 8 ,
676+ target_type_raw,
677+ byte_extract_op,
678+ ns);
668679 }
669- ++offsets;
680+
681+ m_offset_bits += *m_size;
670682 }
671- return nil_exprt ();
672683 }
673684 else if (source_type.id ()==ID_array)
674685 {
675- // A cell of the array might be, or contain, the subexpression
676- // we're looking for.
677- const auto &at=to_array_type (source_type);
678-
679- auto elem_size = pointer_offset_size (at.subtype (), ns);
680-
681- if (!elem_size.has_value ())
682- return nil_exprt ();
686+ const array_typet &array_type = to_array_type (source_type);
683687
684- mp_integer cellidx = offset / (*elem_size );
688+ const auto elem_size = pointer_offset_bits (array_type. subtype (), ns );
685689
686- if (cellidx < 0 || !cellidx.is_long ())
690+ // no arrays of non-byte, zero-, or unknown-sized objects
691+ if (!elem_size.has_value () || *elem_size == 0 || *elem_size % 8 != 0 )
687692 return nil_exprt ();
688693
689- offset = offset % (*elem_size);
694+ if (*target_size <= *elem_size)
695+ return get_subexpression_at_offset (
696+ index_exprt (
697+ expr, from_integer (offset / (*elem_size / 8 ), index_type ())),
698+ offset % (*elem_size / 8 ),
699+ target_type_raw,
700+ byte_extract_op,
701+ ns);
702+ }
690703
691- result=index_exprt (result, from_integer (cellidx, unsignedbv_typet (64 )));
692- return get_subexpression_at_offset (result, offset, target_type, ns);
704+ const auto source_size = pointer_offset_bits (source_type, ns);
705+ if (
706+ offset == 0 && source_size.has_value () && *source_size == *target_size &&
707+ source_type.id () == ID_pointer && target_type_raw.id () == ID_pointer)
708+ {
709+ return typecast_exprt (expr, target_type_raw);
710+ }
711+ else if (!byte_extract_op.empty ())
712+ {
713+ return byte_extract_exprt (
714+ byte_extract_op,
715+ expr,
716+ from_integer (offset, index_type ()),
717+ target_type_raw);
693718 }
694719 else
695720 return nil_exprt ();
@@ -699,12 +724,14 @@ exprt get_subexpression_at_offset(
699724 const exprt &expr,
700725 const exprt &offset,
701726 const typet &target_type,
727+ const irep_idt &byte_extract_op,
702728 const namespacet &ns)
703729{
704730 mp_integer offset_const;
705731
706732 if (to_integer (offset, offset_const))
707733 return nil_exprt ();
708734 else
709- return get_subexpression_at_offset (expr, offset_const, target_type, ns);
735+ return get_subexpression_at_offset (
736+ expr, offset_const, target_type, byte_extract_op, ns);
710737}
0 commit comments