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