From 173afbac0719ddb7b5184b7ab35c6fc25d91b757 Mon Sep 17 00:00:00 2001 From: kettenis Date: Fri, 21 May 2021 16:52:42 +0000 Subject: [PATCH] The implementation of the FUTEX_WAIT option in futex(2) is subtly broken. 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 | 20 ++++++++++++++------ lib/librthread/synch.h | 20 ++++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/libc/thread/synch.h b/lib/libc/thread/synch.h index aaeb965956a..91b5001c515 100644 --- a/lib/libc/thread/synch.h +++ b/lib/libc/thread/synch.h @@ -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 diff --git a/lib/librthread/synch.h b/lib/librthread/synch.h index 381ed1b1749..e5c623e87a0 100644 --- a/lib/librthread/synch.h +++ b/lib/librthread/synch.h @@ -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 -- 2.20.1