Skip to content

Commit b9fc536

Browse files
[3.11] gh-107913: Fix possible losses of OSError error codes (GH-107930) (GH-108524)
Functions like PyErr_SetFromErrno() and SetFromWindowsErr() should be called immediately after using the C API which sets errno or the Windows error code. (cherry picked from commit 2b15536)
1 parent 8a275f7 commit b9fc536

17 files changed

+129
-77
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix possible losses of ``errno`` and ``winerror`` values in :exc:`OSError`
2+
exceptions if they were cleared or modified by the cleanup code before
3+
creating the exception object.

Modules/_cursesmodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3075,8 +3075,8 @@ _curses_getwin(PyObject *module, PyObject *file)
30753075
}
30763076
datalen = PyBytes_GET_SIZE(data);
30773077
if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) {
3078-
Py_DECREF(data);
30793078
PyErr_SetFromErrno(PyExc_OSError);
3079+
Py_DECREF(data);
30803080
goto error;
30813081
}
30823082
Py_DECREF(data);

Modules/_io/fileio.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ _Py_COMP_DIAG_POP
389389

390390
if (async_err)
391391
goto error;
392+
393+
if (self->fd < 0) {
394+
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
395+
goto error;
396+
}
392397
}
393398
else {
394399
PyObject *fdobj;
@@ -420,12 +425,7 @@ _Py_COMP_DIAG_POP
420425
goto error;
421426
}
422427
}
423-
424428
fd_is_own = 1;
425-
if (self->fd < 0) {
426-
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
427-
goto error;
428-
}
429429

430430
#ifndef MS_WINDOWS
431431
if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
@@ -1044,8 +1044,8 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
10441044
Py_END_ALLOW_THREADS
10451045

10461046
if (ret != 0) {
1047-
Py_DECREF(posobj);
10481047
PyErr_SetFromErrno(PyExc_OSError);
1048+
Py_DECREF(posobj);
10491049
return NULL;
10501050
}
10511051

Modules/_io/winconsoleio.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
368368
else
369369
self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY);
370370
if (self->fd < 0) {
371-
CloseHandle(handle);
372371
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
372+
CloseHandle(handle);
373373
goto error;
374374
}
375375
}

Modules/_localemodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -735,8 +735,8 @@ _locale_bindtextdomain_impl(PyObject *module, const char *domain,
735735
}
736736
current_dirname = bindtextdomain(domain, dirname);
737737
if (current_dirname == NULL) {
738-
Py_XDECREF(dirname_bytes);
739738
PyErr_SetFromErrno(PyExc_OSError);
739+
Py_XDECREF(dirname_bytes);
740740
return NULL;
741741
}
742742
result = PyUnicode_DecodeLocale(current_dirname, NULL);

Modules/_multiprocessing/semaphore.c

+5-4
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,12 @@ _multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
516516
return result;
517517

518518
failure:
519-
if (handle != SEM_FAILED)
520-
SEM_CLOSE(handle);
521-
PyMem_Free(name_copy);
522519
if (!PyErr_Occurred()) {
523520
_PyMp_SetError(NULL, MP_STANDARD_ERROR);
524521
}
522+
if (handle != SEM_FAILED)
523+
SEM_CLOSE(handle);
524+
PyMem_Free(name_copy);
525525
return NULL;
526526
}
527527

@@ -556,8 +556,9 @@ _multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
556556
if (name != NULL) {
557557
handle = sem_open(name, 0);
558558
if (handle == SEM_FAILED) {
559+
PyErr_SetFromErrno(PyExc_OSError);
559560
PyMem_Free(name_copy);
560-
return PyErr_SetFromErrno(PyExc_OSError);
561+
return NULL;
561562
}
562563
}
563564
#endif

