Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 66aab0c

Browse files
committed
Issue #23708: Add _Py_read() and _Py_write() functions to factorize code handle
EINTR error and special cases for Windows. These functions now truncate the length to PY_SSIZE_T_MAX to have a portable and reliable behaviour. For example, read() result is undefined if counter is greater than PY_SSIZE_T_MAX on Linux.
1 parent 9eb57c5 commit 66aab0c

5 files changed

Lines changed: 201 additions & 169 deletions

File tree

Include/fileutils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ PyAPI_FUNC(FILE*) _Py_fopen_obj(
8080
PyObject *path,
8181
const char *mode);
8282

83+
PyAPI_FUNC(Py_ssize_t) _Py_read(
84+
int fd,
85+
void *buf,
86+
size_t count);
87+
88+
PyAPI_FUNC(Py_ssize_t) _Py_write(
89+
int fd,
90+
const void *buf,
91+
size_t count);
92+
8393
#ifdef HAVE_READLINK
8494
PyAPI_FUNC(int) _Py_wreadlink(
8595
const wchar_t *path,

Modules/_io/fileio.c

Lines changed: 31 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ static PyObject *
570570
fileio_readinto(fileio *self, PyObject *args)
571571
{
572572
Py_buffer pbuf;
573-
Py_ssize_t n, len;
574-
int err, async_err = 0;
573+
Py_ssize_t n;
574+
int err;
575575

576576
if (self->fd < 0)
577577
return err_closed();
@@ -581,36 +581,16 @@ fileio_readinto(fileio *self, PyObject *args)
581581
if (!PyArg_ParseTuple(args, "w*", &pbuf))
582582
return NULL;
583583

584-
if (_PyVerify_fd(self->fd)) {
585-
len = pbuf.len;
586-
#ifdef MS_WINDOWS
587-
if (len > INT_MAX)
588-
len = INT_MAX;
589-
#endif
590-
591-
do {
592-
Py_BEGIN_ALLOW_THREADS
593-
errno = 0;
594-
#ifdef MS_WINDOWS
595-
n = read(self->fd, pbuf.buf, (int)len);
596-
#else
597-
n = read(self->fd, pbuf.buf, len);
598-
#endif
599-
Py_END_ALLOW_THREADS
600-
} while (n < 0 && errno == EINTR &&
601-
!(async_err = PyErr_CheckSignals()));
602-
603-
if (async_err)
604-
return NULL;
605-
} else
606-
n = -1;
584+
n = _Py_read(self->fd, pbuf.buf, pbuf.len);
585+
/* copy errno because PyBuffer_Release() can indirectly modify it */
607586
err = errno;
608587
PyBuffer_Release(&pbuf);
609-
if (n < 0) {
610-
if (err == EAGAIN)
588+
589+
if (n == -1) {
590+
if (err == EAGAIN) {
591+
PyErr_Clear();
611592
Py_RETURN_NONE;
612-
errno = err;
613-
PyErr_SetFromErrno(PyExc_IOError);
593+
}
614594
return NULL;
615595
}
616596

@@ -645,9 +625,8 @@ fileio_readall(fileio *self)
645625
Py_off_t pos, end;
646626
PyObject *result;
647627
Py_ssize_t bytes_read = 0;
648-
Py_ssize_t len, n;
628+
Py_ssize_t n;
649629
size_t bufsize;
650-
int async_err = 0;
651630

652631
if (self->fd < 0)
653632
return err_closed();
@@ -695,36 +674,21 @@ fileio_readall(fileio *self)
695674
}
696675
}
697676

698-
len = bufsize - bytes_read;
699-
#ifdef MS_WINDOWS
700-
if (len > INT_MAX)
701-
len = INT_MAX;
702-
#endif
703-
do {
704-
Py_BEGIN_ALLOW_THREADS
705-
errno = 0;
706-
#ifdef MS_WINDOWS
707-
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)len);
708-
#else
709-
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, len);
710-
#endif
711-
Py_END_ALLOW_THREADS
712-
} while (n < 0 && errno == EINTR &&
713-
!(async_err = PyErr_CheckSignals()));
677+
n = _Py_read(self->fd,
678+
PyBytes_AS_STRING(result) + bytes_read,
679+
bufsize - bytes_read);
714680

