Skip to content

Commit d3612cc

Browse files
authored
Merge pull request #2161 from tautschnig/empty-struct
Handle empty structs in the back-end (and a number of induced fixes)
2 parents fa0d4f6 + d4296f1 commit d3612cc

File tree

7 files changed

+71
-177
lines changed

7 files changed

+71
-177
lines changed

regression/cbmc/Empty_struct2/main.c

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <assert.h>
2+
3+
struct empty
4+
{
5+
};
6+
7+
#pragma pack(1)
8+
struct S
9+
{
10+
char x;
11+
struct empty e;
12+
char y;
13+
};
14+
#pragma pack()
15+
16+
int main()
17+
{
18+
struct S s;
19+
assert(sizeof(struct S) == 2);
20+
21+
struct empty *p = &s.e;
22+
23+
assert(p == (char *)&s + 1);
24+
25+
return 0;
26+
}
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/pointer-analysis/value_set_dereference.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Author: Daniel Kroening, [email protected]
2929
#include <util/options.h>
3030
#include <util/pointer_offset_size.h>
3131
#include <util/pointer_predicates.h>
32+
#include <util/simplify_expr.h>
3233
#include <util/ssa_expr.h>
3334

3435
// global data, horrible
@@ -471,6 +472,8 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
471472
// try to build a member/index expression - do not use byte_extract
472473
exprt subexpr = get_subexpression_at_offset(
473474
root_object_subexpression, o.offset(), dereference_type, ns);
475+
if(subexpr.is_not_nil())
476+
simplify(subexpr, ns);
474477
if(subexpr.is_not_nil() && subexpr.id() != byte_extract_id())
475478
{
476479
// Successfully found a member, array index, or combination thereof

src/solvers/flattening/pointer_logic.cpp

+26-66
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include "pointer_logic.h"
1313

1414
#include <util/arith_tools.h>
15+
#include <util/byte_operators.h>
1516
#include <util/c_types.h>
1617
#include <util/invariant.h>
1718
#include <util/pointer_offset_size.h>
@@ -98,76 +99,35 @@ exprt pointer_logict::pointer_expr(
9899

99100
const exprt &object_expr=objects[pointer.object];
100101

101-
exprt deep_object=object_rec(pointer.offset, type, object_expr);
102-
103-
return address_of_exprt(deep_object, type);
104-
}
105-
106-
exprt pointer_logict::object_rec(
107-
const mp_integer &offset,
108-
const typet &pointer_type,
109-
const exprt &src) const
110-
{
111-
if(src.type().id()==ID_array)
102+
typet subtype = type.subtype();
103+
// This is a gcc extension.
104+
// https://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Pointer-Arith.html
105+
if(subtype.id() == ID_empty)
106+
subtype = char_type();
107+
const exprt deep_object =
108+
get_subexpression_at_offset(object_expr, pointer.offset, subtype, ns);
109+
CHECK_RETURN(deep_object.is_not_nil());
110+
if(deep_object.id() != byte_extract_id())
111+
return address_of_exprt(deep_object, type);
112+
113+
const byte_extract_exprt &be = to_byte_extract_expr(deep_object);
114+
if(be.offset().is_zero())
115+
return address_of_exprt(be.op(), type);
116+
117+
const auto subtype_bytes = pointer_offset_size(subtype, ns);
118+
CHECK_RETURN(subtype_bytes.has_value() && *subtype_bytes > 0);
119+
if(*subtype_bytes > pointer.offset)
112120
{
113-
auto size = pointer_offset_size(src.type().subtype(), ns);
114-
115-
if(!size.has_value() || *size == 0)
116-
return src;
117-
118-
mp_integer index = offset / (*size);
119-
mp_integer rest = offset % (*size);
120-
if(rest<0)
121-
rest=-rest;
122-
123-
index_exprt tmp(src.type().subtype());
124-
tmp.index()=from_integer(index, typet(ID_integer));
125-
tmp.array()=src;
126-
127-
return object_rec(rest, pointer_type, tmp);
121+
return plus_exprt(
122+
address_of_exprt(be.op(), pointer_type(char_type())),
123+
from_integer(pointer.offset, index_type()));
128124
}
129-
else if(src.type().id()==ID_struct)
125+
else
130126
{
131-
const struct_typet::componentst &components=
132-
to_struct_type(src.type()).components();
133-
134-
if(offset<0)
135-
return src;
136-
137-
mp_integer current_offset=0;
138-
139-
for(const auto &c : components)
140-
{
141-
INVARIANT(
142-
offset >= current_offset,
143-
"when the object has not been found yet its offset must not be smaller"
144-
"than the offset of the current struct component");
145-
146-
const typet &subtype=c.type();
147-
148-
const auto sub_size = pointer_offset_size(subtype, ns);
149-
CHECK_RETURN(sub_size.has_value() && *sub_size != 0);
150-
151-
mp_integer new_offset = current_offset + *sub_size;
152-
153-
if(new_offset>offset)
154-
{
155-
// found it
156-
member_exprt tmp(src, c);
157-
158-
return object_rec(
159-
offset-current_offset, pointer_type, tmp);
160-
}
161-
162-
current_offset=new_offset;
163-
}
164-
165-
return src;
127+
return plus_exprt(
128+
address_of_exprt(be.op(), pointer_type(char_type())),
129+
from_integer(pointer.offset / *subtype_bytes, index_type()));
166130
}
167-
else if(src.type().id()==ID_union)
168-
return src;
169-
170-
return src;
171131
}
172132

173133
pointer_logict::pointer_logict(const namespacet &_ns):ns(_ns)

src/solvers/flattening/pointer_logic.h

-5
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@ class pointer_logict
7878
exprt pointer_expr(
7979
const mp_integer &offset,
8080
const exprt &object) const;
81-
82-
exprt object_rec(
83-
const mp_integer &offset,
84-
const typet &pointer_type,
85-
const exprt &src) const;
8681
};
8782

