Skip to content

Commit 777ad47

Browse files
author
kalibera
committed
Report error when file descriptor number is too large for select() in socket
code or when there are too many descriptors (PR#18634). git-svn-id: https://svn.r-project.org/R/trunk@85689 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 521a8a7 commit 777ad47

File tree

4 files changed

+75
-3
lines changed

4 files changed

+75
-3
lines changed

src/main/connections.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@
8787
8888
Using a dynamic upper limit would not be hard, but not very useful
8989
because of the non-dynamic fd limit.
90+
91+
The current implementation of socket connections uses select(). On
92+
POSIX systems, only FD_SETSIZE descriptors are supported and they
93+
must have numbers between 0 and FD_SETSIZE-1, inclusive. On Linux and macOS,
94+
FD_SETSIZE is normally 1024. On macOS, the limit could be overcome via
95+
_DARWIN_UNLIMITED_SELECT (not used by R), but a POSIX solution would
96+
be to use poll() instead of select(). On Windows, by default 1024 different
97+
descriptors are supported in a single select() call, but these include
98+
valid socket file descriptors of arbitrary numbers, much larger
99+
than FD_SETSIZE. On Windows, the limit can be set in the program
100+
by setting FD_SETSIZE before including WinSock headers, R sets it to
101+
1024 (in sock.h and here in connections.c).
90102
*/
91103

92104
#ifdef HAVE_CONFIG_H
@@ -6323,6 +6335,13 @@ attribute_hidden SEXP do_sockselect(SEXP call, SEXP op, SEXP args, SEXP rho)
63236335
int nsock, i;
63246336
SEXP insock, write, val, insockfd;
63256337
double timeout;
6338+
int fdlim;
6339+
6340+
#ifdef Win32
6341+
fdlim = 1024; /* keep in step with sock.h */
6342+
#else
6343+
fdlim = FD_SETSIZE;
6344+
#endif
63266345

63276346
checkArity(op, args);
63286347

@@ -6358,8 +6377,16 @@ attribute_hidden SEXP do_sockselect(SEXP call, SEXP op, SEXP args, SEXP rho)
63586377
warning(_("a server socket connection cannot be writeable"));
63596378
} else
63606379
error(_("not a socket connection"));
6380+
#ifdef Unix
6381+
if (INTEGER(insockfd)[i] >= fdlim && !immediate)
6382+
error(_("file descriptor is too large for select()"));
6383+
#endif
63616384
}
63626385

6386+
#ifdef Win32
6387+
if (nsock > fdlim && !immediate)
6388+
error(_("too many file descriptors for select()"));
6389+
#endif
63636390
if (! immediate)
63646391
Rsockselect(nsock, INTEGER(insockfd), LOGICAL(val), LOGICAL(write),
63656392
timeout);

src/modules/internet/Rsock.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* R : A Computer Language for Statistical Data Analysis
33
4-
* Copyright (C) 1998-2021 The R Core Team
4+
* Copyright (C) 1998-2023 The R Core Team
55
* Copyright (C) 1996, 1997 Robert Gentleman and Ross Ihaka
66
*
77
* This program is free software; you can redistribute it and/or modify
@@ -196,6 +196,7 @@ setSelectMask(InputHandler *handlers, fd_set *readMask)
196196