715-
if (async_err)
716-
return NULL;
717681
if (n == 0)
718682
break;
719-
if (n < 0) {
683+
if (n == -1) {
720684
if (errno == EAGAIN) {
685+
PyErr_Clear();
721686
if (bytes_read > 0)
722687
break;
723688
Py_DECREF(result);
724689
Py_RETURN_NONE;
725690
}
726691
Py_DECREF(result);
727-
PyErr_SetFromErrno(PyExc_IOError);
728692
return NULL;
729693
}
730694
bytes_read += n;
@@ -756,7 +720,6 @@ fileio_read(fileio *self, PyObject *args)
756720
char *ptr;
757721
Py_ssize_t n;
758722
Py_ssize_t size = -1;
759-
int async_err = 0;
760723
PyObject *bytes;
761724

762725
if (self->fd < 0)
@@ -767,44 +730,29 @@ fileio_read(fileio *self, PyObject *args)
767730
if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
768731
return NULL;
769732

770-
if (size < 0) {
733+
if (size < 0)
771734
return fileio_readall(self);
772-
}
773735

774736
#ifdef MS_WINDOWS
737+
/* On Windows, the count parameter of read() is an int */
775738
if (size > INT_MAX)
776739
size = INT_MAX;
777740
#endif
741+
778742
bytes = PyBytes_FromStringAndSize(NULL, size);
779743
if (bytes == NULL)
780744
return NULL;
781745
ptr = PyBytes_AS_STRING(bytes);
782746

783-
if (_PyVerify_fd(self->fd)) {
784-
do {
785-
Py_BEGIN_ALLOW_THREADS
786-
errno = 0;
787-
#ifdef MS_WINDOWS
788-
n = read(self->fd, ptr, (int)size);
789-
#else
790-
n = read(self->fd, ptr, size);
791-
#endif
792-
Py_END_ALLOW_THREADS
793-
} while (n < 0 && errno == EINTR &&
794-
!(async_err = PyErr_CheckSignals()));
795-
796-
if (async_err)
797-
return NULL;
798-
} else
799-
n = -1;
800-
801-
if (n < 0) {
747+
n = _Py_read(self->fd, ptr, size);
748+
if (n == -1) {
749+
/* copy errno because Py_DECREF() can indirectly modify it */
802750
int err = errno;
803751
Py_DECREF(bytes);
804-
if (err == EAGAIN)
752+
if (err == EAGAIN) {
753+
PyErr_Clear();
805754
Py_RETURN_NONE;
806-
errno = err;
807-
PyErr_SetFromErrno(PyExc_IOError);
755+
}
808756
return NULL;
809757
}
810758

@@ -822,8 +770,8 @@ static PyObject *
822770
fileio_write(fileio *self, PyObject *args)
823771
{
824772
Py_buffer pbuf;
825-
Py_ssize_t n, len;
826-
int err, async_err = 0;
773+
Py_ssize_t n;
774+
int err;
827775

828776
if (self->fd < 0)
829777
return err_closed();
@@ -833,44 +781,16 @@ fileio_write(fileio *self, PyObject *args)
833781
if (!PyArg_ParseTuple(args, "y*", &pbuf))
834782
return NULL;
835783

836-
if (_PyVerify_fd(self->fd)) {
837-
len = pbuf.len;
838-
#ifdef MS_WINDOWS
839-
if (len > 32767 && isatty(self->fd)) {
840-
/* Issue #11395: the Windows console returns an error (12: not
841-
enough space error) on writing into stdout if stdout mode is
842-
binary and the length is greater than 66,000 bytes (or less,
843-
depending on heap usage). */
844-
len = 32767;
845-
} else if (len > INT_MAX)
846-
len = INT_MAX;
847-
#endif
848-
849-
do {
850-
Py_BEGIN_ALLOW_THREADS
851-
errno = 0;
852-
#ifdef MS_WINDOWS
853-
n = write(self->fd, pbuf.buf, (int)len);
854-
#else
855-
n = write(self->fd, pbuf.buf, len);
856-
#endif
857-
Py_END_ALLOW_THREADS
858-
} while (n < 0 && errno == EINTR &&
859-
!(async_err = PyErr_CheckSignals()));
860-
861-
if (async_err)
862-
return NULL;
863-
} else
864-
n = -1;
784+
n = _Py_write(self->fd, pbuf.buf, pbuf.len);
785+
/* copy errno because PyBuffer_Release() can indirectly modify it */
865786
err = errno;
866-
867787
PyBuffer_Release(&pbuf);
868788

869789
if (n < 0) {
870-
if (err == EAGAIN)
790+
if (err == EAGAIN) {
791+
PyErr_Clear();
871792
Py_RETURN_NONE;
872-
errno = err;
873-
PyErr_SetFromErrno(PyExc_IOError);
793+
}
874794
return NULL;
875795
}
876796

Modules/posixmodule.c

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11207,37 +11207,27 @@ os_read_impl(PyModuleDef *module, int fd, Py_ssize_t length)
1120711207
/*[clinic end generated code: output=1f3bc27260a24968 input=1df2eaa27c0bf1d3]*/
1120811208
{
1120911209
Py_ssize_t n;
11210-
int async_err = 0;
1121111210
PyObject *buffer;
1121211211

1121311212
if (length < 0) {
1121411213
errno = EINVAL;
1121511214
return posix_error();
1121611215
}
11217-
if (!_PyVerify_fd(fd))
11218-
return posix_error();
1121911216

1122011217
#ifdef MS_WINDOWS
11221-
#define READ_CAST (int)
11218+
/* On Windows, the count parameter of read() is an int */
1122211219
if (length > INT_MAX)
1122311220
length = INT_MAX;
11224-
#else
11225-
#define READ_CAST
1122611221
#endif
1122711222

1122811223
buffer = PyBytes_FromStringAndSize((char *)NULL, length);
1122911224
if (buffer == NULL)
1123011225
return NULL;
1123111226

11232-
do {
11233-
Py_BEGIN_ALLOW_THREADS
11234-
n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length);
11235-
Py_END_ALLOW_THREADS
11236-
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11237-
11238-
if (n < 0) {
11227+
n = _Py_read(fd, PyBytes_AS_STRING(buffer), length);
11228+
if (n == -1) {
1123911229
Py_DECREF(buffer);
11240-
return (!async_err) ? posix_error() : NULL;
11230+
return NULL;
1124111231
}
1124211232

1124311233
if (n != length)
@@ -11541,33 +11531,7 @@ static Py_ssize_t
1154111531
os_write_impl(PyModuleDef *module, int fd, Py_buffer *data)
1154211532
/*[clinic end generated code: output=aeb96acfdd4d5112 input=3207e28963234f3c]*/
1154311533
{
11544-
Py_ssize_t size;
11545-
int async_err = 0;
11546-
Py_ssize_t len = data->len;
11547-
11548-
if (!_PyVerify_fd(fd)) {
11549-
posix_error();
11550-
return -1;
11551-
}
11552-
11553-
do {
11554-
Py_BEGIN_ALLOW_THREADS
11555-
#ifdef MS_WINDOWS
11556-
if (len > INT_MAX)
11557-
len = INT_MAX;
11558-
size = write(fd, data->buf, (int)len);
11559-
#else
11560-
size = write(fd, data->buf, len);
11561-
#endif
11562-
Py_END_ALLOW_THREADS
11563-
} while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
11564-
11565-
if (size < 0) {
11566-
if (!async_err)
11567-
posix_error();
11568-
return -1;
11569-
}
11570-
return size;
11534+
return _Py_write(fd, data->buf, data->len);
1157111535
}
1157211536

1157311537
#ifdef HAVE_SENDFILE

Objects/fileobject.c

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -383,26 +383,15 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
383383
Py_RETURN_NONE;
384384
}
385385

386-
if (!PyArg_ParseTuple(args, "s", &c)) {
386+
if (!PyArg_ParseTuple(args, "s", &c))
387387
return NULL;
388-
}
389-
n = strlen(c);
390388

391-
Py_BEGIN_ALLOW_THREADS
392-
errno = 0;
393-
#ifdef MS_WINDOWS
394-
if (n > INT_MAX)
395-
n = INT_MAX;
396-
n = write(self->fd, c, (int)n);
397-
#else
398-
n = write(self->fd, c, n);
399-
#endif
400-
Py_END_ALLOW_THREADS
401-
402-
if (n < 0) {
403-
if (errno == EAGAIN)
389+
n = _Py_write(self->fd, c, strlen(c));
390+
if (n == -1) {
391+
if (errno == EAGAIN) {
392+
PyErr_Clear();
404393
Py_RETURN_NONE;
405-
PyErr_SetFromErrno(PyExc_IOError);
394+
}
406395
return NULL;
407396
}
408397

0 commit comments

Comments
 (0)