Skip to content

Commit 33841c8

Browse files
committed
Generalise get_subexpression_at_offset to extract parts of members
This fixes bugs in the previous implementation and enables re-use in the simplifier and other places.
1 parent 880d951 commit 33841c8

File tree

3 files changed

+74
-37
lines changed

3 files changed

+74
-37
lines changed

src/pointer-analysis/value_set_dereference.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,8 +531,9 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
531531
}
532532
else
533533
{
534+
// try to build a member/index expression - do not use byte_extract
534535
exprt subexpr = get_subexpression_at_offset(
535-
root_object_subexpression, o.offset(), dereference_type, ns);
536+
root_object_subexpression, o.offset(), dereference_type, "", ns);
536537
if(subexpr.is_not_nil())
537538
{
538539
// Successfully found a member, array index, or combination thereof

src/util/pointer_offset_size.cpp

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Author: Daniel Kroening, [email protected]
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"
@@ -623,58 +625,87 @@ exprt build_sizeof_expr(
623625

624626
exprt get_subexpression_at_offset(
625627
const exprt &expr,
626-
mp_integer offset,
628+
const mp_integer &offset,
627629
const typet &target_type_raw,
630+
const irep_idt &byte_extract_op,
628631
const namespacet &ns)
629632
{
630-
exprt result = expr;
631-
const typet &source_type=ns.follow(result.type());
632-
const typet &target_type=ns.follow(target_type_raw);
633+
if(offset == 0 && base_type_eq(expr.type(), target_type_raw, ns))
634+
{
635+
exprt result = expr;
636+
637+
if(expr.type() != target_type_raw)
638+
result.type() = target_type_raw;
633639

634-
if(offset==0 && source_type==target_type)
635640
return result;
641+
}
642+
643+
const typet &source_type=ns.follow(expr.type());
644+
const mp_integer target_size = pointer_offset_bits(target_type_raw, ns);
645+
if(target_size < 0)
646+
return nil_exprt();
636647

637648
if(source_type.id()==ID_struct)
638649
{
639-
const auto &st=to_struct_type(source_type);
640-
const struct_typet::componentst &components=st.components();
641-
member_offset_iterator offsets(st, ns);
642-
while(offsets->first<components.size() &&
643-
offsets->second!=-1 &&
644-
offsets->second<=offset)
650+
const struct_typet &struct_type = to_struct_type(source_type);
651+
652+
mp_integer m_offset_bits = 0;
653+
for(const auto &component : struct_type.components())
645654
{
646-
auto nextit=offsets;
647-
++nextit;
648-
if((offsets->first+1)==components.size() || offset<nextit->second)
655+
mp_integer m_size = pointer_offset_bits(component.type(), ns);
656+
if(m_size < 0)
657+
return nil_exprt();
658+
659+
if(
660+
offset * 8 >= m_offset_bits && m_offset_bits % 8 == 0 &&
661+
offset * 8 + target_size <= m_offset_bits + m_size)
649662
{
650-
// This field might be, or might contain, the answer.
651-
result=
652-
member_exprt(
653-
result,
654-
components[offsets->first].get_name(),
655-
components[offsets->first].type());
663+
const member_exprt member(expr, component.get_name(), component.type());
656664
return
657665
get_subexpression_at_offset(
658-
result, offset-offsets->second, target_type, ns);
666+
member,
667+
offset - m_offset_bits / 8,
668+
target_type_raw,
669+
byte_extract_op,
670+
ns);
659671
}
660-
++offsets;
672+
673+
m_offset_bits += m_size;
661674
}
662-
return nil_exprt();
663675
}
664676
else if(source_type.id()==ID_array)
665677
{
666-
// A cell of the array might be, or contain, the subexpression
667-
// we're looking for.
668-
const auto &at=to_array_type(source_type);
669-
mp_integer elem_size=pointer_offset_size(at.subtype(), ns);
670-
if(elem_size==-1)
671-
return nil_exprt();
672-
mp_integer cellidx=offset/elem_size;
673-
if(cellidx < 0 || !cellidx.is_long())
678+
const array_typet &array_type = to_array_type(source_type);
679+
680+
// no arrays of non-byte, zero-, or unknown-sized objects
681+
mp_integer sub_size = pointer_offset_bits(array_type.subtype(), ns);
682+
if(sub_size <= 0 || sub_size % 8 != 0)
674683
return nil_exprt();
675-
offset=offset%elem_size;
676-
result=index_exprt(result, from_integer(cellidx, unsignedbv_typet(64)));
677-
return get_subexpression_at_offset(result, offset, target_type, ns);
684+
685+
if(target_size <= sub_size)
686+
return
687+
get_subexpression_at_offset(
688+
index_exprt(
689+
expr, from_integer(offset / (sub_size / 8), index_type())),
690+
offset % (sub_size / 8),
691+
target_type_raw,
692+
byte_extract_op,
693+
ns);
694+
}
695+
696+
if(offset == 0 && pointer_offset_bits(source_type, ns) == target_size &&
697+
source_type.id() == ID_pointer && target_type_raw.id() == ID_pointer)
698+
{
699+
return typecast_exprt(expr, target_type_raw);
700+
}
701+
else if(!byte_extract_op.empty())
702+
{
703+
return
704+
byte_extract_exprt(
705+
byte_extract_op,
706+
expr,
707+
from_integer(offset, index_type()),
708+
target_type_raw);
678709
}
679710
else
680711
return nil_exprt();
@@ -684,11 +715,14 @@ exprt get_subexpression_at_offset(
684715
const exprt &expr,
685716
const exprt &offset,
686717
const typet &target_type,
718+
const irep_idt &byte_extract_op,
687719
const namespacet &ns)
688720
{
689721
mp_integer offset_const;
690722
if(to_integer(offset, offset_const))
691723
return nil_exprt();
692724

693-
return get_subexpression_at_offset(expr, offset_const, target_type, ns);
725+
return
726+
get_subexpression_at_offset(
727+
expr, offset_const, target_type, byte_extract_op, ns);
694728
}

src/util/pointer_offset_size.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,16 @@ exprt build_sizeof_expr(
8383

8484
exprt get_subexpression_at_offset(
8585
const exprt &expr,
86-
mp_integer offset,
86+
const mp_integer &offset,
8787
const typet &target_type,
88+
const irep_idt &byte_extract_op,
8889
const namespacet &ns);
8990

9091
exprt get_subexpression_at_offset(
9192
const exprt &expr,
9293
const exprt &offset,
9394
const typet &target_type,
95+
const irep_idt &byte_extract_op,
9496
const namespacet &ns);
9597

9698
#endif // CPROVER_UTIL_POINTER_OFFSET_SIZE_H

0 commit comments

Comments
 (0)