Skip to content

Commit c345ce1

Browse files
committed
Issue #10350: Read and save errno before calling a function which might overwrite it.
Original patch by Hallvard B Furuseth.
1 parent 8744881 commit c345ce1

7 files changed

Lines changed: 33 additions & 12 deletions

File tree

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ Core and Builtins
9797
Library
9898
-------
9999

100+
- Issue #10350: Read and save errno before calling a function which might
101+
overwrite it. Original patch by Hallvard B Furuseth.
102+
100103
- Issue #13591: A bug in importlib has been fixed that caused import_module
101104
to load a module twice.
102105

Modules/_io/fileio.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ fileio_readinto(fileio *self, PyObject *args)
506506
{
507507
Py_buffer pbuf;
508508
Py_ssize_t n, len;
509+
int err;
509510

510511
if (self->fd < 0)
511512
return err_closed();
@@ -529,10 +530,12 @@ fileio_readinto(fileio *self, PyObject *args)
529530
Py_END_ALLOW_THREADS
530531
} else
531532
n = -1;
533+
err = errno;
532534
PyBuffer_Release(&pbuf);
533535
if (n < 0) {
534-
if (errno == EAGAIN)
536+
if (err == EAGAIN)
535537
Py_RETURN_NONE;
538+
errno = err;
536539
PyErr_SetFromErrno(PyExc_IOError);
537540
return NULL;
538541
}
@@ -675,9 +678,11 @@ fileio_read(fileio *self, PyObject *args)
675678
n = -1;
676679

677680
if (n < 0) {
681+
int err = errno;
678682
Py_DECREF(bytes);
679-
if (errno == EAGAIN)
683+
if (err == EAGAIN)
680684
Py_RETURN_NONE;
685+
errno = err;
681686
PyErr_SetFromErrno(PyExc_IOError);
682687
return NULL;
683688
}
@@ -697,6 +702,7 @@ fileio_write(fileio *self, PyObject *args)
697702
{
698703
Py_buffer pbuf;
699704
Py_ssize_t n, len;
705+
int err;
700706

701707
if (self->fd < 0)
702708
return err_closed();
@@ -727,12 +733,14 @@ fileio_write(fileio *self, PyObject *args)
727733
Py_END_ALLOW_THREADS
728734
} else
729735
n = -1;
736+
err = errno;
730737

731738
PyBuffer_Release(&pbuf);
732739

733740
if (n < 0) {
734-
if (errno == EAGAIN)
741+
if (err == EAGAIN)
735742
Py_RETURN_NONE;
743+
errno = err;
736744
PyErr_SetFromErrno(PyExc_IOError);
737745
return NULL;
738746
}

Modules/_multiprocessing/semaphore.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
267267
static PyObject *
268268
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
269269
{
270-
int blocking = 1, res;
270+
int blocking = 1, res, err = 0;
271271
double timeout;
272272
PyObject *timeout_obj = Py_None;
273273
struct timespec deadline = {0};
@@ -313,11 +313,13 @@ semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
313313
else
314314
res = sem_timedwait(self->handle, &deadline);
315315
Py_END_ALLOW_THREADS
316+
err = errno;
316317
if (res == MP_EXCEPTION_HAS_BEEN_SET)
317318
break;
318319
} while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
319320

320321
if (res < 0) {
322+
errno = err;
321323
if (errno == EAGAIN || errno == ETIMEDOUT)
322324
Py_RETURN_FALSE;
323325
else if (errno == EINTR)

Modules/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,13 +654,14 @@ Py_Main(int argc, wchar_t **argv)
654654
if (fp == NULL) {
655655
char *cfilename_buffer;
656656
const char *cfilename;
657+
int err = errno;
657658
cfilename_buffer = _Py_wchar2char(filename, NULL);
658659
if (cfilename_buffer != NULL)
659660
cfilename = cfilename_buffer;
660661
else
661662
cfilename = "<unprintable file name>";
662663
fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n",
663-
argv[0], cfilename, errno, strerror(errno));
664+
argv[0], cfilename, err, strerror(err));
664665
if (cfilename_buffer)
665666
PyMem_Free(cfilename_buffer);
666667
return 2;

