Skip to content

Commit 1668588

Browse files
authored
Merge pull request #7597 from tautschnig/bugfixes/7596-attributes
C front-end: fix the interaction between packing and alignment
2 parents f892923 + 488da95 commit 1668588

File tree

6 files changed

+103
-14
lines changed

6 files changed

+103
-14
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#define PADDING_SIZE (64 - sizeof(char) - sizeof(int))
2+
3+
typedef struct __attribute__((packed, aligned(64)))
4+
{
5+
char uchar;
6+
int uint;
7+
char padding[PADDING_SIZE];
8+
} a_t;
9+
10+
typedef struct __attribute__((packed, aligned(64)))
11+
{
12+
int uint;
13+
char uchar;
14+
char padding[PADDING_SIZE];
15+
} b_t;
16+
17+
typedef struct __attribute__((packed))
18+
{
19+
int uint;
20+
char uchar;
21+
struct
22+
{
23+
char a;
24+
int b;
25+
} not_packed __attribute__((aligned(8)));
26+
} c_t;
27+
28+
typedef struct __attribute__((packed, aligned(1)))
29+
{
30+
int uint;
31+
char uchar;
32+
struct
33+
{
34+
char a;
35+
int b;
36+
} not_packed __attribute__((aligned(8)));
37+
} d_t;
38+
39+
int main()
40+
{
41+
_Static_assert(sizeof(a_t) == sizeof(b_t), "");
42+
_Static_assert(sizeof(c_t) == 8 + 2 * sizeof(int), "");
43+
_Static_assert(sizeof(d_t) == 8 + 2 * sizeof(int), "");
44+
return 0;
45+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE gcc-only
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

regression/ansi-c/pragma_pack4/main.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
struct S1
2+
{
3+
char a;
4+
struct
5+
{
6+
short b;
7+
} c;
8+
};
9+
10+
#pragma pack(4)
11+
// note that the above is different from __attribute__((packed, aligned(4))) in
12+
// that it sets the _maximum_ alignment of members - it does not affect the
13+
// overall alignment of the struct
14+
15+
struct S2
16+
{
17+
char a;
18+
struct
19+
{
20+
short b;
21+
} c;
22+
};
23+
24+
int main()
25+
{
26+
_Static_assert(sizeof(struct S1) == sizeof(struct S2), "");
27+
}
Lines changed: 8 additions & 0 deletions
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+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

src/ansi-c/padding.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,10 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
330330
}
331331
}
332332

333-
// Is the struct packed, without any alignment specification?
334-
if(type.get_bool(ID_C_packed) &&
335-
type.find(ID_C_alignment).is_nil())
336-
return; // done
337-
338333
mp_integer offset=0;
339334
mp_integer max_alignment=0;
340335
std::size_t bit_field_bits=0;
336+
const bool struct_is_packed = type.get_bool(ID_C_packed);
341337

342338
for(struct_typet::componentst::iterator
343339
it=components.begin();
@@ -347,9 +343,6 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
347343
const typet it_type=it->type();
348344
mp_integer a=1;
349345

350-
const bool packed=it_type.get_bool(ID_C_packed) ||
351-
ns.follow(it_type).get_bool(ID_C_packed);
352-
353346
if(it_type.id()==ID_c_bit_field)
354347
{
355348
a = alignment(to_c_bit_field_type(it_type).underlying_type(), ns);
@@ -392,13 +385,19 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
392385
bit_field_bits == 0, "padding ensures offset at byte boundaries");
393386

394387
// check minimum alignment
395-
if(a<config.ansi_c.alignment && !packed)
388+
if(
389+
a < config.ansi_c.alignment && !it_type.get_bool(ID_C_packed) &&
390+
!ns.follow(it_type).get_bool(ID_C_packed))
391+
{
396392
a=config.ansi_c.alignment;
393+
}
397394

398395
if(max_alignment<a)
399396
max_alignment=a;
400397

401-
if(a!=1)
398+
if(
399+
a != 1 &&
400+
(!struct_is_packed || it_type.find(ID_C_alignment).is_not_nil()))
402401
{
403402
// we may need to align it
404403
const mp_integer displacement = offset % a;
@@ -433,7 +432,7 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
433432
}
434433
}
435434
// Is the struct packed, without any alignment specification?
436-
else if(type.get_bool(ID_C_packed))
435+
else if(struct_is_packed)
437436
return; // done
438437

439438
// There may be a need for 'end of struct' padding.

src/ansi-c/parser.y

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,12 +1741,14 @@ member_declaring_list:
17411741
type_specifier
17421742
member_declarator
17431743
{
1744-
if(!PARSER.pragma_pack.empty() &&
1744+
if(parser_stack($2).id() != ID_struct &&
1745+
parser_stack($2).id() != ID_union &&
1746+
!PARSER.pragma_pack.empty() &&
17451747
!PARSER.pragma_pack.back().is_zero())
17461748
{
17471749
// communicate #pragma pack(n) alignment constraints by
1748-
// by both setting packing AND alignment; see padding.cpp
1749-
// for more details
1750+
// by both setting packing AND alignment for individual struct/union
1751+
// members; see padding.cpp for more details
17501752
init($$);
17511753
set($$, ID_packed);
17521754
$2=merge($2, $$);

0 commit comments

Comments
 (0)