linux-user: fork-style clone() writes CLONE_PARENT_SETTID from the child side
## Host environment - Operating system: EndeavourOS x86_64 - OS/kernel version: Linux ArchLinux-desktop 6.19.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 04 Mar 2026\ 18:25:08 +0000 x86_64 GNU/Linux\\ - Architecture: ALL - QEMU flavor: qemu-user(I tested qemu-x86_64 and riscv64) - QEMU version: 10.2.1 - QEMU command line: qemu-x86_64 /tmp/test-01 ## Emulated/Virtualized environment QEMU-USER - Architecture:ALL ## Description of problem In the fork-style clone path, CLONE_PARENT_SETTID appears to be implemented on the child side instead of the parent side. Relevant source locations(QEMU 10.2.50): linux-user/syscall.c:7035 linux-user/syscall.c:7042 At linux-user/syscall.c:7035, the child branch does the CLONE_PARENT_SETTID write. At linux-user/syscall.c:7042 and below, the parent branch handles CLONE_PIDFD but does not do the parent-side TID writeback. This is semantically wrong for ordinary private parent memory. After fork(), the child writes into its own private copy of the page, so the parent cannot observe the CLONE_PARENT_SETTID writeback. * Observed output on native Linux: clone_ret=91212 parent_tid=91212 match=yes * Observed output under qemu-x86_64: clone_ret=91214 parent_tid=-1 match=no * Expected behavior: parent_tid should match the returned child TID, as on Linux. * Actual behavior: the parent-visible memory remains unchanged under QEMU. This is a direct guest-visible linux-user semantic mismatch. ## Steps to reproduce 1. Minimal reproducer file: tests/01_clone_parent_settid.c(I upload it) [01_clone_parent_settid.c](/uploads/466eabbfc4f7ba5e99397241b66088d9/01_clone_parent_settid.c) 2. Build: gcc -O2 -Wall -Wextra -static -o /tmp/test-01 tests/01_clone_parent_settid.c 3. Run on native Linux: /tmp/test-01 4. Run under QEMU: qemu-x86_64 /tmp/test-01 ## Additional information I am a student from Xidian University. I quickly discovered Some bugs through Codex. I know that QEMU does not accept content directly generated by AI, so I have verified them and confirm that this bug is **valid**. code ```c #define _GNU_SOURCE #include <errno.h> #include <linux/sched.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> static long raw_clone_parent_settid(int *parent_tid) { return syscall(SYS_clone, (unsigned long)(SIGCHLD | CLONE_PARENT_SETTID), NULL, parent_tid, NULL, 0UL); } int main(void) { int parent_tid = -1; long ret = raw_clone_parent_settid(&parent_tid); if (ret < 0) { perror("clone"); return 1; } if (ret == 0) { _exit(0); } if (waitpid((pid_t)ret, NULL, 0) < 0) { perror("waitpid"); return 1; } printf("clone_ret=%ld parent_tid=%d match=%s\n", ret, parent_tid, parent_tid == ret ? "yes" : "no"); return 0; } ```
issue