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`).

Reply via email to