https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127311
Bug ID: 127311
Summary: [C++] -fstrict-flex-arrays=3 does not reach
DECL_NOT_FLEXARRAY in the C++ front end
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: 220255623 at seu dot edu.cn
Target Milestone: ---
Created attachment 65549
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65549&action=edit
Preprocessed C++ reproducer for -fstrict-flex-arrays=3; compile with the
command in the report.
Build and target
----------------
GCC: 15.2.0 , native x86_64-pc-linux-gnu
Source: GCC 15.2.0 release tree (datestamp 20250808)
Host/Target/Build: x86_64-pc-linux-gnu
Relevant version output:
$ g++ -v
Using built-in specs.
COLLECT_GCC=~/gcc-builds/gcc-15.2.0-x86_64/bin/g++
Target: x86_64-pc-linux-gnu
Configured with: ~/gcc-sources/gcc-15.2.0/configure
--prefix=~/gcc-builds/gcc-15.2.0-x86_64 --disable-bootstrap --disable-multilib
--disable-nls --enable-languages=c,c++ --enable-default-pie --enable-cet
--disable-werror --enable-checking=release --with-system-zlib
--with-pkgversion=defuzz-gcc-15.2.0
Thread model: posix
gcc version 15.2.0
Reproducer
----------
C++ reproducer:
struct S {
int a;
int c[1];
};
unsigned long f (S *s) {
return __builtin_object_size (&s->c[0], 1);
}
The C control is the same struct and call with `struct S *s`; this is the
`trigger.cpp` / `trigger-c.c` pair.
Commands:
g++ -O2 -fstrict-flex-arrays=3 -fdump-tree-objsz1 -c trigger.cpp -o /dev/null
gcc -xc -O2 -fstrict-flex-arrays=3 -fdump-tree-objsz1 -c trigger-c.c -o
/dev/null
Both commands exit 0 with no stdout or stderr. With -fstrict-flex-arrays=3,
the trailing array c[1] is not a flexible array member, so the type-1 object
size of &s->c[0] should be 4 in both languages.
Observed in the objsz1 dumps:
C++: int f (...)
{
int _4;
_4 = -1;
return _4;
}
C: _1: maximum subobject size 4
long unsigned int _2;
_2 = 4;
The C++ result is (size_t)-1 because the array is still treated as a flexible
array member. The C result is the expected 4.
Root cause
----------
The GCC manual documents -fstrict-flex-arrays as "(C and C++ only)" and says
that at level 3 only an array declared as a flexible array member is treated
as one.
The C front end converts that decision into DECL_NOT_FLEXARRAY on trailing
FIELD_DECLs in gcc/c/c-decl.cc (finish_struct). The C++ front end contains no
reference to DECL_NOT_FLEXARRAY or c_strict_flex_array_level_of. Consequently
the field keeps its default zero value.
The middle end consumes the bit directly. In gcc/tree.cc,
array_ref_flexible_size_p returns:
return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
Thus zero is interpreted as "this is a flexible array member". No middle-end
pass re-derives the decision from the attribute or from
flag_strict_flex_arrays. LTO streaming and the C++20 module serializer only
carry the existing bit through; they do not initialize it from the option.
Diagnostics and hardening effects
---------------------------------
The same missing bit also affects the middle-end consumers:
* __builtin_object_size (..., 1) and __builtin_dynamic_object_size (..., 1)
remain unknown in C++.
* -Warray-bounds=2 does not warn in C++ for s->c[4], while C warns.
* -Wstrict-flex-arrays remains silent in C++, because
gcc/gimple-array-bounds.cc checks DECL_NOT_FLEXARRAY directly.
* Type-1 FORTIFY paths lose their check. For a same-source probe using
struct S { int a; char buf[1]; }; and strcpy(s->buf, src), C emits
call __strcpy_chk@PLT while C++ emits call strcpy@PLT.
* Non-strict -fsanitize=bounds also does not instrument this C++ access at
level 3. -fsanitize=bounds-strict is unaffected.
memcpy is not claimed here: its fortified form uses the type-0 object size
(__glibc_objsize0), which does not consult DECL_NOT_FLEXARRAY.
Versions tested
---------------
The same result occurs with GCC 15.2.0, GCC 16.1.0, the GCC 16.1 RC dated
20260424, and GCC 17.0.0 development snapshots dated 20260426 and 20260531.
No version tested produces the expected C++ result. Other versions and point
releases were not tested.
Attachments
-----------
trigger.ii is attached now. I will add trigger-c.i, trigger.cpp, trigger-c.c,
build.sh, gcc-v.txt and optionally the two objsz1 text dumps after the report
is created.