https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128302
Bug ID: 128302
Summary: clear_padding_union and categorize_ctor_elements_1
ignore union bit-fields, leaving padding bits
uninitialized
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: 220245569 at seu dot edu.cn
CC: 220255623 at seu dot edu.cn, jianhao.xu at seu dot edu.cn
Target Milestone: ---
Target: *-*-*
Summary
-------
For unions containing bit-field members (e.g. `union U { unsigned int flags :
27; }`),
both `__builtin_clear_padding` and `-ftrivial-auto-var-init=zero` fail to zero
the unused padding bits (bits 27..31):
1. `clear_padding_union` (`gcc/gimple-fold.cc:4620-4643`) loops over union
`FIELD_DECL`s and passes `TREE_TYPE (field)` (`unsigned int`, 4 bytes) to
`clear_padding_type` without checking `DECL_BIT_FIELD (field)`. It treats
all
32 bits as active value bits and folds `__builtin_clear_padding(&u)` to a
complete no-op (`ret`).
2. `categorize_ctor_elements_1` (`gcc/expr.cc:7266-7282`) checks whether a
union
initializer covers the entire union by comparing `TYPE_SIZE (elt)` (32 bits)
instead of `DECL_SIZE (field)` (27 bits) against the union size. It marks
`union U u = {.flags = 1}` as completely initialized (`p_complete = -1`),
suppressing prologue zeroing under `-ftrivial-auto-var-init=zero` and
emitting a read-modify-write (`andl $-134217728, %eax`) that preserves the
5 uninitialized stack bits!
Reproducer
----------
$ cat trigger.c
union pkt_hdr {
unsigned int flags : 27;
};
void sink(const void *);
void test_auto_zero(void) {
union pkt_hdr u = {.flags = 1};
sink(&u);
}
void test_clear_padding(union pkt_hdr *p) {
__builtin_clear_padding(p);
}
Compile flag: gcc -O2 -std=c23 -ftrivial-auto-var-init=zero -S trigger.c
$ cat trigger.s
test_auto_zero:
subq $24, %rsp
movl 12(%rsp), %eax # reads uninitialized stack word!
leaq 12(%rsp), %rdi
andl $-134217728, %eax # preserves upper 5 uninitialized
padding bits!
orl $1, %eax
movl %eax, 12(%rsp)
call sink
addq $24, %rsp
ret
test_clear_padding:
ret # folded to a complete no-op!
Suggested Fix
-------------
1. Check `DECL_BIT_FIELD (field)` in `clear_padding_union`
(`gcc/gimple-fold.cc:4620-4643`)
and mark only `DECL_SIZE (field)` bits as used.
2. Use `DECL_SIZE (field)` rather than `TYPE_SIZE (elt)` when testing union
field
coverage in `categorize_ctor_elements_1` (`gcc/expr.cc:7266-7282`).