@@ -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"
@@ -676,64 +678,87 @@ exprt build_sizeof_expr(
676678
677679exprt get_subexpression_at_offset (
678680 const exprt &expr,
679- mp_integer offset,
681+ const mp_integer & offset,
680682 const typet &target_type_raw,
683+ const irep_idt &byte_extract_op,
681684 const namespacet &ns)
682685{
683- exprt result = expr;
684- const typet &source_type=ns.follow (result.type ());
685- const typet &target_type=ns.follow (target_type_raw);
686+ if (offset == 0 && base_type_eq (expr.type (), target_type_raw, ns))
687+ {
688+ exprt result = expr;
689+
690+ if (expr.type () != target_type_raw)
691+ result.type () = target_type_raw;
686692
687- if (offset==0 && source_type==target_type)
688693 return result;
694+ }
695+
696+ const typet &source_type = ns.follow (expr.type ());
697+ const auto target_size = pointer_offset_bits (target_type_raw, ns);
698+ if (!target_size.has_value ())
699+ return nil_exprt ();
689700
690701 if (source_type.id ()==ID_struct)
691702 {
692- const auto &st=to_struct_type (source_type);
693- const struct_typet::componentst &components=st.components ();
694- member_offset_iterator offsets (st, ns);
695- while (offsets->first <components.size () &&
696- offsets->second !=-1 &&
697- offsets->second <=offset)
703+ const struct_typet &struct_type = to_struct_type (source_type);
704+
705+ mp_integer m_offset_bits = 0 ;
706+ for (const auto &component : struct_type.components ())
698707 {
699- auto nextit=offsets;
700- ++nextit;
701- if ((offsets->first +1 )==components.size () || offset<nextit->second )
708+ const auto m_size = pointer_offset_bits (component.type (), ns);
709+ if (!m_size.has_value ())
710+ return nil_exprt ();
711+
712+ if (
713+ offset * 8 >= m_offset_bits && m_offset_bits % 8 == 0 &&
714+ offset * 8 + *target_size <= m_offset_bits + *m_size)
702715 {
703- // This field might be, or might contain, the answer.
704- result=
705- member_exprt (
706- result,
707- components[offsets->first ].get_name (),
708- components[offsets->first ].type ());
709- return
710- get_subexpression_at_offset (
711- result, offset-offsets->second , target_type, ns);
716+ const member_exprt member (expr, component.get_name (), component.type ());
717+ return get_subexpression_at_offset (
718+ member,
719+ offset - m_offset_bits / 8 ,
720+ target_type_raw,
721+ byte_extract_op,
722+ ns);
712723 }
713- ++offsets;
724+
725+ m_offset_bits += *m_size;
714726 }
715- return nil_exprt ();
716727 }
717728 else if (source_type.id ()==ID_array)
718729 {
719- // A cell of the array might be, or contain, the subexpression
720- // we're looking for.
721- const auto &at=to_array_type (source_type);
722-
723- auto elem_size = pointer_offset_size (at.subtype (), ns);
724-
725- if (!elem_size.has_value ())
726- return nil_exprt ();
730+ const array_typet &array_type = to_array_type (source_type);
727731
728- mp_integer cellidx = offset / (*elem_size );
732+ const auto elem_size = pointer_offset_bits (array_type. subtype (), ns );
729733
730- if (cellidx < 0 || !cellidx.is_long ())
734+ // no arrays of non-byte, zero-, or unknown-sized objects
735+ if (!elem_size.has_value () || *elem_size == 0 || *elem_size % 8 != 0 )
731736 return nil_exprt ();
732737
733- offset = offset % (*elem_size);
738+ if (*target_size <= *elem_size)
739+ return get_subexpression_at_offset (
740+ index_exprt (
741+ expr, from_integer (offset / (*elem_size / 8 ), index_type ())),
742+ offset % (*elem_size / 8 ),
743+ target_type_raw,
744+ byte_extract_op,
745+ ns);
746+ }
734747
735- result=index_exprt (result, from_integer (cellidx, unsignedbv_typet (64 )));
736- return get_subexpression_at_offset (result, offset, target_type, ns);
748+ const auto source_size = pointer_offset_bits (source_type, ns);
749+ if (
750+ offset == 0 && source_size.has_value () && *source_size == *target_size &&
751+ source_type.id () == ID_pointer && target_type_raw.id () == ID_pointer)
752+ {
753+ return typecast_exprt (expr, target_type_raw);
754+ }
755+ else if (!byte_extract_op.empty ())
756+ {
757+ return byte_extract_exprt (
758+ byte_extract_op,
759+ expr,
760+ from_integer (offset, index_type ()),
761+ target_type_raw);
737762 }
738763 else
739764 return nil_exprt ();
@@ -743,12 +768,14 @@ exprt get_subexpression_at_offset(
743768 const exprt &expr,
744769 const exprt &offset,
745770 const typet &target_type,
771+ const irep_idt &byte_extract_op,
746772 const namespacet &ns)
747773{
748774 mp_integer offset_const;
749775
750776 if (to_integer (offset, offset_const))
751777 return nil_exprt ();
752778 else
753- return get_subexpression_at_offset (expr, offset_const, target_type, ns);
779+ return get_subexpression_at_offset (
780+ expr, offset_const, target_type, byte_extract_op, ns);
754781}
0 commit comments