Skip to content

Commit

Permalink
Prevent erroneously waiting for an unbounded time in Unix.select
Browse files Browse the repository at this point in the history
The documentation of `Unix.select _ _ _ s` reads:

> The fourth argument is the maximal timeout, in seconds; a negative
> fourth argument means no timeout (unbounded wait).

This fixes a potential bug on Windows with the implementation of
`Unix.select`. If a file descriptor list exceeds `FD_SETSIZE` (64
elements by default), or if one of the lists contains at least one fd
that's not a socket, then [`select`][1] is emulated. In this code
path, if the timeout ends up equating the sentinel value for an
unbounded wait (`INFINITE` in the WinAPI, equal to $2^{32}$), then the
wait becomes unbounded. This breaks the semantics of
[Unix.select]. Cap the timeout to $2^{32}$ milliseconds.

[1]: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select
  • Loading branch information
MisterDA committed Dec 26, 2024
1 parent 7664ab3 commit 6b91650
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 3 deletions.
6 changes: 6 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ Working version
- #13504, #13625: Add `Thread.set_current_thread_name`.
(Romain Beauxis, review by Gabriel Scherer and Antonin Décimo)

- #13576: On Windows, prevent erroneously waiting for an unbounded time in
Unix.select if more than 64 file descriptors per lists are watched, or if
watching non-socket file descriptors, and a timeout longer than $2^{32}$
milliseconds is used. Cap the timeout to $2^{32}$ milliseconds.
(Antonin Décimo, review by Miod Vallat)

### Tools:

- #12019: ocamlc: add `align_double` and `align_int64` to `ocamlc -config`
Expand Down
3 changes: 2 additions & 1 deletion otherlibs/unix/select_win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,8 @@ CAMLprim value caml_unix_select(value readfds, value writefds, value exceptfds,

if (tm_sec >= 0.0)
{
tm_msec = (DWORD)(tm_sec * MSEC_PER_SEC);
double msec = tm_sec * MSEC_PER_SEC;
tm_msec = msec < INFINITE ? (DWORD)msec : INFINITE - 1;
DEBUG_PRINT("Will wait %d ms", tm_msec);
}
else
Expand Down
6 changes: 5 additions & 1 deletion otherlibs/unix/unix.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,11 @@ val select :
The result is composed of three sets of descriptors: those ready
for reading (first component), ready for writing (second component),
and over which an exceptional condition is pending (third
component). *)
component).
On Windows, if one of descriptor lists exceeds [FD_SETSIZE] elements
(64 by default), or if at least one non-socket file descriptor is
used, the maximal timeout is capped to 2{^32} milliseconds. *)

(** {1 Locking} *)

Expand Down
6 changes: 5 additions & 1 deletion otherlibs/unix/unixLabels.mli
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,11 @@ val select :
The result is composed of three sets of descriptors: those ready
for reading (first component), ready for writing (second component),
and over which an exceptional condition is pending (third
component). *)
component).
On Windows, if one of descriptor lists exceeds [FD_SETSIZE] elements
(64 by default), or if at least one non-socket file descriptor is
used, the maximal timeout is capped to 2{^32} milliseconds. *)

(** {1 Locking} *)

Expand Down

0 comments on commit 6b91650

Please sign in to comment.