[PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings

Gustavo A. R. Silva posted 1 patch 1 month, 2 weeks ago
arch/x86/events/perf_event.h | 41 ++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 18 deletions(-)
[PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Gustavo A. R. Silva 1 month, 2 weeks ago
-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
getting ready to enable it, globally.

Use the TRAILING_OVERLAP() helper to fix the following warnings:

14 arch/x86/events/intel/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
6 arch/x86/events/amd/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
3 arch/x86/events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
1 arch/x86/xen/../events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
1 arch/x86/events/zhaoxin/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
1 ./arch/x86/include/generated/../../events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

This helper creates a union between a flexible-array member (FAM)
and a set of members that would otherwise follow it. This overlays
the trailing members onto the FAM while preserving the original
memory layout.

Lastly, the static_assert() ensures the alignment between the FAM
and struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES]; is not
inadvertently changed, and it's intentionally placed inmediately
after the related structure (that is, no blank line in between).

It's also worth mentioning that the entire Intel LBR bits block
is moved just to avoid splitting it.

Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
 arch/x86/events/perf_event.h | 41 ++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index fad87d3c8b2c..9641b888cbee 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -318,24 +318,6 @@ struct cpu_hw_events {
 	/* Cached CFG_C values */
 	u64			cfg_c_val[X86_PMC_IDX_MAX];
 
-	/*
-	 * Intel LBR bits
-	 */
-	int				lbr_users;
-	int				lbr_pebs_users;
-	struct perf_branch_stack	lbr_stack;
-	struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
-	u64				lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */
-	union {
-		struct er_account		*lbr_sel;
-		struct er_account		*lbr_ctl;
-	};
-	u64				br_sel;
-	void				*last_task_ctx;
-	int				last_log_id;
-	int				lbr_select;
-	void				*lbr_xsave;
-
 	/*
 	 * Intel host/guest exclude bits
 	 */
@@ -384,7 +366,30 @@ struct cpu_hw_events {
 	void				*kfree_on_online[X86_PERF_KFREE_MAX];
 
 	struct pmu			*pmu;
+
+	/*
+	 * Intel LBR bits
+	 */
+	int				lbr_users;
+	int				lbr_pebs_users;
+	union {
+		struct er_account		*lbr_sel;
+		struct er_account		*lbr_ctl;
+	};
+	u64				br_sel;
+	void				*last_task_ctx;
+	int				last_log_id;
+	int				lbr_select;
+	void				*lbr_xsave;
+
+	/* Must be last as it ends in a flexible-array member. */
+	TRAILING_OVERLAP(struct perf_branch_stack, lbr_stack, entries,
+		struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
+		u64				lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */
+	);
 };
+static_assert(offsetof(struct cpu_hw_events, lbr_stack.entries) ==
+	      offsetof(struct cpu_hw_events, lbr_entries));
 
 #define __EVENT_CONSTRAINT_RANGE(c, e, n, m, w, o, f) {	\
 	{ .idxmsk64 = (n) },		\
-- 
2.51.0
Re: [PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Peter Zijlstra 1 month, 1 week ago
On Wed, Apr 29, 2026 at 01:29:18PM -0600, Gustavo A. R. Silva wrote:

> +	/*
> +	 * Intel LBR bits
> +	 */
> +	int				lbr_users;
> +	int				lbr_pebs_users;
> +	union {
> +		struct er_account		*lbr_sel;
> +		struct er_account		*lbr_ctl;
> +	};
> +	u64				br_sel;
> +	void				*last_task_ctx;
> +	int				last_log_id;
> +	int				lbr_select;
> +	void				*lbr_xsave;
> +
> +	/* Must be last as it ends in a flexible-array member. */
> +	TRAILING_OVERLAP(struct perf_branch_stack, lbr_stack, entries,
> +		struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
> +		u64				lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */
> +	);

FWIW, this thing is horrible crap. Per construction this thing does not
need to be last at all, you can have multiple such constructs in a
single structure and things would be perfectly fine.

Also, your TRAILING_OVERLAP() thing should probably have
__no_randomize_layout in ATTRS, rather than empty (and I'm assuming
__packed implies __no_randomized_layout, otherwise 'fun' things can
happen).

>  };
Re: [PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Peter Zijlstra 1 month, 1 week ago
On Wed, Apr 29, 2026 at 01:29:18PM -0600, Gustavo A. R. Silva wrote:
> -Wflex-array-member-not-at-end was introduced in GCC-14, and we are
> getting ready to enable it, globally.
> 
> Use the TRAILING_OVERLAP() helper to fix the following warnings:
> 
> 14 arch/x86/events/intel/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 6 arch/x86/events/amd/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 3 arch/x86/events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 1 arch/x86/xen/../events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 1 arch/x86/events/zhaoxin/../perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 1 ./arch/x86/include/generated/../../events/perf_event.h:326:41: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]
> 
> This helper creates a union between a flexible-array member (FAM)
> and a set of members that would otherwise follow it. This overlays
> the trailing members onto the FAM while preserving the original
> memory layout.
> 
> Lastly, the static_assert() ensures the alignment between the FAM
> and struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES]; is not
> inadvertently changed, and it's intentionally placed inmediately
> after the related structure (that is, no blank line in between).
> 
> It's also worth mentioning that the entire Intel LBR bits block
> is moved just to avoid splitting it.
> 
> Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> ---
>  arch/x86/events/perf_event.h | 41 ++++++++++++++++++++----------------
>  1 file changed, 23 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
> index fad87d3c8b2c..9641b888cbee 100644
> --- a/arch/x86/events/perf_event.h
> +++ b/arch/x86/events/perf_event.h
> @@ -318,24 +318,6 @@ struct cpu_hw_events {
>  	/* Cached CFG_C values */
>  	u64			cfg_c_val[X86_PMC_IDX_MAX];
>  
> -	/*
> -	 * Intel LBR bits
> -	 */
> -	int				lbr_users;
> -	int				lbr_pebs_users;
> -	struct perf_branch_stack	lbr_stack;
> -	struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
> -	u64				lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */
> -	union {
> -		struct er_account		*lbr_sel;
> -		struct er_account		*lbr_ctl;
> -	};
> -	u64				br_sel;
> -	void				*last_task_ctx;
> -	int				last_log_id;
> -	int				lbr_select;
> -	void				*lbr_xsave;
> -
>  	/*
>  	 * Intel host/guest exclude bits
>  	 */
> @@ -384,7 +366,30 @@ struct cpu_hw_events {
>  	void				*kfree_on_online[X86_PERF_KFREE_MAX];
>  
>  	struct pmu			*pmu;
> +
> +	/*
> +	 * Intel LBR bits
> +	 */
> +	int				lbr_users;
> +	int				lbr_pebs_users;
> +	union {
> +		struct er_account		*lbr_sel;
> +		struct er_account		*lbr_ctl;
> +	};
> +	u64				br_sel;
> +	void				*last_task_ctx;
> +	int				last_log_id;
> +	int				lbr_select;
> +	void				*lbr_xsave;
> +
> +	/* Must be last as it ends in a flexible-array member. */
> +	TRAILING_OVERLAP(struct perf_branch_stack, lbr_stack, entries,
> +		struct perf_branch_entry	lbr_entries[MAX_LBR_ENTRIES];
> +		u64				lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */
> +	);
>  };
> +static_assert(offsetof(struct cpu_hw_events, lbr_stack.entries) ==
> +	      offsetof(struct cpu_hw_events, lbr_entries));

This is horrible. That code was perfectly fine, and now you've made it
an unholy trainwreck just because compiler is stupid :-(

Also, we seem to be going around in circles, what was wrong with:

  https://lore.kernel.org/all/20240806113254.GG12673@noisy.programming.kicks-ass.net/
Re: [PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Gustavo A. R. Silva 1 month, 1 week ago
>    https://lore.kernel.org/all/20240806113254.GG12673@noisy.programming.kicks-ass.net/ 

Feel free to apply it.
Re: [PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Peter Zijlstra 1 month, 1 week ago
On Mon, May 04, 2026 at 01:50:50PM -0600, Gustavo A. R. Silva wrote:
> >    https://lore.kernel.org/all/20240806113254.GG12673@noisy.programming.kicks-ass.net/
> 
> Feel free to apply it.

Bah, stupid warning :/

There really is no sane way to tell the compiler that the code is fine
and it should just STFU already? I mean, it is directly followed by an
array of the right type to fill that flex thing.

Anyway, I suppose this all very much relies on the structure not getting
randomized, so let me stick __no_randomize_layout on it at the very
least.
Re: [PATCH][next] perf/x86: Avoid multiple -Wflex-array-member-not-at-end warnings
Posted by Peter Zijlstra 1 month, 1 week ago
On Thu, May 07, 2026 at 10:10:12AM +0200, Peter Zijlstra wrote:
> On Mon, May 04, 2026 at 01:50:50PM -0600, Gustavo A. R. Silva wrote:
> > >    https://lore.kernel.org/all/20240806113254.GG12673@noisy.programming.kicks-ass.net/
> > 
> > Feel free to apply it.
> 
> Bah, stupid warning :/
> 
> There really is no sane way to tell the compiler that the code is fine
> and it should just STFU already? I mean, it is directly followed by an
> array of the right type to fill that flex thing.
> 
> Anyway, I suppose this all very much relies on the structure not getting
> randomized, so let me stick __no_randomize_layout on it at the very
> least.

Ideally GCC would get fixed to allow something like so:

struct bar;

struct foo {
	...
	struct bar entries[];
};

struct ponies {
	...
	struct foo my_foo __sized_by(my_bars);
	struct bar my_bars[16];
	...
};

Such that the __sized_by() applies to foo::entries and ensures the
member is no longer considered unsized.

But I suspect this needs the whole of the flexarray insanity fixed;
because for some idiotic reason it is allowed for offsetof(struct foo,
entries) != sizeof(struct foo), and if that is the case, then everything
goes sideways in a hurry.

Note that the kernel very much does not rely on that weird behaviour,
since it always allocates sizeof(foo) + count * sizeof(foo::entries[0])
like. So we always have sufficient space at the end of the object.

And then I'm sure fixing flexarray is considered breaking ABI and so
we're left up a creek without no paddles on.

This is a giant shitshow, is what.