[PATCH] KVM: x86: Fix C++ user API for structures with variable length arrays
From: David Woodhouse
Date: Thu Feb 26 2026 - 06:46:06 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
Commit 94dfc73e7cf4 ("treewide: uapi: Replace zero-length arrays with
flexible-array members") broke the userspace API for C++. Not just in
the sense of 'userspace needs to be updated, but UAPI is supposed to be
stable", but broken in the sense that I can't actually see *how* the
structures can be used from C++ in the same way that they were usable
before.
These structures ending in VLAs are typically a *header*, which can be
followed by an arbitrary number of entries. Userspace typically creates
a larger structure with some non-zero number of entries, for example in
QEMU's kvm_arch_get_supported_msr_feature():
struct {
struct kvm_msrs info;
struct kvm_msr_entry entries[1];
} msr_data = {};
While that works in C, it fails in C++ with an error like:
flexible array member ‘kvm_msrs::entries’ not at end of ‘struct msr_data’
Fix this by using __DECLARE_FLEX_ARRAY() for the VLA, which is a helper
provided by <linux/stddef.h> that already uses [0] for C++ compilation.
Also put the header fields into a struct_group() to provide (in C) a
separate struct (e.g 'struct kvm_msrs_hdr') without the trailing VLA.
Fixes: 94dfc73e7cf4 ("treewide: uapi: Replace zero-length arrays with flexible-array members")
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
arch/x86/include/uapi/asm/kvm.h | 29 ++++++++++++++++++-----------
include/uapi/linux/kvm.h | 9 ++++++---
2 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 7ceff6583652..8fc0bc2d39a6 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -194,16 +194,19 @@ struct kvm_msr_entry {
/* for KVM_GET_MSRS and KVM_SET_MSRS */
struct kvm_msrs {
- __u32 nmsrs; /* number of msrs in entries */
- __u32 pad;
-
- struct kvm_msr_entry entries[];
+ __struct_group(kvm_msrs_hdr, hdr, /* no attrs */,
+ __u32 nmsrs; /* number of msrs in entries */
+ __u32 pad;
+ );
+ __DECLARE_FLEX_ARRAY(struct kvm_msr_entry, entries);
};
/* for KVM_GET_MSR_INDEX_LIST */
struct kvm_msr_list {
- __u32 nmsrs; /* number of msrs in entries */
- __u32 indices[];
+ __struct_group(kvm_msr_list_hdr, hdr, /* no attrs */,
+ __u32 nmsrs; /* number of msrs in entries */
+ );
+ __DECLARE_FLEX_ARRAY(__u32, indices);
};
/* Maximum size of any access bitmap in bytes */
@@ -265,9 +268,11 @@ struct kvm_cpuid_entry2 {
/* for KVM_SET_CPUID2 */
struct kvm_cpuid2 {
- __u32 nent;
- __u32 padding;
- struct kvm_cpuid_entry2 entries[];
+ __struct_group(kvm_cpuid2_hdr, hdr, /* no attrs */,
+ __u32 nent;
+ __u32 padding;
+ );
+ __DECLARE_FLEX_ARRAY(struct kvm_cpuid_entry2, entries);
};
/* for KVM_GET_PIT and KVM_SET_PIT */
@@ -397,8 +402,10 @@ struct kvm_xsave {
* The offsets of the state save areas in struct kvm_xsave follow
* the contents of CPUID leaf 0xD on the host.
*/
- __u32 region[1024];
- __u32 extra[];
+ __struct_group(kvm_xsave_hdr, hdr, /* no attrs */,
+ __u32 region[1024];
+ );
+ __DECLARE_FLEX_ARRAY(__u32, extra);
};
#define KVM_MAX_XCRS 16
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index dddb781b0507..2849d32ba035 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -11,6 +11,7 @@
#include <linux/const.h>
#include <linux/types.h>
#include <linux/compiler.h>
+#include <linux/stddef.h>
#include <linux/ioctl.h>
#include <asm/kvm.h>
@@ -1034,9 +1035,11 @@ struct kvm_irq_routing_entry {
};
struct kvm_irq_routing {
- __u32 nr;
- __u32 flags;
- struct kvm_irq_routing_entry entries[];
+ __struct_group(kvm_irq_routing_hdr, hdr, /* no attrs */,
+ __u32 nr;
+ __u32 flags;
+ );
+ __DECLARE_FLEX_ARRAY(struct kvm_irq_routing_entry, entries);
};
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
--
2.43.0
Attachment:
smime.p7s
Description: S/MIME cryptographic signature