diff options
author | Erlang/OTP <otp@erlang.org> | 2021-11-11 16:32:53 +0100 |
---|---|---|
committer | Erlang/OTP <otp@erlang.org> | 2021-11-11 16:32:53 +0100 |
commit | c5004ddeacdb2813f00c5325ae6d5f9c88a273d5 (patch) | |
tree | b57beb22de5eee9c0c207ca1c17e42ba92a58e94 | |
parent | 22c3f8028770ab1d99e94fcb91f6d0f5177cb10f (diff) | |
parent | 98dec6cf320edb46a58fcc64eda4f644e75be755 (diff) | |
download | erlang-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.c | 17 | ||||
-rw-r--r-- | erts/lib_src/pthread/ethr_event.c | 26 |
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) |