Modules/_ssl.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -3898,8 +3898,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
38983898
/* the password callback has already set the error information */
38993899
}
39003900
else if (errno != 0) {
3901-
ERR_clear_error();
39023901
PyErr_SetFromErrno(PyExc_OSError);
3902+
ERR_clear_error();
39033903
}
39043904
else {
39053905
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -3919,8 +3919,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
39193919
/* the password callback has already set the error information */
39203920
}
39213921
else if (errno != 0) {
3922-
ERR_clear_error();
39233922
PyErr_SetFromErrno(PyExc_OSError);
3923+
ERR_clear_error();
39243924
}
39253925
else {
39263926
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -4147,8 +4147,8 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self,
41474147
PySSL_END_ALLOW_THREADS
41484148
if (r != 1) {
41494149
if (errno != 0) {
4150-
ERR_clear_error();
41514150
PyErr_SetFromErrno(PyExc_OSError);
4151+
ERR_clear_error();
41524152
}
41534153
else {
41544154
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -4195,8 +4195,8 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath)
41954195
PySSL_END_ALLOW_THREADS
41964196
if (dh == NULL) {
41974197
if (errno != 0) {
4198-
ERR_clear_error();
41994198
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
4199+
ERR_clear_error();
42004200
}
42014201
else {
42024202
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);

Modules/faulthandler.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -469,11 +469,10 @@ faulthandler_allocate_stack(void)
469469

470470
int err = sigaltstack(&stack, &old_stack);
471471
if (err) {
472+
PyErr_SetFromErrno(PyExc_OSError);
472473
/* Release the stack to retry sigaltstack() next time */
473474
PyMem_Free(stack.ss_sp);
474475
stack.ss_sp = NULL;
475-
476-
PyErr_SetFromErrno(PyExc_OSError);
477476
return -1;
478477
}
479478
return 0;

Modules/fcntlmodule.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,12 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
208208
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
209209
memcpy(str, buf, len);
210210
}
211-
PyBuffer_Release(&pstr); /* No further access to str below this point */
212211
if (ret < 0) {
213212
PyErr_SetFromErrno(PyExc_OSError);
213+
PyBuffer_Release(&pstr);
214214
return NULL;
215215
}
216+
PyBuffer_Release(&pstr);
216217
if (mutate_arg) {
217218
return PyLong_FromLong(ret);
218219
}
@@ -237,8 +238,8 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
237238
ret = ioctl(fd, code, buf);
238239
Py_END_ALLOW_THREADS
239240
if (ret < 0) {
240-
PyBuffer_Release(&pstr);
241241
PyErr_SetFromErrno(PyExc_OSError);
242+
PyBuffer_Release(&pstr);
242243
return NULL;
243244
}
244245
PyBuffer_Release(&pstr);

Modules/getpath.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,12 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
347347
return NULL;
348348
}
349349
FILE *fp = _Py_wfopen(path, L"rb");
350-
PyMem_Free((void *)path);
351350
if (!fp) {
352351
PyErr_SetFromErrno(PyExc_OSError);
352+
PyMem_Free((void *)path);
353353
return NULL;
354354
}
355+
PyMem_Free((void *)path);
355356

356357
r = PyList_New(0);
357358
if (!r) {

Modules/mmapmodule.c

+2
Original file line numberDiff line numberDiff line change
@@ -1366,13 +1366,15 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
13661366
prot, flags,
13671367
fd, offset);
13681368

1369+
int saved_errno = errno;
13691370
if (devzero != -1) {
13701371
close(devzero);
13711372
}
13721373

13731374
if (m_obj->data == (char *)-1) {
13741375
m_obj->data = NULL;
13751376
Py_DECREF(m_obj);
1377+
errno = saved_errno;
13761378
PyErr_SetFromErrno(PyExc_OSError);
13771379
return NULL;
13781380
}

Modules/overlapped.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,9 @@ _overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
365365
&NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
366366
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
367367
{
368+
SetFromWindowsErr(0);
368369
PyMem_RawFree(pdata);
369-
return SetFromWindowsErr(0);
370+
return NULL;
370371
}
371372

372373
return Py_BuildValue(F_HANDLE, NewWaitObject);

0 commit comments

Comments
 (0)