https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127685
Bug ID: 127685
Summary: [17 Regression] Constant member-function pointer table
loads optimized to null
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: alexey.klimkin at intel dot com
Target Milestone: ---
AI-assisted diagnosis and reduction; compiler output and execution results
were checked against the reproducer and a local fix.
GCC 17 optimizes a populated static table of member-function pointers into
a call through address zero at -O1, -O2, -O3, and -Os. The standalone test
uses no headers and bounds the table index to 0 or 1. It should exit 0.
Target: x86_64-pc-linux-gnu
Compiler: GCC 17.0.0 20261001 (experimental)
Upstream base: 2e70e94cef1d76dbb3202d64184a7a8329c92f4e
Tested local compiler checkout: b9fdf4bc282fee44596de7f2ddfeec71e717c2ec
(the checkout also carries unrelated local fixes).
Regression is associated with commit
bd948cdc8664d9a1cd84ffeaae676a286c98e911, 2026-09-29:
"ranger: do not special case pointers in range_from_readonly_*"
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=bd948cdc8664d9a1cd84ffeaae676a286c98e911
Reproducer (also attached as testcase.C):
// { dg-do run { target c++11 } }
// Equivalent member-function pointer types can have distinct FIELD_DECLs
// in the constant initializer and the load. Do not infer a null pointer
// when matching those fields by identity fails.
struct Matcher
{
bool first () { return true; }
bool second () { return false; }
__attribute__((noinline)) bool dispatch (unsigned index)
{
using Proc = bool (Matcher::*)();
static const Proc table[] = { &Matcher::first, &Matcher::second };
const Proc proc = table[index];
return (this->*proc)();
}
};
int
main (int argc, char **)
{
Matcher matcher;
unsigned index = static_cast<unsigned>(argc - 1) & 1U;
if (matcher.dispatch (index) != (index == 0)
|| matcher.dispatch (index ^ 1U) != (index != 0))
__builtin_abort ();
}
Commands:
g++ -std=c++11 -O1 testcase.C -o testcase
./testcase
Expected: exit 0.
Actual: SIGSEGV from an indirect call to address zero.
The same test fails at -O2, -O3 and -Os, passes at -O0, and passes with:
g++ -std=c++11 -O1 --param=vrp-cstload-limit=0 testcase.C -o testcase
GCC 14.3.0 passes the test at -O1, -O2 and -O3.
A header-only Boost.Regex search reproducer shows the same failure with
GCC 17 at -O1/-O2/-O3 and passes with GCC 14.3.0 and Clang 24.0.0.
Optimized Matcher::dispatch contains:
mov $0, %eax
call *%rax
Diagnosis:
gcc/gimple-range-fold.cc:range_from_readonly_load handles COMPONENT_REF
by comparing constructor field nodes with ref_fld using pointer identity.
The member-function pointer constructor and the load have distinct
FIELD_DECL nodes for __pfn, belonging to equivalent record types.
Constructor lookup therefore misses a field that is actually populated.
The missing-record-field path calls range_from_missing_constructor_part
and infers zero. Ranger subsequently folds the function pointer to null.
GDB confirmed that the load's __pfn FIELD_DECL differs from the populated
constructor's __pfn FIELD_DECL. Replacing the constant-load range logic in
an isolated cc1plus with the version before bd948cdc8664 removes the failure.
This is an isolation experiment, not a full revision bisection.
Proposed conservative fix:
When field lookup fails, return unknown if DECL_CONTEXT(ref_fld) differs
from TREE_TYPE(cst), rather than inferring zero initialization. An attached
four-line guard preserves the existing behavior for exact record types.
Validation:
- Reproducer fails before the guard and passes afterward.
- GCC DejaGNU torture test: 14 expected passes, no unexpected failures,
including -O0/-O1/-O2/-O3/-Os and both LTO variants, with patched cc1plus
and lto1. Regression test checks both table entries.
- Original downstream test suite: 25/25 tests pass at -O3 with the guard,
including a Valgrind test. Before the guard, 11 tests segfault in
Boost.Regex search dispatch emitted into consumer code.
- Full GCC bootstrap/testsuites have not run.
The proposed fix and test were AI-assisted. Patch is offered for review.