https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297758

            Bug ID: 297758
           Summary: usr.sbin/pmc: builds failed with gcc14
           Product: Base System
           Version: 16.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: bin
          Assignee: [email protected]
          Reporter: [email protected]

Created attachment 273995
  --> https://bugs.freebsd.org/bugzilla/attachment.cgi?id=273995&action=edit
pmc-gcc14.patch

usr.sbin/pmc does not build with the amd64-gcc14 cross toolchain.  The
FreeBSD-main-amd64-gcc14_build CI job fails at a209aac86882:

  https://ci.freebsd.org/job/FreeBSD-main-amd64-gcc14_build/4531/console

This is the only compilation error in that log.  I get the same error
locally at the same revision.

  usr.sbin/pmc/headers.hh:79:25: error: flexible array member
  'pmchdr_cpuidinfo::cpuid' in an otherwise empty 'struct pmchdr_cpuidinfo'
     79 |         uint32_t        cpuid[];


Cause
-----

C++ has no flexible array members.  Each C++ compiler accepts them as an
extension.  GCC 14 and older versions refuse one that is the only member
of a struct.  GCC 15 removes this limit.  The adjacent struct
pmchdr_pmcinfo has a uint64_t rate before its char pmc[], thus it builds.

  uint32_t cpuid[]   clang++ 21 & g++ 15: OK, g++ 14: ERR
  uint32_t cpuid[0]  all three OK

A Makefile change cannot correct this.  The g++ frontend gives an
unconditional error, not a diagnostic behind a -W option.  These options
have no effect: -fpermissive, -fms-extensions, -w, -Wno-error,
-std=gnu++14, -std=gnu++20.


Remove the GCC 14 CI job?
-------------------------

Does the tree still need to support the GCC 14 cross toolchain?  I can
change the CI GCC jobs to GCC 15 only.  If that is acceptable, please
ignore the options below.


Options
-------

The attached patch does option 1.  The choice is for the author and the
reviewers.

1. Keep the flexible array member, and limit the workaround (attached).

Use cpuid[0] in an #if block for GCC versions before 15.  cpuid[] stays
the primary form, thus clang and GCC 15 get it.  The layout is the same in
both branches.  Remove the block at either of these events:

  - GCC 14 is not a supported cross toolchain.
  - The struct gets another member.

Note that a zero-length array and a flexible array member differ under
hardening options.  With -fstrict-flex-arrays=3, clang gives
__builtin_object_size(p->a, 1) as 0 for a[0], but the correct size for
a[].  FreeBSD does not use -fstrict-flex-arrays now.  This is the reason
to keep cpuid[0] conditional.

I am not very satisfied with this option.  It puts a preprocessor
conditional in a header that gives the pmc log file format.  I chose it
because pmchdr_cpuidinfo is possibly there for a future extension.  If
that is not correct, option 2 or option 3 is better.

2. Use a typedef.

  typedef uint32_t pmchdr_cpuidinfo;

process_cpuidinfo() keeps its pmchdr_cpuidinfo *cpuidinfo declaration and
its delete[].  The cast goes away, and cpuidinfo->cpuid[i] becomes
cpuidinfo[i].  There is no extension, no conditional, and no -Wpedantic
diagnostic on the three compilers.

3. Remove the struct.

Use uint32_t * in process_cpuidinfo(), and delete the struct.
write_cpuinfo() in cmd_pmc_record.cc already builds the payload as a
uint32_t * buffer and does not use the struct.  Thus the struct holds no
data that uint32_t * does not hold.

If the struct is for future fields, note that another member also
corrects the GCC 14 error.  The limit applies only while cpuid[] is the
only member.  You can add the struct again at that time, with a plain
cpuid[].

A fourth option changes the pmc log file format: give the struct a leading
count field, keep cpuid[], and write the field in write_cpuinfo().  This
is a design decision.


Related defect
--------------

process_cpuidinfo() releases the buffer through the wrong type:

  cpuidinfo = (pmchdr_cpuidinfo *)new uint32_t[len];
  ...
  delete[] cpuidinfo;

new uint32_t[] gives the buffer, but delete[] gets a pmchdr_cpuidinfo *.
This is undefined behavior.  The patch keeps a uint32_t *buf for the
allocation and the release, and uses the struct pointer only to read the
data.  Options 2 and 3 correct this on their own.

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to