Skip to content

Commit 3e20303

Browse files
[3.12] gh-107913: Fix possible losses of OSError error codes (GH-107930) (#108523)
gh-107913: Fix possible losses of OSError error codes (GH-107930) 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) Co-authored-by: Serhiy Storchaka <[email protected]>
1 parent bbdd889 commit 3e20303

17 files changed

+129
-75
lines changed
Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3071,8 +3071,8 @@ _curses_getwin(PyObject *module, PyObject *file)
30713071
}
30723072
datalen = PyBytes_GET_SIZE(data);
30733073
if (fwrite(PyBytes_AS_STRING(data), 1, datalen, fp) != datalen) {
3074-
Py_DECREF(data);
30753074
PyErr_SetFromErrno(PyExc_OSError);
3075+
Py_DECREF(data);
30763076
goto error;
30773077
}
30783078
Py_DECREF(data);

Modules/_io/fileio.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
394394

395395
if (async_err)
396396
goto error;
397+
398+
if (self->fd < 0) {
399+
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
400+
goto error;
401+
}
397402
}
398403
else {
399404
PyObject *fdobj;
@@ -425,12 +430,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
425430
goto error;
426431
}
427432
}
428-
429433
fd_is_own = 1;
430-
if (self->fd < 0) {
431-
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
432-
goto error;
433-
}
434434

435435
#ifndef MS_WINDOWS
436436
if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
@@ -1058,8 +1058,8 @@ _io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj)
10581058
Py_END_ALLOW_THREADS
10591059

10601060
if (ret != 0) {
1061-
Py_DECREF(posobj);
10621061
PyErr_SetFromErrno(PyExc_OSError);
1062+
Py_DECREF(posobj);
10631063
return NULL;
10641064
}
10651065

Modules/_io/winconsoleio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,8 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
378378
else
379379
self->fd = _Py_open_osfhandle_noraise(handle, _O_RDONLY | _O_BINARY);
380380
if (self->fd < 0) {
381-
CloseHandle(handle);
382381
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
382+
CloseHandle(handle);
383383
goto error;
384384
}
385385
}

Modules/_localemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,8 @@ _locale_bindtextdomain_impl(PyObject *module, const char *domain,
737737
}
738738
current_dirname = bindtextdomain(domain, dirname);
739739
if (current_dirname == NULL) {
740-
Py_XDECREF(dirname_bytes);
741740
PyErr_SetFromErrno(PyExc_OSError);
741+
Py_XDECREF(dirname_bytes);
742742
return NULL;
743743
}
744744
result = PyUnicode_DecodeLocale(current_dirname, NULL);

Modules/_multiprocessing/semaphore.c

Lines changed: 5 additions & 4 deletions
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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,8 +3889,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
38893889
/* the password callback has already set the error information */
38903890
}
38913891
else if (errno != 0) {
3892-
ERR_clear_error();
38933892
PyErr_SetFromErrno(PyExc_OSError);
3893+
ERR_clear_error();
38943894
}
38953895
else {
38963896
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -3910,8 +3910,8 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile,
39103910
/* the password callback has already set the error information */
39113911
}
39123912
else if (errno != 0) {
3913-
ERR_clear_error();
39143913
PyErr_SetFromErrno(PyExc_OSError);
3914+
ERR_clear_error();
39153915
}
39163916
else {
39173917
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -4140,8 +4140,8 @@ _ssl__SSLContext_load_verify_locations_impl(PySSLContext *self,
41404140
PySSL_END_ALLOW_THREADS
41414141
if (r != 1) {
41424142
if (errno != 0) {
4143-
ERR_clear_error();
41444143
PyErr_SetFromErrno(PyExc_OSError);
4144+
ERR_clear_error();
41454145
}
41464146
else {
41474147
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);
@@ -4188,8 +4188,8 @@ _ssl__SSLContext_load_dh_params(PySSLContext *self, PyObject *filepath)
41884188
PySSL_END_ALLOW_THREADS
41894189
if (dh == NULL) {
41904190
if (errno != 0) {
4191-
ERR_clear_error();
41924191
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, filepath);
4192+
ERR_clear_error();
41934193
}
41944194
else {
41954195
_setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__);

Modules/faulthandler.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,10 @@ faulthandler_allocate_stack(void)
414414

415415
int err = sigaltstack(&stack, &old_stack);
416416
if (err) {
417+
PyErr_SetFromErrno(PyExc_OSError);
417418
/* Release the stack to retry sigaltstack() next time */
418419
PyMem_Free(stack.ss_sp);
419420
stack.ss_sp = NULL;
420-
421-
PyErr_SetFromErrno(PyExc_OSError);
422421
return -1;
423422
}
424423
return 0;

Modules/fcntlmodule.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,12 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
211211
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
212212
memcpy(str, buf, len);
213213
}
214-
PyBuffer_Release(&pstr); /* No further access to str below this point */
215214
if (ret < 0) {
216215
PyErr_SetFromErrno(PyExc_OSError);
216+
PyBuffer_Release(&pstr);
217217
return NULL;
218218
}
219+
PyBuffer_Release(&pstr);
219220
if (mutate_arg) {
220221
return PyLong_FromLong(ret);
221222
}
@@ -240,8 +241,8 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
240241
ret = ioctl(fd, code, buf);
241242
Py_END_ALLOW_THREADS
242243
if (ret < 0) {
243-
PyBuffer_Release(&pstr);
244244
PyErr_SetFromErrno(PyExc_OSError);
245+
PyBuffer_Release(&pstr);
245246
return NULL;
246247
}
247248
PyBuffer_Release(&pstr);

Modules/getpath.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,12 @@ getpath_readlines(PyObject *Py_UNUSED(self), PyObject *args)
341341
return NULL;
342342
}
343343
FILE *fp = _Py_wfopen(path, L"rb");
344-
PyMem_Free((void *)path);
345344
if (!fp) {
346345
PyErr_SetFromErrno(PyExc_OSError);
346+
PyMem_Free((void *)path);
347347
return NULL;
348348
}
349+
PyMem_Free((void *)path);
349350

350351
r = PyList_New(0);
351352
if (!r) {

Modules/mmapmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,13 +1356,15 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
13561356
m_obj->data = mmap(NULL, map_size, prot, flags, fd, offset);
13571357
Py_END_ALLOW_THREADS
13581358

1359+
int saved_errno = errno;
13591360
if (devzero != -1) {
13601361
close(devzero);
13611362
}
13621363

13631364
if (m_obj->data == (char *)-1) {
13641365
m_obj->data = NULL;
13651366
Py_DECREF(m_obj);
1367+
errno = saved_errno;
13661368
PyErr_SetFromErrno(PyExc_OSError);
13671369
return NULL;
13681370
}

Modules/overlapped.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,9 @@ _overlapped_RegisterWaitWithQueue_impl(PyObject *module, HANDLE Object,
367367
&NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
368368
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
369369
{
370+
SetFromWindowsErr(0);
370371
PyMem_RawFree(pdata);
371-
return SetFromWindowsErr(0);
372+
return NULL;
372373
}
373374

374375
return Py_BuildValue(F_HANDLE, NewWaitObject);

0 commit comments

Comments
 (0)