Skip to contentSkip to conversation

acpi: nfit: intel: avoid multiple -Wflex-array-member-not-at-end warnings

PATCH Superseded Gustavo A. R. Silva 4 participants 8 messages Jun 11, 2025 – Jun 25, 2025

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 acpi: nfit: intel: avoid multiple -Wflex-array-member-not-at-end warnings

-Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally.

Refactor multiple structs that contain flexible-array members in the middle by replacing them with unions.

These changes preserve the memory layout while effectively adjusting it so that the flexible-array member is always treated as the last member.

With these changes, fix a dozen instances of the following type of warning:

drivers/acpi/nfit/intel.c:692:35: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

---
Changes in v3:
- Use union instead of DEFINE_RAW_FLEX().

Changes in v2:
- Use DEFINE_RAW_FLEX() instead of __struct_group().
- Link: https://lore.kernel.org/linux-hardening/Z-QpUcxFCRByYcTA@kspp/

v1:
- Link: https://lore.kernel.org/linux-hardening/Z618ILbAR8YAvTkd@kspp/

 drivers/acpi/nfit/intel.c | 132 +++++++++++++++++++++++++++++++-------
 1 file changed, 108 insertions(+), 24 deletions(-)
drivers/acpi/nfit/intel.c +108 -24
index 3902759abcba..987d427ec2b6 100644
@@ -55,9 +55,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	unsigned long security_flags = 0;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_get_security_state cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_get_security_state cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
@@ -120,9 +127,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
 static int intel_security_freeze(struct nvdimm *nvdimm)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_freeze_lock cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_freeze_lock cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FREEZE_LOCK,
@@ -153,9 +167,16 @@ static int intel_security_change_key(struct nvdimm *nvdimm,
 	unsigned int cmd = ptype == NVDIMM_MASTER ?
 		NVDIMM_INTEL_SET_MASTER_PASSPHRASE :
 		NVDIMM_INTEL_SET_PASSPHRASE;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_set_passphrase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_set_passphrase cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -195,9 +216,16 @@ static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
 		const struct nvdimm_key_data *key_data)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_unlock_unit cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_unlock_unit cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
