The implementation of the FUTEX_WAIT option in futex(2) is subtly broken.
authorkettenis <kettenis@openbsd.org>
Fri, 21 May 2021 16:52:42 +0000 (16:52 +0000)
committerkettenis <kettenis@openbsd.org>
Fri, 21 May 2021 16:52:42 +0000 (16:52 +0000)
Unfortunately libc and libpthread rely on the broken behaviour.  Adjust
the code in those libraries such that it works with both the old and the
proposed new behaviour.  The kernel changes that fix the issue will be
committed in a week or so to give those who do their own builds a chance
to update these libraries before we make the change.

ok mpi@, deraadt@

lib/libc/thread/synch.h
lib/librthread/synch.h

index aaeb965..91b5001 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: synch.h,v 1.5 2020/07/06 13:33:06 pirofti Exp $ */
+/*     $OpenBSD: synch.h,v 1.6 2021/05/21 16:52:42 kettenis Exp $ */
 /*
  * Copyright (c) 2017 Martin Pieuchot
  *
@@ -29,12 +29,17 @@ static inline int
 _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs)
 {
        struct timespec rel;
+       int error;
 
-       if (abs == NULL)
-               return futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
+       if (abs == NULL) {
+               error = futex(p, FUTEX_WAIT_PRIVATE, val, NULL, NULL);
+               if (error == -1)
+                       error = errno;
+               return error;
+       }
 
        if (abs->tv_nsec >= 1000000000 || WRAP(clock_gettime)(clockid, &rel))
-               return (EINVAL);
+               return EINVAL;
 
        rel.tv_sec = abs->tv_sec - rel.tv_sec;
        if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) {
@@ -42,9 +47,12 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
                rel.tv_nsec += 1000000000;
        }
        if (rel.tv_sec < 0)
-               return (ETIMEDOUT);
+               return ETIMEDOUT;
 
-       return futex(p, FUTEX_WAIT_PRIVATE, val, &rel, NULL);
+       error = futex(p, FUTEX_WAIT_PRIVATE, val, &rel, NULL);
+       if (error == -1)
+               error = errno;
+       return error;
 }
 
 static inline int
index 381ed1b..e5c623e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: synch.h,v 1.6 2019/10/24 12:32:18 sthen Exp $ */
+/*     $OpenBSD: synch.h,v 1.7 2021/05/21 16:52:42 kettenis Exp $ */
 /*
  * Copyright (c) 2017 Martin Pieuchot
  *
@@ -36,12 +36,17 @@ static inline int
 _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *abs)
 {
        struct timespec rel;
+       int error;
 
-       if (abs == NULL)
-               return futex(p, FUTEX_WAIT, val, NULL, NULL);
+       if (abs == NULL) {
+               error = futex(p, FUTEX_WAIT, val, NULL, NULL);
+               if (error == -1)
+                       error = errno;
+               return error;
+       }
 
        if (abs->tv_nsec >= 1000000000 || clock_gettime(clockid, &rel))
-               return (EINVAL);
+               return EINVAL;
 
        rel.tv_sec = abs->tv_sec - rel.tv_sec;
        if ((rel.tv_nsec = abs->tv_nsec - rel.tv_nsec) < 0) {
@@ -49,9 +54,12 @@ _twait(volatile uint32_t *p, int val, clockid_t clockid, const struct timespec *
                rel.tv_nsec += 1000000000;
        }
        if (rel.tv_sec < 0)
-               return (ETIMEDOUT);
+               return ETIMEDOUT;
 
-       return futex(p, FUTEX_WAIT, val, &rel, NULL);
+       error = futex(p, FUTEX_WAIT, val, &rel, NULL);
+       if (error == -1)
+               error = errno;
+       return error;
 }
 
 static inline int