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.

Reply via email to