@@ -234,9 +262,16 @@ static int intel_security_disable(struct nvdimm *nvdimm,
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_disable_passphrase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_disable_passphrase cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
@@ -277,9 +312,16 @@ static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	unsigned int cmd = ptype == NVDIMM_MASTER ?
 		NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_secure_erase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_secure_erase cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -318,9 +360,16 @@ static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_query_overwrite cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_query_overwrite cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_QUERY_OVERWRITE,
@@ -354,9 +403,16 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_overwrite cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_overwrite cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_OVERWRITE,
@@ -407,9 +463,16 @@ const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
 static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc,
 		struct nd_intel_bus_fw_activate_businfo *info)
 {
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_bus_fw_activate_businfo cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_bus_fw_activate_businfo cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
@@ -518,9 +581,16 @@ static enum nvdimm_fwa_capability intel_bus_fwa_capability(
 static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc)
 {
 	struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_bus_fw_activate cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_bus_fw_activate cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE,
@@ -582,9 +652,16 @@ const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops;
 static int intel_fwa_dimminfo(struct nvdimm *nvdimm,
 		struct nd_intel_fw_activate_dimminfo *info)
 {
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_fw_activate_dimminfo cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_fw_activate_dimminfo cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO,
@@ -688,9 +765,16 @@ static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_fw_activate_arm cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_fw_activate_arm cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM,
Signature · 1 line
2.43.0
#1 lore raw

Hi all,

Friendly ping: who can review or take this, please? :)

Thanks!
-Gustavo

Quoted 262 lines · Gustavo A. R. Silva

-Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally.

Refactor multiple structs that contain flexible-array members in the middle by replacing them with unions.

These changes preserve the memory layout while effectively adjusting it so that the flexible-array member is always treated as the last member.

With these changes, fix a dozen instances of the following type of warning:

drivers/acpi/nfit/intel.c:692:35: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

---
Changes in v3:
- Use union instead of DEFINE_RAW_FLEX().

Changes in v2:
- Use DEFINE_RAW_FLEX() instead of __struct_group().
- Link: https://lore.kernel.org/linux-hardening/Z-QpUcxFCRByYcTA@kspp/

v1:
- Link: https://lore.kernel.org/linux-hardening/Z618ILbAR8YAvTkd@kspp/

  drivers/acpi/nfit/intel.c | 132 +++++++++++++++++++++++++++++++-------
  1 file changed, 108 insertions(+), 24 deletions(-)
drivers/acpi/nfit/intel.c +108 -24
index 3902759abcba..987d427ec2b6 100644
@@ -55,9 +55,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
  {
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
  	unsigned long security_flags = 0;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_get_security_state cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_get_security_state cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
@@ -120,9 +127,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
  static int intel_security_freeze(struct nvdimm *nvdimm)
  {
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_freeze_lock cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_freeze_lock cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_FREEZE_LOCK,
@@ -153,9 +167,16 @@ static int intel_security_change_key(struct nvdimm *nvdimm,
  	unsigned int cmd = ptype == NVDIMM_MASTER ?
  		NVDIMM_INTEL_SET_MASTER_PASSPHRASE :
  		NVDIMM_INTEL_SET_PASSPHRASE;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_set_passphrase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_set_passphrase cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -195,9 +216,16 @@ static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
  		const struct nvdimm_key_data *key_data)
  {
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_unlock_unit cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_unlock_unit cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
@@ -234,9 +262,16 @@ static int intel_security_disable(struct nvdimm *nvdimm,
  {
  	int rc;
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_disable_passphrase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_disable_passphrase cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
@@ -277,9 +312,16 @@ static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
  	unsigned int cmd = ptype == NVDIMM_MASTER ?
  		NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_secure_erase cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_secure_erase cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -318,9 +360,16 @@ static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
  {
  	int rc;
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_query_overwrite cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_query_overwrite cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_QUERY_OVERWRITE,
@@ -354,9 +403,16 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
  {
  	int rc;
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_overwrite cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_overwrite cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_OVERWRITE,
@@ -407,9 +463,16 @@ const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
  static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc,
  		struct nd_intel_bus_fw_activate_businfo *info)
  {
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_bus_fw_activate_businfo cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_bus_fw_activate_businfo cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
@@ -518,9 +581,16 @@ static enum nvdimm_fwa_capability intel_bus_fwa_capability(
  static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc)
  {
  	struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_bus_fw_activate cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_bus_fw_activate cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE,
@@ -582,9 +652,16 @@ const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops;
  static int intel_fwa_dimminfo(struct nvdimm *nvdimm,
  		struct nd_intel_fw_activate_dimminfo *info)
  {
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_fw_activate_dimminfo cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_fw_activate_dimminfo cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO,
@@ -688,9 +765,16 @@ static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm)
  {
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
  	struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_fw_activate_arm cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_fw_activate_arm cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM,
#2 lore raw
In reply to Gustavo A. R. Silva
Quoted 13 lines · Gustavo A. R. Silva

-Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally.

Refactor multiple structs that contain flexible-array members in the middle by replacing them with unions.

These changes preserve the memory layout while effectively adjusting it so that the flexible-array member is always treated as the last member.

With these changes, fix a dozen instances of the following type of warning:

Quoted 6 lines

drivers/acpi/nfit/intel.c:692:35: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

---
Changes in v3:
- Use union instead of DEFINE_RAW_FLEX().

I think your TRAILING_OVERLAP macro[1] is perfect here. I'll try to get that landed for the next rc. Can you double-check that this works correctly in these cases?

Quoted 9 lines
drivers/acpi/nfit/intel.c +4 -1
@@ -55,9 +55,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	unsigned long security_flags = 0;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */

drivers/acpi/nfit/intel.c static unsigned long intel_security_flags(struct nvdimm *nvdimm, · line 70

Quoted 10 lines
drivers/acpi/nfit/intel.c +5 -1
+	union {
 		struct nd_cmd_pkg pkg;
-		struct nd_intel_get_security_state cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_get_security_state cmd;
+		};
 	} nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,

I think it would be a pretty small and direct replacement:

	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

-Kees

[1] https://web.git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=for-next/kspp&id=29bb79e9dbf1ba100125e39deb7147acd490903f

Signature · 1 line
Kees Cook
#3 lore raw
Quoted 16 lines · Kees Cook
Quoted 15 lines · Gustavo A. R. Silva

-Wflex-array-member-not-at-end was introduced in GCC-14, and we are getting ready to enable it, globally.

Refactor multiple structs that contain flexible-array members in the middle by replacing them with unions.

These changes preserve the memory layout while effectively adjusting it so that the flexible-array member is always treated as the last member.

With these changes, fix a dozen instances of the following type of warning:

drivers/acpi/nfit/intel.c:692:35: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

Quoted 8 lines
Quoted 4 lines

---
Changes in v3:
- Use union instead of DEFINE_RAW_FLEX().

I think your TRAILING_OVERLAP macro[1] is perfect here. I'll try to get that landed for the next rc. Can you double-check that this works correctly in these cases?

Absolutely. If people prefer that route I'm happy to wait for the helper to land in linus' tree.

Quoted 23 lines
Quoted 10 lines
drivers/acpi/nfit/intel.c +4 -1
@@ -55,9 +55,16 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
  {
  	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
  	unsigned long security_flags = 0;
-	struct {
+	/*
+	 * This effectively creates a union between the flexible-array member
+	 * and any members after _offset_to_fam.
+	 */

drivers/acpi/nfit/intel.c static unsigned long intel_security_flags(struct nvdimm *nvdimm, · line 70

Quoted 10 lines
drivers/acpi/nfit/intel.c +5 -1
+	union {
  		struct nd_cmd_pkg pkg;
-		struct nd_intel_get_security_state cmd;
+		struct {
+			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
+			struct nd_intel_get_security_state cmd;
+		};
  	} nd_cmd = {
  		.pkg = {
  			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,

I think it would be a pretty small and direct replacement:

Quoted 4 lines
	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

Yes, this works. Hopefully, maintainers will comment on this and let us know what they prefer. :)

Thanks!
-Gustavo

Quoted 5 lines

-Kees

[1] https://web.git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=for-next/kspp&id=29bb79e9dbf1ba100125e39deb7147acd490903f

#4 lore raw

Gustavo A. R. Silva wrote:
[..]

Quoted 9 lines
Quoted 6 lines

I think it would be a pretty small and direct replacement:

	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

Yes, this works. Hopefully, maintainers will comment on this and let us know what they prefer. :)

Hey Gustavo, apologies for the latency here. I think TRAILING_OVERLAP() looks lovely for this if only because I can read that and have an idea what it means vs wondering what this _offset_to_fam is about and needing to read the comment.

If you can get me that patch on top of the TRAILING_OVERLAP() branch I can test it out and ack it to let it do in through the KSPP tree.

Acked-by Tested-by
#5 lore raw
Quoted 12 lines · dan.j.williams@ wrote:

Gustavo A. R. Silva wrote:
[..]

Quoted 9 lines
Quoted 6 lines

I think it would be a pretty small and direct replacement:

	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

Yes, this works. Hopefully, maintainers will comment on this and let us know what they prefer. :)

Quoted 7 lines

Hey Gustavo, apologies for the latency here. I think TRAILING_OVERLAP() looks lovely for this if only because I can read that and have an idea what it means vs wondering what this _offset_to_fam is about and needing to read the comment.

If you can get me that patch on top of the TRAILING_OVERLAP() branch I can test it out and ack it to let it do in through the KSPP tree.

Just to move this along, I gave this conversion a try and all looks good here. So feel free to fold this in and add:

...and take it through the KSPP tree with the TRAILING_OVERLAP() merge.

-- 8< --

drivers/acpi/nfit/intel.c +36 -132
index 987d427ec2b6..c88647428715 100644
@@ -55,17 +55,9 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	unsigned long security_flags = 0;
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_get_security_state cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_get_security_state cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -127,17 +119,9 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,
 static int intel_security_freeze(struct nvdimm *nvdimm)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_freeze_lock cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_freeze_lock cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FREEZE_LOCK,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -167,17 +151,9 @@ static int intel_security_change_key(struct nvdimm *nvdimm,
 	unsigned int cmd = ptype == NVDIMM_MASTER ?
 		NVDIMM_INTEL_SET_MASTER_PASSPHRASE :
 		NVDIMM_INTEL_SET_PASSPHRASE;
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_set_passphrase cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_set_passphrase cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_family = NVDIMM_FAMILY_INTEL,
 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2,
@@ -216,17 +192,9 @@ static int __maybe_unused intel_security_unlock(struct nvdimm *nvdimm,
 		const struct nvdimm_key_data *key_data)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_unlock_unit cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_unlock_unit cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_UNLOCK_UNIT,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -262,17 +230,9 @@ static int intel_security_disable(struct nvdimm *nvdimm,
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_disable_passphrase cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_disable_passphrase cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -312,17 +272,9 @@ static int __maybe_unused intel_security_erase(struct nvdimm *nvdimm,
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	unsigned int cmd = ptype == NVDIMM_MASTER ?
 		NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE;
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_secure_erase cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_secure_erase cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_family = NVDIMM_FAMILY_INTEL,
 			.nd_size_in = ND_INTEL_PASSPHRASE_SIZE,
@@ -360,17 +312,9 @@ static int __maybe_unused intel_security_query_overwrite(struct nvdimm *nvdimm)
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_query_overwrite cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_query_overwrite cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_QUERY_OVERWRITE,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -403,17 +347,9 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm,
 {
 	int rc;
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_overwrite cmd;
-		};
-	} nd_cmd = {
+        TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+                         struct nd_intel_overwrite cmd;
+        ) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_OVERWRITE,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -463,17 +399,9 @@ const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
 static int intel_bus_fwa_businfo(struct nvdimm_bus_descriptor *nd_desc,
 		struct nd_intel_bus_fw_activate_businfo *info)
 {
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_bus_fw_activate_businfo cmd;
-		};
-	} nd_cmd = {
+        TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+                         struct nd_intel_bus_fw_activate_businfo cmd;
+        ) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE_BUSINFO,
 			.nd_family = NVDIMM_BUS_FAMILY_INTEL,
@@ -581,17 +509,9 @@ static enum nvdimm_fwa_capability intel_bus_fwa_capability(
 static int intel_bus_fwa_activate(struct nvdimm_bus_descriptor *nd_desc)
 {
 	struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_bus_fw_activate cmd;
-		};
-	} nd_cmd = {
+        TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+                         struct nd_intel_bus_fw_activate cmd;
+        ) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_BUS_INTEL_FW_ACTIVATE,
 			.nd_family = NVDIMM_BUS_FAMILY_INTEL,
@@ -652,17 +572,9 @@ const struct nvdimm_bus_fw_ops *intel_bus_fw_ops = &__intel_bus_fw_ops;
 static int intel_fwa_dimminfo(struct nvdimm *nvdimm,
 		struct nd_intel_fw_activate_dimminfo *info)
 {
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_fw_activate_dimminfo cmd;
-		};
-	} nd_cmd = {
+        TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+                         struct nd_intel_fw_activate_dimminfo cmd;
+        ) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_DIMMINFO,
 			.nd_family = NVDIMM_FAMILY_INTEL,
@@ -765,17 +677,9 @@ static int intel_fwa_arm(struct nvdimm *nvdimm, enum nvdimm_fwa_trigger arm)
 {
 	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
 	struct acpi_nfit_desc *acpi_desc = nfit_mem->acpi_desc;
-	/*
-	 * This effectively creates a union between the flexible-array member
-	 * and any members after _offset_to_fam.
-	 */
-	union {
-		struct nd_cmd_pkg pkg;
-		struct {
-			u8 _offset_to_fam[offsetof(struct nd_cmd_pkg, nd_payload)];
-			struct nd_intel_fw_activate_arm cmd;
-		};
-	} nd_cmd = {
+	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
+			 struct nd_intel_fw_activate_arm cmd;
+	) nd_cmd = {
 		.pkg = {
 			.nd_command = NVDIMM_INTEL_FW_ACTIVATE_ARM,
 			.nd_family = NVDIMM_FAMILY_INTEL,
#6 lore raw
Quoted 21 lines · On 25/06/25 15:08, [email protected] wrote:
Quoted 12 lines · dan.j.williams@ wrote:

Gustavo A. R. Silva wrote:
[..]

Quoted 9 lines
Quoted 6 lines

I think it would be a pretty small and direct replacement:

	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

Yes, this works. Hopefully, maintainers will comment on this and let us know what they prefer. :)

Quoted 7 lines

Hey Gustavo, apologies for the latency here. I think TRAILING_OVERLAP() looks lovely for this if only because I can read that and have an idea what it means vs wondering what this _offset_to_fam is about and needing to read the comment.

If you can get me that patch on top of the TRAILING_OVERLAP() branch I can test it out and ack it to let it do in through the KSPP tree.

Quoted 7 lines

Just to move this along, I gave this conversion a try and all looks good here. So feel free to fold this in and add:

...and take it through the KSPP tree with the TRAILING_OVERLAP() merge.

Thank you, Dan! :)

-Gustavo

#7 lore raw
Quoted 27 lines · Gustavo A. R. Silva
Quoted 24 lines · On 25/06/25 15:08, [email protected] wrote:
Quoted 12 lines · dan.j.williams@ wrote:

Gustavo A. R. Silva wrote:
[..]

Quoted 9 lines
Quoted 6 lines

I think it would be a pretty small and direct replacement:

	TRAILING_OVERLAP(struct nd_cmd_pkg, pkg, nd_payload,
			 struct nd_intel_get_security_state cmd;
	) nd_cmd = {
		...

Yes, this works. Hopefully, maintainers will comment on this and let us know what they prefer. :)

Quoted 7 lines

Hey Gustavo, apologies for the latency here. I think TRAILING_OVERLAP() looks lovely for this if only because I can read that and have an idea what it means vs wondering what this _offset_to_fam is about and needing to read the comment.

If you can get me that patch on top of the TRAILING_OVERLAP() branch I can test it out and ack it to let it do in through the KSPP tree.

Just to move this along, I gave this conversion a try and all looks good here. So feel free to fold this in and add:

Quoted 6 lines
Quoted 4 lines

...and take it through the KSPP tree with the TRAILING_OVERLAP() merge.

Thank you, Dan! :)

Uh oh, I spoke too soon. I saw most of the tests pass when I sent that mail, but the firmware-update.sh regresses. It passes on vanilla v6.16-rc3 and fails with both the original open-coded _offset_to_fam[] approach and TRAILING_OVERLAP() conversion.

Let me try to get some more debug info.

The test is:

meson test -C build firmware-update.sh

...from the ndctl project:

https://github.com/pmem/ndctl