Skip to content

gh-102494: fix MemoryError when using selectors on Solaris #102495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions Modules/selectmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,12 +790,16 @@ poll_dealloc(PyObject *op)
#ifdef HAVE_SYS_DEVPOLL_H
static PyMethodDef devpoll_methods[];

#define DEVPOLL_IN_BUFFER_SIZE 128
#define DEVPOLL_MAX_OUT_BUFFER_SIZE 1024

typedef struct {
PyObject_HEAD
int fd_devpoll;
int max_n_fds;
int n_fds;
int out_size;
struct pollfd *fds;
struct pollfd *out_fds;
} devpollObject;

#define devpollObject_CAST(op) ((devpollObject *)(op))
Expand Down Expand Up @@ -848,7 +852,7 @@ internal_devpoll_register(devpollObject *self, int fd,
self->fds[self->n_fds].fd = fd;
self->fds[self->n_fds].events = POLLREMOVE;

if (++self->n_fds == self->max_n_fds) {
if (++self->n_fds == DEVPOLL_IN_BUFFER_SIZE) {
if (devpoll_flush(self))
return NULL;
}
Expand All @@ -857,7 +861,7 @@ internal_devpoll_register(devpollObject *self, int fd,
self->fds[self->n_fds].fd = fd;
self->fds[self->n_fds].events = (signed short)events;

if (++self->n_fds == self->max_n_fds) {
if (++self->n_fds == DEVPOLL_IN_BUFFER_SIZE) {
if (devpoll_flush(self))
return NULL;
}
Expand Down Expand Up @@ -929,7 +933,7 @@ select_devpoll_unregister_impl(devpollObject *self, int fd)
self->fds[self->n_fds].fd = fd;
self->fds[self->n_fds].events = POLLREMOVE;

if (++self->n_fds == self->max_n_fds) {
if (++self->n_fds == DEVPOLL_IN_BUFFER_SIZE) {
if (devpoll_flush(self))
return NULL;
}
Expand Down Expand Up @@ -989,8 +993,8 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
if (devpoll_flush(self))
return NULL;

dvp.dp_fds = self->fds;
dvp.dp_nfds = self->max_n_fds;
dvp.dp_fds = self->out_fds;
dvp.dp_nfds = self->out_size;
dvp.dp_timeout = (int)ms;

if (timeout >= 0) {
Expand Down Expand Up @@ -1034,8 +1038,8 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
return NULL;

for (i = 0; i < poll_result; i++) {
num1 = PyLong_FromLong(self->fds[i].fd);
num2 = PyLong_FromLong(self->fds[i].revents);
num1 = PyLong_FromLong(self->out_fds[i].fd);
num2 = PyLong_FromLong(self->out_fds[i].revents);
if ((num1 == NULL) || (num2 == NULL)) {
Py_XDECREF(num1);
Py_XDECREF(num2);
Expand Down Expand Up @@ -1128,12 +1132,12 @@ static devpollObject *
newDevPollObject(PyObject *module)
{
devpollObject *self;
int fd_devpoll, limit_result;
struct pollfd *fds;
int fd_devpoll, limit_result, out_size;
struct pollfd *fds, *out_fds;
struct rlimit limit;

/*
** If we try to process more that getrlimit()
** If we try to process more than getrlimit()
** fds, the kernel will give an error, so
** we set the limit here. It is a dynamic
** value, because we can change rlimit() anytime.
Expand All @@ -1144,27 +1148,46 @@ newDevPollObject(PyObject *module)
return NULL;
}

/*
** If the limit is too high (or RLIM_INFINITY), we might
** allocate huge amounts of memory or even fail to allocate.
*/
out_size = limit.rlim_cur;
if (out_size > DEVPOLL_MAX_OUT_BUFFER_SIZE) {
out_size = DEVPOLL_MAX_OUT_BUFFER_SIZE;
}

fd_devpoll = _Py_open("/dev/poll", O_RDWR);
if (fd_devpoll == -1)
return NULL;

fds = PyMem_NEW(struct pollfd, limit.rlim_cur);
fds = PyMem_NEW(struct pollfd, DEVPOLL_IN_BUFFER_SIZE);
if (fds == NULL) {
close(fd_devpoll);
PyErr_NoMemory();
return NULL;
}

out_fds = PyMem_NEW(struct pollfd, out_size);
if (fds == NULL) {
close(fd_devpoll);
PyMem_Free(fds);
PyErr_NoMemory();
return NULL;
}

self = PyObject_New(devpollObject, get_select_state(module)->devpoll_Type);
if (self == NULL) {
close(fd_devpoll);
PyMem_Free(fds);
PyMem_Free(out_fds);
return NULL;
}
self->fd_devpoll = fd_devpoll;
self->max_n_fds = limit.rlim_cur;
self->n_fds = 0;
self->fds = fds;
self->out_size = out_size;
self->out_fds = out_fds;

return self;
}
Expand All @@ -1176,6 +1199,7 @@ devpoll_dealloc(PyObject *op)
PyTypeObject *type = Py_TYPE(self);
(void)devpoll_internal_close(self);
PyMem_Free(self->fds);
PyMem_Free(self->out_fds);
PyObject_Free(self);
Py_DECREF(type);
}
Expand Down
Loading