https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128275

            Bug ID: 128275
           Summary: [16/17 Regression] C++ jump-bypass .DEFERRED_INIT
                    clobbers DECL_HARD_REGISTER and omits =pattern padding
                    zeroing
           Product: gcc
           Version: 16.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          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
-------
GCC 16 added C++ `switch`/`goto` jump-bypass `.DEFERRED_INIT` instrumentation
in
`gcc/cp/decl.cc:3943-3986` (`decl_instrument_init_bypass_p` /
`build_deferred_init_call`), which introduces two wrong-code/hardening bugs:

1. Clobbering live physical registers (`DECL_HARD_REGISTER`):
   `decl_instrument_init_bypass_p` (`gcc/cp/decl.cc:3947`) checks `VAR_P
(decl)`
   and `!DECL_ARTIFICIAL (decl)`, but omits `!DECL_HARD_REGISTER (decl)`
   (unlike `gimplify_decl_expr` in `gcc/gimplify.cc:2138`). If a `switch` case
   declares a local explicit register variable `register long local_r12
asm("r12")`
   and execution takes a different `case`, the injected jump-bypass
`.DEFERRED_INIT`
   overwrites the physical register `r12` with `0` or `0xFEFE...` on the path
   that bypassed the declaration!
2. Missing padding zeroing under `-ftrivial-auto-var-init=pattern`:
   `build_deferred_init_call` (`gcc/cp/decl.cc:3963`) emits `IFN_DEFERRED_INIT`
   without emitting `BUILT_IN_CLEAR_PADDING` when `flag_auto_var_init ==
AUTO_VAR_INIT_PATTERN`
   (unlike `gimple_add_init_for_auto_var` in `gcc/gimplify.cc:2044-2055`),
leaving
   `0xFE` pattern bytes in struct padding when initialization is bypassed.

Reproducer
----------
$ cat trigger.cc
long test_hard_reg(int sel, long init_r12) {
    register long r asm("r12") = init_r12;
    switch (sel) {
    case 1:
        register long local_r12 asm("r12");
        local_r12 = 42;
        return local_r12;
    case 2:
        return r;
    }
    return r;
}

Compile flag: g++ -O2 -ftrivial-auto-var-init=pattern -S trigger.cc

$ cat trigger.s
_Z13test_hard_regil:
        movl    $42, %eax
        cmpl    $1, %edi
        je      .L1
        movabsq $-72340172838076674, %rax       # 0xfefefefefefefefe
        cmpl    $2, %edi
        cmovne  %rsi, %rax                      # when sel == 2, returns
0xfefefe... instead of init_r12!
.L1:
        ret

Suggested Fix
-------------
1. Add `!DECL_HARD_REGISTER (decl)` to `decl_instrument_init_bypass_p` in
`gcc/cp/decl.cc:3947`.
2. Emit `BUILT_IN_CLEAR_PADDING` after `IFN_DEFERRED_INIT` in
`gcc/cp/decl.cc:3963`
   when `flag_auto_var_init == AUTO_VAR_INIT_PATTERN`.

Reply via email to