8883
#endif // CPROVER_SOLVERS_FLATTENING_POINTER_LOGIC_H

src/util/pointer_offset_size.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -722,12 +722,11 @@ exprt get_subexpression_at_offset(
722722
}
723723
}
724724

725-
const byte_extract_exprt be(
725+
return byte_extract_exprt(
726726
byte_extract_id(),
727727
expr,
728728
from_integer(offset_bytes, index_type()),
729729
target_type_raw);
730-
return simplify_expr(be, ns);
731730
}
732731

733732
exprt get_subexpression_at_offset(

src/util/simplify_expr.cpp

+7-104
Original file line numberDiff line numberDiff line change
@@ -1781,112 +1781,15 @@ bool simplify_exprt::simplify_byte_extract(byte_extract_exprt &expr)
17811781
}
17821782
}
17831783

1784-
// rethink the remaining code to correctly handle big endian
1785-
if(expr.id()!=ID_byte_extract_little_endian)
1784+
// try to refine it down to extracting from a member or an index in an array
1785+
exprt subexpr =
1786+
get_subexpression_at_offset(expr.op(), offset, expr.type(), ns);
1787+
if(subexpr.is_nil() || subexpr == expr)
17861788
return true;
17871789

1788-
// get type of object
1789-
const typet &op_type=ns.follow(expr.op().type());
1790-
1791-
if(op_type.id()==ID_array)
1792-
{
1793-
exprt result=expr.op();
1794-
1795-
// try proper array or string constant
1796-
for(const typet *op_type_ptr=&op_type;
1797-
op_type_ptr->id()==ID_array;
1798-
op_type_ptr=&(ns.follow(*op_type_ptr).subtype()))
1799-
{
1800-
DATA_INVARIANT(*el_size > 0, "arrays must not have zero-sized objects");
1801-
DATA_INVARIANT(
1802-
(*el_size) % 8 == 0,
1803-
"array elements have a size in bits which is a multiple of bytes");
1804-
1805-
mp_integer el_bytes = (*el_size) / 8;
1806-
1807-
if(base_type_eq(expr.type(), op_type_ptr->subtype(), ns) ||
1808-
(expr.type().id()==ID_pointer &&
1809-
op_type_ptr->subtype().id()==ID_pointer))
1810-
{
1811-
if(offset%el_bytes==0)
1812-
{
1813-
offset/=el_bytes;
1814-
1815-
result=
1816-
index_exprt(
1817-
result,
1818-
from_integer(offset, expr.offset().type()));
1819-
result.make_typecast(expr.type());
1820-
1821-
if(!base_type_eq(expr.type(), op_type_ptr->subtype(), ns))
1822-
result.make_typecast(expr.type());
1823-
1824-
expr.swap(result);
1825-
simplify_rec(expr);
1826-
return false;
1827-
}
1828-
}
1829-
else
1830-
{
1831-
auto sub_size = pointer_offset_size(op_type_ptr->subtype(), ns);
1832-
1833-
if(sub_size.has_value() && *sub_size > 0)
1834-
{
1835-
mp_integer index = offset / (*sub_size);
1836-
offset %= (*sub_size);
1837-
1838-
result=
1839-
index_exprt(
1840-
result,
1841-
from_integer(index, expr.offset().type()));
1842-
}
1843-
}
1844-
}
1845-
}
1846-
else if(op_type.id()==ID_struct)
1847-
{
1848-
const struct_typet &struct_type=
1849-
to_struct_type(op_type);
1850-
const struct_typet::componentst &components=
1851-
struct_type.components();
1852-
1853-
mp_integer m_offset_bits=0;
1854-
for(const auto &component : components)
1855-
{
1856-
auto m_size = pointer_offset_bits(component.type(), ns);
1857-
if(!m_size.has_value() || *m_size <= 0)
1858-
break;
1859-
1860-
if(
1861-
offset * 8 == m_offset_bits && *el_size == *m_size &&
1862-
base_type_eq(expr.type(), component.type(), ns))
1863-
{
1864-
member_exprt member(expr.op(), component.get_name(), component.type());
1865-
simplify_member(member);
1866-
expr.swap(member);
1867-
1868-
return false;
1869-
}
1870-
else if(
1871-
offset * 8 >= m_offset_bits &&
1872-
offset * 8 + *el_size <= m_offset_bits + *m_size &&
1873-
m_offset_bits % 8 == 0)
1874-
{
1875-
expr.op()=
1876-
member_exprt(expr.op(), component.get_name(), component.type());
1877-
simplify_member(expr.op());
1878-
expr.offset()=
1879-
from_integer(offset-m_offset_bits/8, expr.offset().type());
1880-
simplify_rec(expr);
1881-
1882-
return false;
1883-
}
1884-
1885-
m_offset_bits += *m_size;
1886-
}
1887-
}
1888-
1889-
return true;
1790+
simplify_rec(subexpr);
1791+
expr.swap(subexpr);
1792+
return false;
18901793
}
18911794

18921795
bool simplify_exprt::simplify_byte_update(byte_update_exprt &expr)

0 commit comments

Comments
 (0)