https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128065
Bug ID: 128065
Summary: strub attribute silently ignored for functions defined
in a precompiled header
Product: gcc
Version: 16.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: pch
Assignee: unassigned at gcc dot gnu.org
Reporter: yqtian668 at gmail dot com
Target Milestone: ---
Host: x86_64-linux-gnu
Target: x86_64-linux-gnu
Created attachment 65913
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65913&action=edit
Reproducer and complete GCC 16.2 / trunk sessions
Functions with a strub attribute that are defined in a header get stack
scrubbing when the header is included textually, but not when the same
header comes from a precompiled header built with the same options: the
__strub_* calls disappear, without a diagnostic, and the strub run-time
tests fail.
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-linux-gnu/16.2.0/lto-wrapper
Target: x86_64-linux-gnu
Configured with: /usr/src/gcc/configure --build=x86_64-linux-gnu
--disable-multilib --enable-languages=c,c++,fortran,go
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 16.2.0 (GCC)
1. Reduced case (GCC 16.2.0; complete output):
=== Part 1: reduced case
$ cat h.h
int __attribute__ ((strub ("at-calls")))
secret (int x)
{
volatile int buf[16];
buf[0] = x;
return buf[0] + 1;
}
$ cat t.c
#include "h.h"
int main (void) { return secret (1) != 2; }
$ gcc -O2 -c t.c -o textual.o
[exit status: 0]
$ nm textual.o
U __strub_leave
0000000000000000 T main
0000000000000000 T secret
$ gcc -O2 -x c-header h.h -o h.h.gch
[exit status: 0]
$ gcc -O2 -Winvalid-pch -H -c t.c -o pch.o
! h.h.gch
t.c
[exit status: 0]
$ nm pch.o
0000000000000000 T main
0000000000000000 T secret
2. The run-time tests c-c++-common/torture/strub-run1.c .. strub-run4.c,
compiled as the testsuite does (the .c file with its dg-options) and with
the same file used as a precompiled header under the same options. For
example strub-run1.c at -O2 (complete output):
--- strub-run1.c, dg-options: -fstrub=strict, -O2
$ gcc -O2 -fstrub=strict strub-run1.c -o strub-run1-textual
[exit status: 0]
$ ./strub-run1-textual
[exit status: 0]
$ gcc -O2 -fstrub=strict -x c-header strub-run1.h -o strub-run1.h.gch
[exit status: 0]
$ gcc -O2 -fstrub=strict -Winvalid-pch -H use-strub-run1.c -o strub-run1-pch
! strub-run1.h.gch
use-strub-run1.c
[exit status: 0]
$ ./strub-run1-pch
[exit status: 134]
Aborted (core dumped)
All eight builds (exit status of the program; 134 = abort):
| test | dg-options | opt | textual | via PCH |
|---|---|---|---|---|
| strub-run1.c | -fstrub=strict | -O0 | 0 | 134 |
| strub-run1.c | -fstrub=strict | -O2 | 0 | 134 |
| strub-run2.c | -fstrub=strict | -O0 | 0 | 134 |
| strub-run2.c | -fstrub=strict | -O2 | 0 | 134 |
| strub-run3.c | -fstrub=strict | -O0 | 0 | 134 |
| strub-run3.c | -fstrub=strict | -O2 | 0 | 134 |
| strub-run4.c | -fstrub=all | -O0 | 0 | 0 |
| strub-run4.c | -fstrub=all | -O2 | 0 | 0 |
strub-run1..3 use strub attributes under -fstrub=strict and fail through
the PCH at -O0 and -O2; strub-run4 (-fstrub=all, scrubbing requested by
the option) passes. These results suggest that attribute-based strub handling
is not
preserved through the PCH, whereas -fstrub=all remains effective in
these tests. The underlying mechanism has not been identified. Same results
with trunk (17.0.0 20260905, --enable-checking=yes);
complete outputs attached.
Since strub is a security hardening feature, losing it silently is worse
than an error: a project that precompiles a header with strub functions
believes the stack is scrubbed.