Browse Source

libc: the SysV IPC pad words depend on the word size, not on the arch

sem and tst-semctl fail on riscv64 with everything after the first time
field shifted:

  sem_nsems: 0
  sem_otime: Thu Jan  1 00:00:00 1970
  sem_ctime: Thu Jan  1 00:00:01 1970

sem_ctime reads the word holding sem_nsems, which is 1, hence one second
past the epoch; sem_nsems reads a pad word.  The cause is the second
half of the condition guarding the pad:

  #if (__WORDSIZE == 32 && !defined(__arc__) && ... && !defined(__riscv) ...) || \
      ((defined(__arc__) || ... || defined(__riscv) || ...) && !defined(__UCLIBC_USE_TIME64__))

which does not test the word size at all.  __riscv is the only entry in
that list that is also defined on a 64-bit target -- __arm__, __m68k__,
__i386__, __xtensa__, __csky__, __or1k__, __microblaze__ and __arc__ are
32-bit only -- so riscv64 inherited a rule meant for riscv32 and got the
32-bit pad words in a 64-bit structure.

The kernel splits each time value into a low and a high word on 32-bit
targets only (asm-generic/{sem,msg,shm}buf.h); on 64-bit ones the field
is a single long.  So both the pads and the TIME64 halves depend on
__WORDSIZE, and the architecture list was only ever the set of 32-bit
targets with TIME64 enabled.  Say that instead:

  #if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)   /* pad */
  #if __WORDSIZE == 32 && defined(__UCLIBC_USE_TIME64__)    /* halves */

msq.h had no word-size test on its pads at all, which is why riscv64,
aarch64 and kvx all carry a wrong msqid_ds today -- silently, because
tst-msgctl only checks msg_stime and that one happens to land right.

Verified by compiling a translation unit per architecture that asserts
the field offsets against the kernel's own headers, before and after:

  riscv64  (64 bit, no TIME64)   8 fields wrong -> all pass
             sem_ctime, sem_nsems, msg_rtime, msg_ctime,
             msg_cbytes, msg_qnum, msg_qbytes, msg_lspid
  riscv32  (32 bit, TIME64)      pass -> pass
  m68k     (32 bit, TIME64)      pass -> pass

Only the 64-bit cases change, which are exactly the broken ones.

Signed-off-by: Ramin Moussavi <lordrasmus@gmail.com>
ramin 1 week ago
parent
commit
3848522a99

+ 10 - 0
libc/sysdeps/linux/common/bits/msq.h

@@ -34,6 +34,10 @@ typedef unsigned long int msglen_t;
 
 /* Structure of record for one message inside the kernel.
    The type `struct msg' is opaque.  */
+
+/* The kernel keeps the upper half of each time field in a separate word on
+   32-bit targets -- see asm-generic/msgbuf.h -- and a single long on 64-bit
+   ones, where the pad words below must not exist.  */
 struct msqid_ds
 {
   struct ipc_perm msg_perm;	/* structure describing operation permission */
@@ -46,11 +50,17 @@ struct msqid_ds
   unsigned long int msg_ctime_internal_2;
 #else
   __time_t msg_stime;		/* time of last msgsnd command */
+# if __WORDSIZE == 32
   unsigned long int __uclibc_unused1;
+# endif
   __time_t msg_rtime;		/* time of last msgrcv command */
+# if __WORDSIZE == 32
   unsigned long int __uclibc_unused2;
+# endif
   __time_t msg_ctime;		/* time of last change */
+# if __WORDSIZE == 32
   unsigned long int __uclibc_unused3;
+# endif
 #endif
   unsigned long int __msg_cbytes; /* current number of bytes on queue */
   msgqnum_t msg_qnum;		/* number of messages currently on queue */

+ 8 - 8
libc/sysdeps/linux/common/bits/sem.h

@@ -35,32 +35,32 @@
 #define SETALL		17		/* set all semval's */
 
 
-/* Data structure describing a set of semaphores.  */
+/* The kernel splits each time field into a low and a high word on 32-bit
+   targets only -- see asm-generic/sembuf.h -- and keeps a single long on
+   64-bit ones.  */
 struct semid_ds
 {
   struct ipc_perm sem_perm;		/* operation permission struct */
-#if defined(__UCLIBC_USE_TIME64__)
+#if __WORDSIZE == 32 && defined(__UCLIBC_USE_TIME64__)
   unsigned long int __sem_otime_internal_1;
   unsigned long int __sem_otime_internal_2;
 #else
   __time_t sem_otime;			/* last semop() time */
 #endif
-#if (__WORDSIZE == 32 && !defined(__ARC64_ARCH32__) && !defined(__arc__) && !defined(__arm__) && !defined(__or1k__) && !defined(__xtensa__) && !defined(__riscv) && !defined(__csky__) && !defined(__i386__) && !defined(__microblaze__) && !defined(__m68k__)) || \
-    ((defined(__ARC64_ARCH32__) || defined(__arc__) || defined(__arm__) || defined(__or1k__) || defined(__xtensa__) || defined(__riscv) || defined(__csky__) || defined(__i386__) || defined(__microblaze__) || defined(__m68k__)) && !defined(__UCLIBC_USE_TIME64__))
+#if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)
   unsigned long int __uclibc_unused1;
 #endif
-#if defined(__UCLIBC_USE_TIME64__)
+#if __WORDSIZE == 32 && defined(__UCLIBC_USE_TIME64__)
   unsigned long int __sem_ctime_internal_1;
   unsigned long int __sem_ctime_internal_2;
 #else
   __time_t sem_ctime;			/* last time changed by semctl() */
 #endif
-#if (__WORDSIZE == 32 && !defined(__ARC64_ARCH32__) && !defined(__arc__) && !defined(__arm__) && !defined(__or1k__) && !defined(__xtensa__) && !defined(__riscv) && !defined(__csky__) && !defined(__i386__) && !defined(__microblaze__) && !defined(__m68k__)) || \
-    ((defined(__ARC64_ARCH32__) || defined(__arc__) || defined(__arm__) || defined(__or1k__) || defined(__xtensa__) || defined(__riscv) || defined(__csky__) || defined(__i386__) || defined(__microblaze__) || defined(__m68k__)) && !defined(__UCLIBC_USE_TIME64__))
+#if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)
   unsigned long int __uclibc_unused2;
 #endif
   unsigned long int sem_nsems;		/* number of semaphores in set */
-#if defined(__UCLIBC_USE_TIME64__)
+#if __WORDSIZE == 32 && defined(__UCLIBC_USE_TIME64__)
   __time_t sem_otime;			/* last semop() time */
   __time_t sem_ctime;			/* last time changed by semctl() */
 #endif

+ 7 - 10
libc/sysdeps/linux/common/bits/shm.h

@@ -49,34 +49,31 @@ 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__)
+#if __WORDSIZE == 32 && 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__))
+#if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)
     unsigned long int __uclibc_unused1;
 #endif
-#if defined(__UCLIBC_USE_TIME64__)
+#if __WORDSIZE == 32 && 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__))
+#if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)
     unsigned long int __uclibc_unused2;
 #endif
-#if defined(__UCLIBC_USE_TIME64__)
+#if __WORDSIZE == 32 && 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__))
+#if __WORDSIZE == 32 && !defined(__UCLIBC_USE_TIME64__)
     unsigned long int __uclibc_unused3;
 #endif
     __pid_t shm_cpid;			/* pid of creator */
@@ -84,7 +81,7 @@ 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__)
+#if __WORDSIZE == 32 && 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() */