Просмотр исходного кода

libc: fix struct shmid_ds layout for TIME64

The TIME64 handling of shmid_ds was missing or wrong almost everywhere
(exposed by the new upstream tst-shmctl):

- common bits/shm.h (i386, microblaze, arc, or1k, ...) had no TIME64
  layout at all: with a 64-bit __time_t every field after shm_atime
  shifted and shmctl(IPC_STAT) returned garbage
- csky has its own bits/shm.h (different SHMLBA), also without TIME64
- m68k (commit 9a23a016a, "Fix Sysvipc for ARM, AARCH64, RISCV64, KVX
  and m68k") declares plain 64-bit time fields over the kernel's split
  low/high words.  That layout is only correct little-endian - m68k is
  big-endian, so the times came back word-swapped

Use the same scheme as bits/sem.h: under __UCLIBC_USE_TIME64__ the
kernel-facing fields are the split __shm_*_internal_1/2 words and the
real __time_t fields live at the end of the struct; shmctl() combines
the words after IPC_STAT.  The headers that use this layout define
__SHMID_DS_TIME64_SPLIT so shm.c does not need to repeat the arch list
(mips keeps its existing private variant).

arm and riscv32 keep their inline little-endian layout from 9a23a016a,
which is correct there.  xtensa still has no TIME64 handling in its
bits/shm.h.

Verified under qemu-system-microblazeel: tst-shmctl passes, sem/
tst-semctl/tst-msgctl stay green.  Also fixes the tst-shmctl failures
on i686, csky and m68k.

Signed-off-by: Ramin Moussavi <ramin.moussavi@yacoub.de>
Ramin Moussavi 4 дней назад
Родитель
Сommit
5bbfe79168

+ 8 - 0
libc/misc/sysvipc/shm.c

@@ -75,6 +75,14 @@ int shmctl(int shmid, int cmd, struct shmid_ds *buf)
 		arg.buff->shm_dtime = (__time_t)arg.buff->shm_dtime_internal_1 | (__time_t)(arg.buff->shm_dtime_internal_2) << 32;
 		arg.buff->shm_ctime = (__time_t)arg.buff->shm_ctime_internal_1 | (__time_t)(arg.buff->shm_ctime_internal_2) << 32;
 	}
+#elif defined(__SHMID_DS_TIME64_SPLIT)
+	// combine the kernel's split time words
+	// When cmd is IPC_RMID, buf should be NULL.
+	if (buf != NULL) {
+		buf->shm_atime = (__time_t)buf->__shm_atime_internal_1 | (__time_t)(buf->__shm_atime_internal_2) << 32;
+		buf->shm_dtime = (__time_t)buf->__shm_dtime_internal_1 | (__time_t)(buf->__shm_dtime_internal_2) << 32;
+		buf->shm_ctime = (__time_t)buf->__shm_ctime_internal_1 | (__time_t)(buf->__shm_ctime_internal_2) << 32;
+	}
 #endif
 	return __ret;
 #else

+ 30 - 0
libc/sysdeps/linux/common/bits/shm.h

@@ -49,17 +49,47 @@ struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
     size_t shm_segsz;			/* size of segment in bytes */
+#if defined(__UCLIBC_USE_TIME64__)
+    unsigned long int __shm_atime_internal_1;
+    unsigned long int __shm_atime_internal_2;
+#else
     __time_t shm_atime;			/* time of last shmat() */
+#endif
+#if (__WORDSIZE == 32 && !defined(__ARC64_ARCH32__) && !defined(__arc__) && !defined(__arm__) && !defined(__or1k__) && !defined(__xtensa__) && !defined(__riscv) && !defined(__csky__) && !defined(__i386__) && !defined(__m68k__) && !defined(__microblaze__)) || \
+    ((defined(__ARC64_ARCH32__) || defined(__arc__) || defined(__arm__) || defined(__or1k__) || defined(__xtensa__) || defined(__riscv) || defined(__csky__) || defined(__i386__) || defined(__m68k__) || defined(__microblaze__)) && !defined(__UCLIBC_USE_TIME64__))
     unsigned long int __uclibc_unused1;
+#endif
+#if defined(__UCLIBC_USE_TIME64__)
+    unsigned long int __shm_dtime_internal_1;
+    unsigned long int __shm_dtime_internal_2;
+#else
     __time_t shm_dtime;			/* time of last shmdt() */
+#endif
+#if (__WORDSIZE == 32 && !defined(__ARC64_ARCH32__) && !defined(__arc__) && !defined(__arm__) && !defined(__or1k__) && !defined(__xtensa__) && !defined(__riscv) && !defined(__csky__) && !defined(__i386__) && !defined(__m68k__) && !defined(__microblaze__)) || \
+    ((defined(__ARC64_ARCH32__) || defined(__arc__) || defined(__arm__) || defined(__or1k__) || defined(__xtensa__) || defined(__riscv) || defined(__csky__) || defined(__i386__) || defined(__m68k__) || defined(__microblaze__)) && !defined(__UCLIBC_USE_TIME64__))
     unsigned long int __uclibc_unused2;
