Skip to content

Commit d8e3aa0

Browse files
author
Daniel Kroening
authored
Merge pull request #283 from smowton/symex_deref_clean_struct_member
Symex: synthesise clean references to subfields and/or array indices when addressing subexpressions
2 parents 1bcc33c + 1117fac commit d8e3aa0

File tree

3 files changed

+136
-21
lines changed

3 files changed

+136
-21
lines changed

src/pointer-analysis/value_set_dereference.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
514514
const typet &object_type=ns.follow(object.type());
515515
const exprt &root_object=o.root_object();
516516
const typet &root_object_type=ns.follow(root_object.type());
517+
518+
exprt root_object_subexpression=root_object;
517519

518520
if(dereference_type_compare(object_type, dereference_type) &&
519521
o.offset().is_zero())
@@ -573,6 +575,13 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
573575
if(ns.follow(result.value.type())!=ns.follow(dereference_type))
574576
result.value.make_typecast(dereference_type);
575577
}
578+
else if(get_subexpression_at_offset(root_object_subexpression, o.offset(),
579+
dereference_type, ns))
580+
{
581+
// Successfully found a member, array index, or combination thereof
582+
// that matches the desired type and offset:
583+
result.value=root_object_subexpression;
584+
}
576585
else
577586
{
578587
// we extract something from the root object

src/util/pointer_offset_size.cpp

+101-21
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,39 @@ Author: Daniel Kroening, [email protected]
2121

2222
#include "pointer_offset_size.h"
2323

24+
member_offset_iterator::member_offset_iterator(const struct_typet& _type,
25+
const namespacet& _ns) :
26+
current({0,0}),
27+
type(_type),
28+
ns(_ns),
29+
bit_field_bits(0)
30+
{
31+
}
32+
33+
member_offset_iterator& member_offset_iterator::operator++()
34+
{
35+
if(current.second!=-1) // Already failed?
36+
{
37+
const auto& comp=type.components()[current.first];
38+
if(comp.type().id()==ID_c_bit_field)
39+
{
40+
// take the extra bytes needed
41+
std::size_t w=to_c_bit_field_type(comp.type()).get_width();
42+
for(; w>bit_field_bits; ++current.second, bit_field_bits+=8);
43+
bit_field_bits-=w;
44+
}
45+
else
46+
{
47+
const typet &subtype=comp.type();
48+
mp_integer sub_size=pointer_offset_size(subtype, ns);
49+
if(sub_size==-1) current.second=-1; // give up
50+
else current.second+=sub_size;
51+
}
52+
}
53+
++current.first;
54+
return *this;
55+
}
56+
2457
/*******************************************************************\
2558
2659
Function: member_offset
@@ -39,35 +72,18 @@ mp_integer member_offset(
3972
const namespacet &ns)
4073
{
4174
const struct_typet::componentst &components=type.components();
42-
43-
mp_integer result=0;
44-
std::size_t bit_field_bits=0;
75+
member_offset_iterator offsets(type,ns);
4576

4677
for(struct_typet::componentst::const_iterator
4778
it=components.begin();
48-
it!=components.end();
49-
it++)
79+
it!=components.end() && offsets->second!=-1;
80+
++it, ++offsets)
5081
{
5182
if(it->get_name()==member)
5283
break;
53-
54-
if(it->type().id()==ID_c_bit_field)
55-
{
56-
// take the extra bytes needed
57-
std::size_t w=to_c_bit_field_type(it->type()).get_width();
58-
for(; w>bit_field_bits; ++result, bit_field_bits+=8);
59-
bit_field_bits-=w;
60-
}
61-
else
62-
{
63-
const typet &subtype=it->type();
64-
mp_integer sub_size=pointer_offset_size(subtype, ns);
65-
if(sub_size==-1) return -1; // give up
66-
result+=sub_size;
67-
}
6884
}
6985

70-
return result;
86+
return offsets->second;
7187
}
7288

7389
/*******************************************************************\
@@ -616,3 +632,67 @@ exprt build_sizeof_expr(
616632

617633
return result;
618634
}
635+
636+
bool get_subexpression_at_offset(
637+
exprt& result,
638+
mp_integer offset,
639+
const typet& target_type_raw,
640+
const namespacet& ns)
641+
{
642+
const typet& source_type=ns.follow(result.type());
643+
const typet& target_type=ns.follow(target_type_raw);
644+
645+
if(offset==0 && source_type==target_type)
646+
return true;
647+
648+
if(source_type.id()==ID_struct)
649+
{
650+
const auto& st=to_struct_type(source_type);
651+
const struct_typet::componentst &components=st.components();
652+
member_offset_iterator offsets(st,ns);
653+
while(offsets->first<components.size() && offsets->second!=-1 && offsets->second<=offset)
654+
{
655+
auto nextit=offsets;
656+
++nextit;
657+
if((offsets->first+1)==components.size() || offset<nextit->second)
658+
{
659+
// This field might be, or might contain, the answer.
660+
result=member_exprt(result,
661+
components[offsets->first].get_name(),
662+
components[offsets->first].type());
663+
return get_subexpression_at_offset(result, offset - offsets->second, target_type, ns);
664+
}
665+
++offsets;
666+
}
667+
return false;
668+
}
669+
else if(source_type.id()==ID_array)
670+
{
671+
// A cell of the array might be, or contain, the subexpression we're looking for.
672+
const auto& at=to_array_type(source_type);
673+
mp_integer elem_size=pointer_offset_size(at.subtype(),ns);
674+
if(elem_size==-1)
675+
return false;
676+
mp_integer cellidx=offset / elem_size;
677+
if(cellidx < 0 || !cellidx.is_long())
678+
return false;
679+
offset=offset % elem_size;
680+
result=index_exprt(result,from_integer(cellidx,unsignedbv_typet(64)));
681+
return get_subexpression_at_offset(result,offset,target_type,ns);
682+
}
683+
else
684+
return false;
685+
686+
}
687+
688+
bool get_subexpression_at_offset(
689+
exprt& result,
690+
const exprt& offset,
691+
const typet& target_type,
692+
const namespacet& ns)
693+
{
694+
mp_integer offset_const;
695+
if(to_integer(offset,offset_const))
696+
return false;
697+
return get_subexpression_at_offset(result,offset_const,target_type,ns);
698+
}

src/util/pointer_offset_size.h

+26
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ class constant_exprt;
2121

2222
// these return -1 on failure
2323

24+
class member_offset_iterator {
25+
typedef std::pair<size_t,mp_integer> refst;
26+
refst current;
27+
const struct_typet &type;
28+
const namespacet &ns;
29+
size_t bit_field_bits;
30+
public:
31+
member_offset_iterator(const struct_typet& _type,
32+
const namespacet& _ns);
33+
member_offset_iterator& operator++();
34+
const refst& operator*() const { return current; }
35+
const refst* operator->() const { return &current; }
36+
};
37+
2438
mp_integer member_offset(
2539
const struct_typet &type,
2640
const irep_idt &member,
@@ -57,4 +71,16 @@ exprt build_sizeof_expr(
5771
const constant_exprt &expr,
5872
const namespacet &ns);
5973

74+
bool get_subexpression_at_offset(
75+
exprt& result,
76+
mp_integer offset,
77+
const typet& target_type,
78+
const namespacet& ns);
79+
80+
bool get_subexpression_at_offset(
81+
exprt& result,
82+
const exprt& offset,
83+
const typet& target_type,
84+
const namespacet& ns);
85+
6086
#endif

0 commit comments

Comments
 (0)