Callers could be passing arbitrarily large abstime values, we have to cap
that to the resulting timeout to the limits of the mach_msg_timeout_t type.
---
sysdeps/mach/htl/pt-timedblock.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/sysdeps/mach/htl/pt-timedblock.c b/sysdeps/mach/htl/pt-timedblock.c
index 2b51f532bd..ad92d1ad1a 100644
--- a/sysdeps/mach/htl/pt-timedblock.c
+++ b/sysdeps/mach/htl/pt-timedblock.c
@@ -39,6 +39,8 @@ __pthread_timedblock (struct __pthread *thread,
mach_msg_header_t msg;
mach_msg_timeout_t timeout;
struct timespec now;
+ time_t sec_diff;
+ mach_msg_timeout_t sec_diff_timeout, nsec_diff_timeout;
retry:
/* We have an absolute time and now we have to convert it to a
@@ -51,13 +53,23 @@ retry:
|| (now.tv_sec == abstime->tv_sec && now.tv_nsec > abstime->tv_nsec))
return ETIMEDOUT;
- timeout = (abstime->tv_sec - now.tv_sec) * 1000;
+ sec_diff = abstime->tv_sec - now.tv_sec;
if (abstime->tv_nsec >= now.tv_nsec)
- timeout += (abstime->tv_nsec - now.tv_nsec + 999999) / 1000000;
+ nsec_diff_timeout = (abstime->tv_nsec - now.tv_nsec + 999999) / 1000000;
else
- /* Need to do a carry. */
- timeout -= (now.tv_nsec - abstime->tv_nsec + 999999) / 1000000;
+ {
+ /* Need to do a carry. */
+ sec_diff--;
+ nsec_diff_timeout = (abstime->tv_nsec + 1000000000 - now.tv_nsec +
999999) / 1000000;
+ }
+
+ sec_diff_timeout = sec_diff;
+ if (sec_diff_timeout != sec_diff
+ || __builtin_mul_overflow (sec_diff_timeout, 1000u, &timeout)
+ || __builtin_add_overflow (timeout, nsec_diff_timeout, &timeout))
+ /* Overflow, use maximum expressable value. */
+ timeout = (mach_msg_timeout_t) -1;
err = __mach_msg (&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MSG_OPTIONS |
MACH_RCV_INTERRUPT, 0,
sizeof msg, thread->wakeupmsg.msgh_remote_port,
--
2.53.0