+#endif
+#if defined(__UCLIBC_USE_TIME64__)
+    unsigned long int __shm_ctime_internal_1;
+    unsigned long int __shm_ctime_internal_2;
+#else
     __time_t shm_ctime;			/* time of last change by shmctl() */
+#endif
+#if (__WORDSIZE == 32 && !defined(__ARC64_ARCH32__) && !defined(__arc__) && !defined(__arm__) && !defined(__or1k__) && !defined(__xtensa__) && !defined(__riscv) && !defined(__csky__) && !defined(__i386__) && !defined(__m68k__) && !defined(__microblaze__)) || \
+    ((defined(__ARC64_ARCH32__) || defined(__arc__) || defined(__arm__) || defined(__or1k__) || defined(__xtensa__) || defined(__riscv) || defined(__csky__) || defined(__i386__) || defined(__m68k__) || defined(__microblaze__)) && !defined(__UCLIBC_USE_TIME64__))
     unsigned long int __uclibc_unused3;
+#endif
     __pid_t shm_cpid;			/* pid of creator */
     __pid_t shm_lpid;			/* pid of last shmop */
     shmatt_t shm_nattch;		/* number of current attaches */
     unsigned long int __uclibc_unused4;
     unsigned long int __uclibc_unused5;
+#if defined(__UCLIBC_USE_TIME64__)
+    __time_t shm_atime;			/* time of last shmat() */
+    __time_t shm_dtime;			/* time of last shmdt() */
+    __time_t shm_ctime;			/* time of last change by shmctl() */
+# define __SHMID_DS_TIME64_SPLIT 1
+#endif
   };
 
 #ifdef __USE_MISC

+ 15 - 0
libc/sysdeps/linux/csky/bits/shm.h

@@ -39,17 +39,32 @@ struct shmid_ds
   {
     struct ipc_perm shm_perm;		/* operation permission struct */
     size_t shm_segsz;			/* size of segment in bytes */
+#if defined(__UCLIBC_USE_TIME64__)
+    unsigned long int __shm_atime_internal_1;
+    unsigned long int __shm_atime_internal_2;
+    unsigned long int __shm_dtime_internal_1;
+    unsigned long int __shm_dtime_internal_2;
+    unsigned long int __shm_ctime_internal_1;
+    unsigned long int __shm_ctime_internal_2;
+#else
     __time_t shm_atime;			/* time of last shmat() */
     unsigned long int __uclibc_unused1;
     __time_t shm_dtime;			/* time of last shmdt() */
     unsigned long int __uclibc_unused2;
     __time_t shm_ctime;			/* time of last change by shmctl() */
     unsigned long int __uclibc_unused3;
+#endif
     __pid_t shm_cpid;			/* pid of creator */
     __pid_t shm_lpid;			/* pid of last shmop */
     shmatt_t shm_nattch;		/* number of current attaches */
     unsigned long int __uclibc_unused4;
     unsigned long int __uclibc_unused5;
+#if defined(__UCLIBC_USE_TIME64__)
+    __time_t shm_atime;			/* time of last shmat() */
+    __time_t shm_dtime;			/* time of last shmdt() */
+    __time_t shm_ctime;			/* time of last change by shmctl() */
+# define __SHMID_DS_TIME64_SPLIT 1
+#endif
   };
 
 #ifdef __USE_MISC

+ 12 - 3
libc/sysdeps/linux/m68k/bits/shm.h

@@ -50,9 +50,12 @@ struct shmid_ds
     struct ipc_perm shm_perm;		/* operation permission struct */
     size_t shm_segsz;			/* size of segment in bytes */
 #if defined(__UCLIBC_USE_TIME64__)
-    __time_t shm_atime;
-    __time_t shm_dtime;
-    __time_t shm_ctime;
+    unsigned long int __shm_atime_internal_1;
+    unsigned long int __shm_atime_internal_2;
+    unsigned long int __shm_dtime_internal_1;
+    unsigned long int __shm_dtime_internal_2;
+    unsigned long int __shm_ctime_internal_1;
+    unsigned long int __shm_ctime_internal_2;
 #else
     __time_t shm_atime;			/* time of last shmat() */
     unsigned long int __uclibc_unused1;
@@ -66,6 +69,12 @@ struct shmid_ds
     shmatt_t shm_nattch;		/* number of current attaches */
     unsigned long int __uclibc_unused4;
     unsigned long int __uclibc_unused5;
+#if defined(__UCLIBC_USE_TIME64__)
+    __time_t shm_atime;			/* time of last shmat() */
+    __time_t shm_dtime;			/* time of last shmdt() */
+    __time_t shm_ctime;			/* time of last change by shmctl() */
+# define __SHMID_DS_TIME64_SPLIT 1
+#endif
   };
 
 #ifdef __USE_MISC