197197
while(tmp) {
198198
if(tmp->fileDescriptor > 0) {
199+
/* FD_SETSIZE limit checked by addInputHandler */
199200
FD_SET(tmp->fileDescriptor, readMask);
200201
maxfd = maxfd < tmp->fileDescriptor ? tmp->fileDescriptor : maxfd;
201202
}
@@ -237,6 +238,8 @@ static int R_SocketWait(int sockfd, int write, int timeout)
237238
set_timeval(&tv, timeout);
238239

239240
#ifdef Unix
241+
if (sockfd >= FD_SETSIZE)
242+
return -EINVAL;
240243
maxfd = setSelectMask(R_InputHandlers, &rfd);
241244
#else
242245
FD_ZERO(&rfd);
@@ -324,7 +327,15 @@ int R_SocketWaitMultiple(int nsock, int *insockfd, int *ready, int *write,
324327
FD_ZERO(&rfd);
325328
#endif
326329
FD_ZERO(&wfd);
330+
#ifdef Win32
331+
if (nsock > FD_SETSIZE)
332+
return -WSAEINVAL;
333+
#endif
327334
for (i = 0; i < nsock; i++) {
335+
#ifdef Unix
336+
if (insockfd[i] >= FD_SETSIZE)
337+
return -EINVAL;
338+
#endif
328339
if(write[i]) FD_SET(insockfd[i], &wfd);
329340
else FD_SET(insockfd[i], &rfd);
330341
if(maxfd < insockfd[i]) maxfd = insockfd[i];
@@ -432,6 +443,10 @@ int R_SockConnect(int port, char *host, int timeout)
432443
set_timeval(&tv, timeout);
433444

434445
#ifdef Unix
446+
if (s >= FD_SETSIZE) {
447+
errno = EINVAL;
448+
CLOSE_N_RETURN(-1);
449+
}
435450
maxfd = setSelectMask(R_InputHandlers, &rfd);
436451
#else
437452
FD_ZERO(&rfd);
@@ -567,6 +582,10 @@ int R_SockListen(int sockp, char *buf, int len, int timeout)
567582
set_timeval(&tv, timeout);
568583

569584
#ifdef Unix
585+
if (sockp >= FD_SETSIZE) {
586+
errno = EINVAL;
587+
return -1;
588+
}
570589
maxfd = setSelectMask(R_InputHandlers, &rfd);
571590
#else
572591
FD_ZERO(&rfd);

src/modules/internet/sock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* R : A Computer Language for Statistical Data Analysis
33
4-
* Copyright (C) 1998-2020 The R Core Team
4+
* Copyright (C) 1998-2023 The R Core Team
55
*
66
* This program is free software; you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -42,6 +42,7 @@ ssize_t Sock_write(int fd, const void *buf, size_t nbytes, Sock_error_t perr);
4242
#ifndef Win32
4343
# define SOCKET int
4444
#else
45+
/* keep FD_SETSIZE in step with connections.c, but this is the default */
4546
# define FD_SETSIZE 1024
4647
# include<winsock2.h>
4748
#endif

src/modules/internet/sockconn.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* R : A Computer Language for Statistical Data Analysis
3-
* Copyright (C) 2001-2022 The R Core Team.
3+
* Copyright (C) 2001-2023 The R Core Team.
44
*
55
* This program is free software; you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,14 @@ static Rboolean sock_open(Rconnection con)
5555
warning("port %d cannot be opened", this->port);
5656
return FALSE;
5757
}
58+
#ifdef Unix
59+
if (sock1 >= FD_SETSIZE) {
60+
/* R_SockListen below would fail */
61+
R_SockClose(sock1);
62+
warning(_("file descriptor is too large for select()"));
63+
return FALSE;
64+
}
65+
#endif
5866
{
5967
RCNTXT cntxt;
6068

@@ -81,6 +89,14 @@ static Rboolean sock_open(Rconnection con)
8189
return FALSE;
8290
}
8391
}
92+
#ifdef Unix
93+
if (sock >= FD_SETSIZE && (con->canwrite || con->blocking)) {
94+
/* Reading/writing via such socket would fail */
95+
R_SockClose(sock);
96+
warning(_("file descriptor is too large for select()"));
97+
return FALSE;
98+
}
99+
#endif
84100
free(con->description);
85101
size_t sz = strlen(buf) + 10;
86102
con->description = (char *) malloc(sz); // FIXME check allocation
@@ -272,6 +288,15 @@ Rconnection in_R_newservsock(int port)
272288
port);
273289
/* for Solaris 12.5 */ new = NULL;
274290
}
291+
#ifdef Unix
292+
if (sock >= FD_SETSIZE) {
293+
/* R_SockListen (accept) called from sock_open would fail */
294+
free(new->private); free(new->description); free(new->class); free(new);
295+
R_SockClose(sock);
296+
error(_("file descriptor is too large for select()"));
297+
/* for Solaris 12.5 */ new = NULL;
298+
}
299+
#endif
275300
((Rservsockconn)new->private)-> fd = sock;
276301
new->isopen = TRUE;
277302

0 commit comments

Comments
 (0)