Skip to content

Commit b0d3a6b

Browse files
committed
Issue #10350: Read and save errno before calling a function which might overwrite it.
Original patch by Hallvard B Furuseth.
2 parents 6e84b34 + 732f234 commit b0d3a6b

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
@@ -419,6 +419,9 @@ Core and Builtins
419419
Library
420420
-------
421421

422+
- Issue #10350: Read and save errno before calling a function which might
423+
overwrite it. Original patch by Hallvard B Furuseth.
424+
422425
- Issue #11610: Introduce a more general way to declare abstract properties.
423426

424427
- Issue #13591: A bug in importlib has been fixed that caused import_module

Modules/_io/fileio.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ fileio_readinto(fileio *self, PyObject *args)
530530
{
531531
Py_buffer pbuf;
532532
Py_ssize_t n, len;
533+
int err;
533534

534535
if (self->fd < 0)
535536
return err_closed();
@@ -553,10 +554,12 @@ fileio_readinto(fileio *self, PyObject *args)
553554
Py_END_ALLOW_THREADS
554555
} else
555556
n = -1;
557+
err = errno;
556558
PyBuffer_Release(&pbuf);
557559
if (n < 0) {
558-
if (errno == EAGAIN)
560+
if (err == EAGAIN)
559561
Py_RETURN_NONE;
562+
errno = err;
560563
PyErr_SetFromErrno(PyExc_IOError);
561564
return NULL;
562565
}
@@ -726,9 +729,11 @@ fileio_read(fileio *self, PyObject *args)
726729
n = -1;
727730

728731
if (n < 0) {
732+
int err = errno;
729733
Py_DECREF(bytes);
730-
if (errno == EAGAIN)
734+
if (err == EAGAIN)
731735
Py_RETURN_NONE;
736+
errno = err;
732737
PyErr_SetFromErrno(PyExc_IOError);
733738
return NULL;
734739
}
@@ -748,6 +753,7 @@ fileio_write(fileio *self, PyObject *args)
748753
{
749754
Py_buffer pbuf;
750755
Py_ssize_t n, len;
756+
int err;
751757

752758
if (self->fd < 0)
753759
return err_closed();
@@ -778,12 +784,14 @@ fileio_write(fileio *self, PyObject *args)
778784
Py_END_ALLOW_THREADS
779785
} else
780786
n = -1;
787+
err = errno;
781788

782789
PyBuffer_Release(&pbuf);
783790

784791
if (n < 0) {
785-
if (errno == EAGAIN)
792+
if (err == EAGAIN)
786793
Py_RETURN_NONE;
794+
errno = err;
787795
PyErr_SetFromErrno(PyExc_IOError);
788796
return NULL;
789797
}

Modules/_multiprocessing/semaphore.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
255255
static PyObject *
256256
semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
257257
{
258-
int blocking = 1, res;
258+
int blocking = 1, res, err = 0;
259259
double timeout;
260260
PyObject *timeout_obj = Py_None;
261261
struct timespec deadline = {0};
@@ -301,11 +301,13 @@ semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
301301
else
302302
res = sem_timedwait(self->handle, &deadline);
303303
Py_END_ALLOW_THREADS
304+
err = errno;
304305
if (res == MP_EXCEPTION_HAS_BEEN_SET)
305306
break;
306307
} while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
307308

308309
if (res < 0) {
310+
errno = err;
309311
if (errno == EAGAIN || errno == ETIMEDOUT)
310312
Py_RETURN_FALSE;
311313
else if (errno == EINTR)

Modules/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,13 +655,14 @@ Py_Main(int argc, wchar_t **argv)
655655
if (fp == NULL) {
656656
char *cfilename_buffer;
657657
const char *cfilename;
658+
int err = errno;
658659
cfilename_buffer = _Py_wchar2char(filename, NULL);
659660
if (cfilename_buffer != NULL)
660661
cfilename = cfilename_buffer;
661662
else
662663
cfilename = "<unprintable file name>";
663664
fprintf(stderr, "%ls: can't open file '%s': [Errno %d] %s\n",
664-
argv[0], cfilename, errno, strerror(errno));
665+
argv[0], cfilename, err, strerror(err));
665666
if (cfilename_buffer)
666667
PyMem_Free(cfilename_buffer);
667668
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;
@@ -969,7 +971,7 @@ readline_until_enter_or_signal(char *prompt, int *signal)
969971
completed_input_string = not_done_reading;
970972

971973
while (completed_input_string == not_done_reading) {
972-
int has_input = 0;
974+
int has_input = 0, err = 0;
973975

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

989-
if(has_input > 0) {
992+
if (has_input > 0) {
990993
rl_callback_read_char();
991994
}
992-
else if (errno == EINTR) {
995+
else if (err == EINTR) {
993996
int s;
994997
#ifdef WITH_THREAD
995998
PyEval_RestoreThread(_PyOS_ReadlineTState);

Modules/timemodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,12 +515,14 @@ time_strftime(PyObject *self, PyObject *args)
515515
* will be ahead of time...
516516
*/
517517
for (i = 1024; ; i += i) {
518+
int err;
518519
outbuf = (time_char *)PyMem_Malloc(i*sizeof(time_char));
519520
if (outbuf == NULL) {
520521
PyErr_NoMemory();
521522
break;
522523
}
523524
buflen = format_time(outbuf, i, fmt, &buf);
525+
err = errno;
524526
if (buflen > 0 || i >= 256 * fmtlen) {
525527
/* If the buffer is 256 times as long as the format,
526528
it's probably not failing for lack of room!
@@ -538,7 +540,7 @@ time_strftime(PyObject *self, PyObject *args)
538540
PyMem_Free(outbuf);
539541
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
540542
/* VisualStudio .NET 2005 does this properly */
541-
if (buflen == 0 && errno == EINVAL) {
543+
if (buflen == 0 && err == EINVAL) {
542544
PyErr_SetString(PyExc_ValueError, "Invalid format string");
543545
break;
544546
}

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)