summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2021-11-11 16:32:53 +0100
committerErlang/OTP <otp@erlang.org>2021-11-11 16:32:53 +0100
commitc5004ddeacdb2813f00c5325ae6d5f9c88a273d5 (patch)
treeb57beb22de5eee9c0c207ca1c17e42ba92a58e94
parent22c3f8028770ab1d99e94fcb91f6d0f5177cb10f (diff)
parent98dec6cf320edb46a58fcc64eda4f644e75be755 (diff)
downloaderlang-c5004ddeacdb2813f00c5325ae6d5f9c88a273d5.tar.gz
Merge branch 'rickard/select-timeout-fix/GH-5339/OTP-17735' into maint-22
* rickard/select-timeout-fix/GH-5339/OTP-17735: Limit timeout value in calls to select()
-rw-r--r--erts/emulator/sys/common/erl_poll.c17
-rw-r--r--erts/lib_src/pthread/ethr_event.c26
2 files changed, 41 insertions, 2 deletions
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 5a8318dce2..9af4ec65fc 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -71,6 +71,12 @@
# define _DARWIN_UNLIMITED_SELECT
#endif
+/*
+ * According to posix, select() implementations should
+ * support a max timeout value of at least 31 days.
+ */
+#define ERTS_SELECT_MAX_TV_SEC__ (31*24*60*60-1)
+
#ifndef WANT_NONBLOCKING
# define WANT_NONBLOCKING
#endif
@@ -1753,6 +1759,17 @@ get_timeout_timeval(ErtsPollSet *ps,
}
else {
ErtsMonotonicTime sec = timeout/(1000*1000);
+ if (sec >= ERTS_SELECT_MAX_TV_SEC__) {
+ tvp->tv_sec = ERTS_SELECT_MAX_TV_SEC__;
+ tvp->tv_usec = 0;
+ /*
+ * If we actually should time out on
+ * this (huge) timeout, the select() call
+ * will be restarted with a newly calculated
+ * timeout after verifying the timeout...
+ */
+ return 1;
+ }
tvp->tv_sec = sec;
tvp->tv_usec = timeout - sec*(1000*1000);
diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c
index 9d6e26fd81..57450448c4 100644
--- a/erts/lib_src/pthread/ethr_event.c
+++ b/erts/lib_src/pthread/ethr_event.c
@@ -36,6 +36,12 @@
# define _DARWIN_UNLIMITED_SELECT
#endif
+/*
+ * According to posix, select() implementations should
+ * support a max timeout value of at least 31 days.
+ */
+#define ETHR_SELECT_MAX_TV_SEC__ (31*24*60*60-1)
+
#include "ethread.h"
#undef ETHR_INCLUDE_MONOTONIC_CLOCK__
#define ETHR_INCLUDE_MONOTONIC_CLOCK__
@@ -500,6 +506,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
#endif
fd_set *rsetp, *esetp;
struct timeval select_timeout;
+ int select_timeout_res;
#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
#if ERTS_USE_PREMATURE_TIMEOUT
@@ -527,7 +534,22 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
#endif
select_timeout.tv_sec = time / (1000*1000);
- select_timeout.tv_usec = time % (1000*1000);
+
+ if (select_timeout.tv_sec <= ETHR_SELECT_MAX_TV_SEC__) {
+ select_timeout.tv_usec = time % (1000*1000);
+ select_timeout_res = ETIMEDOUT;
+ }
+ else {
+ select_timeout.tv_sec = ETHR_SELECT_MAX_TV_SEC__;
+ select_timeout.tv_usec = 0;
+ /*
+ * Return EINTR (spurious wakeup) instead of
+ * ETIMEDOUT if we time out on this (huge)
+ * timeout value. Caller is responsible for
+ * restarting the wait...
+ */
+ select_timeout_res = EINTR;
+ }
ETHR_ASSERT(val != ETHR_EVENT_ON__);
@@ -577,7 +599,7 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
sres = select(fd + 1, rsetp, NULL, esetp, &select_timeout);
if (sres == 0)
- res = ETIMEDOUT;
+ res = select_timeout_res;
else {
res = EINTR;
if (sres < 0 && errno != EINTR)