https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128574
Bug ID: 128574
Summary: wrong code: TER moves a trapping FP operation past a
builtin library call (gap in the PR102129 fix)
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: lzy20000419 at outlook dot com
Target Milestone: ---
PR102129 was fixed in GCC 12 (r12-3248-g5e57bacf6f35, "avoid TER of possibly
trapping expressions"): out-of-SSA TER no longer substitutes a possibly
trapping expression into a use that sits after a call. The fix relies on the
per-statement call counter in find_replaceable_in_bb, and that counter is not
incremented for calls to builtin functions ("many will expand to inline
insns"). Library calls such as puts, printf, fputs, putchar, fwrite and
feclearexcept are builtins that stay real calls, so the PR102129 testcase with
g () replaced by puts ("...") is still miscompiled on trunk: with overflow
traps enabled, the program prints before it traps.
#define _GNU_SOURCE
#include <fenv.h>
#include <stdio.h>
volatile double vx = 1e308;
__attribute__((noinline)) double f (double x)
{
double r = x * 5.0; /* overflows: must trap before puts runs */
puts ("puts ran");
return r;
}
int main (void)
{
setvbuf (stdout, 0, _IONBF, 0);
feenableexcept (FE_OVERFLOW);
double r = f (vx);
printf ("%g\n", r);
return 0;
}
Observed (x86_64-linux-gnu, glibc):
gcc -O0 -> (nothing), SIGFPE (136), correct
gcc -O1 / -O2 / -O3 / -Os -> prints "puts ran", then SIGFPE, wrong
order
gcc -O2 -fno-tree-ter -> (nothing), SIGFPE, correct
gcc -O2 -fno-builtin-puts -> (nothing), SIGFPE, correct
clang -O2 -> (nothing), SIGFPE, correct
same file with a plain noinline g () instead of puts -> correct on 12.2+ (the
PR102129 fix works there)
Fails at -O1 and above with trunk (gcc 17.0.0 20261108, bcf14085d827), and the
puts form at -O2 also fails with 7.5, 11.2, 12.2 and 14.2. Godbolt:
https://godbolt.org/z/qTM8o4nsq
A flag-reading form also fails (regression: 7.5 OK, 8.5 to trunk wrong):
#include <fenv.h>
#include <stdio.h>
volatile double va = 1e300, vb = 1e300;
double g;
__attribute__((noinline)) int f(double a, double b) {
double t = a * b;
feclearexcept (FE_ALL_EXCEPT);
g = t;
return fetestexcept (FE_OVERFLOW) != 0;
}
int main (void) { int r = f (va, vb); printf ("%d %g\n", r, g); return r; }
feclearexcept form: -O0 prints "0 inf" (correct); -O1+ prints "1 inf" (wrong).
-fno-tree-ter and -fno-builtin-feclearexcept restore "0 inf". At -O1, GCC 7.5
is OK and 8.5 through trunk 20261108 are wrong. Godbolt:
https://godbolt.org/z/x111q3Wfv
Root cause (tree-ssa-ter.cc): find_replaceable_in_bb refuses replacement when
tab->call_cnt[ver] != cur_call_cnt and the definition gimple_could_trap_p (the
PR102129 / PR33593 check). But cur_call_cnt is only incremented for calls that
are not fndecl_built_in_p. For a builtin that is expanded as a normal library
call, the trap check never sees the call, so the multiply is substituted into
the return and expanded after call puts / after feclearexcept.
Possible fix (not tested): count every call that may not return or may observe
FP state for the trap check (e.g. keep a second counter that includes builtins,
or only exempt builtins known to expand inline / const without FP side
effects); alternatively mark the multiply not replaceable when any call
statement lies between definition and use.
Related: PR102129 (RESOLVED FIXED in 12; this report is the case its fix misses
— See Also). PR33593 (same check, -fnon-call-exceptions). PR29186 (NEW, FP flag
reading in general; the feclearexcept form is a concrete TER instance — See
Also). PR128315 is a different feclearexcept/FE_INVALID issue with sin/cos
under -frounding-math, not this TER gap. No matching open bug for "TER moves
trap past builtin library call" in quicksearch on 2026-11-09.
Regression status: the puts form already fails with 7.5, so it is not a recent
regression; the feclearexcept form is a regression since 8 (7.5 OK).
Disclaimer: This test case was generated by a fuzzer, and the report was
written with LLM assistance.