Commit 0376e9c2dd for qemu.org

commit 0376e9c2dd1f46dd779ebc85f40f7a8cfa46ed6f
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Tue Mar 24 14:02:29 2026 +0000

    linux-user/i386/signal.c: Correct definition of target_fpstate_32

    Our definition of the target_fpstate_32 struct doesn't match the
    kernel's version.  We only use this struct definition in the
    definition of 'struct sigframe', where it is used in a field that is
    present only for legacy reasons to retain the offset of the following
    'extramask' field.  So really all that matters is its length, and we
    do get that right; but our previous definition using
    X86LegacySaveArea implicitly added an extra alignment constraint
    (because X86LegacySaveArea is tagged as 16-aligned) which the real
    target_fpstate_32 does not have.  Because we allocate and use a
    'struct sigframe' on the guest's stack with the guest's alignment
    requirements, this resulted in the undefined-behaviour sanitizer
    complaining during 'make check-tcg' for i386-linux-user:

    ../../linux-user/i386/signal.c:471:35: runtime error: member access within misaligned address 0x1000c07f75ec for type 'struct sigframe', which requires 16 byte alignment
    0x1000c07f75ec: note: pointer points here
      00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
                  ^

    ../../linux-user/i386/signal.c:808:5: runtime error: member access within misaligned address 0x1000c07f75f4 for type 'struct target_sigcontext_32', which requires 8 byte alignment
    0x1000c07f75f4: note: pointer points here
      0a 00 00 00 33 00 00 00  00 00 00 00 2b 00 00 00  2b 00 00 00 40 05 80 40  f4 7f 10 08 58 05 80 40
                  ^

    and various similar errors.

    Replace the use of X86LegacyXSaveArea with a set of fields that match
    the kernel _fpstate_32 struct, and assert that the length is correct.
    We could equally have used
       uint8_t legacy_area[512];
    but following the kernel is probably less confusing overall.

    Since in target/i386/cpu.h we assert that X86LegacySaveArea is 512
    bytes, and in linux-user/i386/signal.c we assert that
    target_fregs_state is (32 + 80) bytes, the new assertion confirms
    that we didn't change the size of target_fpstate_32 here, only its
    alignment requirements.

    Cc: qemu-stable@nongnu.org
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
    Message-id: 20260305161739.1775232-1-peter.maydell@linaro.org

diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 0f11dba831..b646fde431 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -60,10 +60,33 @@ struct target_fpx_sw_bytes {
 };
 QEMU_BUILD_BUG_ON(sizeof(struct target_fpx_sw_bytes) != 12*4);

+struct fpxreg {
+    uint16_t significand[4];
+    uint16_t exponent;
+    uint16_t padding[3];
+};
+
+struct xmmreg {
+    uint32_t element[4];
+};
+
+/*
+ * This corresponds to the kernel's _fpstate_32. Since we
+ * only use it for the fpstate_unused padding section in
+ * the target sigcontext, it doesn't actually matter what fields
+ * we define here as long as we get the size right.
+ */
 struct target_fpstate_32 {
     struct target_fregs_state fpstate;
-    X86LegacyXSaveArea fxstate;
+    uint32_t fxsr_env[6];
+    uint32_t mxcsr;
+    uint32_t reserved;
+    struct fpxreg fxsr_st[8];
+    struct xmmreg xmm[8];
+    uint32_t padding1[44];
+    uint32_t padding2[12]; /* aka sw_reserved */
 };
+QEMU_BUILD_BUG_ON(sizeof(struct target_fpstate_32) != 32 + 80 + 512);

 struct target_sigcontext_32 {
     uint16_t gs, __gsh;