Modules/readline.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ write_history_file(PyObject *self, PyObject *args)
154154
{
155155
PyObject *filename_obj = Py_None, *filename_bytes;
156156
char *filename;
157+
int err;
157158
if (!PyArg_ParseTuple(args, "|O:write_history_file", &filename_obj))
158159
return NULL;
159160
if (filename_obj != Py_None) {
@@ -164,10 +165,11 @@ write_history_file(PyObject *self, PyObject *args)
164165
filename_bytes = NULL;
165166
filename = NULL;
166167
}
167-
errno = write_history(filename);
168-
if (!errno && _history_length >= 0)
168+
errno = err = write_history(filename);
169+
if (!err && _history_length >= 0)
169170
history_truncate_file(filename, _history_length);
170171
Py_XDECREF(filename_bytes);
172+
errno = err;
171173
if (errno)
172174
return PyErr_SetFromErrno(PyExc_IOError);
173175
Py_RETURN_NONE;
@@ -970,7 +972,7 @@ readline_until_enter_or_signal(char *prompt, int *signal)
970972
completed_input_string = not_done_reading;
971973

972974
while (completed_input_string == not_done_reading) {
973-
int has_input = 0;
975+
int has_input = 0, err = 0;
974976

975977
while (!has_input)
976978
{ struct timeval timeout = {0, 100000}; /* 0.1 seconds */
@@ -984,13 +986,14 @@ readline_until_enter_or_signal(char *prompt, int *signal)
984986
/* select resets selectset if no input was available */
985987
has_input = select(fileno(rl_instream) + 1, &selectset,
986988
NULL, NULL, timeoutp);
989+
err = errno;
987990
if(PyOS_InputHook) PyOS_InputHook();
988991
}
989992

990-
if(has_input > 0) {
993+
if (has_input > 0) {
991994
rl_callback_read_char();
992995
}
993-
else if (errno == EINTR) {
996+
else if (err == EINTR) {
994997
int s;
995998
#ifdef WITH_THREAD
996999
PyEval_RestoreThread(_PyOS_ReadlineTState);

Modules/timemodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,14 @@ time_strftime(PyObject *self, PyObject *args)
527527
* will be ahead of time...
528528
*/
529529
for (i = 1024; ; i += i) {
530+
int err;
530531
outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char));
531532
if (outbuf == NULL) {
532533
PyErr_NoMemory();
533534
break;
534535
}
535536
buflen = format_time(outbuf, i, fmt, &buf);
537+
err = errno;
536538
if (buflen > 0 || i >= 256 * fmtlen) {
537539
/* If the buffer is 256 times as long as the format,
538540
it's probably not failing for lack of room!
@@ -550,7 +552,7 @@ time_strftime(PyObject *self, PyObject *args)
550552
PyMem_Free(outbuf);
551553
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
552554
/* VisualStudio .NET 2005 does this properly */
553-
if (buflen == 0 && errno == EINVAL) {
555+
if (buflen == 0 && err == EINVAL) {
554556
PyErr_SetString(PyExc_ValueError, "Invalid format string");
555557
break;
556558
}

Parser/myreadline.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ static int
3636
my_fgets(char *buf, int len, FILE *fp)
3737
{
3838
char *p;
39+
int err;
3940
while (1) {
4041
if (PyOS_InputHook != NULL)
4142
(void)(PyOS_InputHook)();
@@ -44,6 +45,7 @@ my_fgets(char *buf, int len, FILE *fp)
4445
p = fgets(buf, len, fp);
4546
if (p != NULL)
4647
return 0; /* No error */
48+
err = errno;
4749
#ifdef MS_WINDOWS
4850
/* In the case of a Ctrl+C or some other external event
4951
interrupting the operation:
@@ -78,7 +80,7 @@ my_fgets(char *buf, int len, FILE *fp)
7880
return -1; /* EOF */
7981
}
8082
#ifdef EINTR
81-
if (errno == EINTR) {
83+
if (err == EINTR) {
8284
int s;
8385
#ifdef WITH_THREAD
8486
PyEval_RestoreThread(_PyOS_ReadlineTState);

0 commit comments

Comments
 (0)