From 4eb39196e567605beb394204b4517eae0a73a687 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Tue, 16 Dec 2025 02:39:30 +0100 Subject: [PATCH 1/2] gh-142776: Ensure fp file descriptor is closed on all code paths in import.c --- Python/import.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Python/import.c b/Python/import.c index db433dbc971d76..4e86a7660ad9fd 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4762,6 +4762,7 @@ static PyObject * _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { + FILE *fp = NULL; PyObject *mod = NULL; PyThreadState *tstate = _PyThreadState_GET(); @@ -4804,16 +4805,12 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /* We would move this (and the fclose() below) into * _PyImport_GetModuleExportHooks(), but it isn't clear if the intervening * code relies on fp still being open. */ - FILE *fp; if (file != NULL) { fp = Py_fopen(info.filename, "r"); if (fp == NULL) { goto finally; } } - else { - fp = NULL; - } PyModInitFunction p0 = NULL; PyModExportFunction ex0 = NULL; @@ -4822,7 +4819,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) mod = import_run_modexport(tstate, ex0, &info, spec); // Modules created from slots handle GIL enablement (Py_mod_gil slot) // when they're created. - goto cleanup; + goto finally; } if (p0 == NULL) { goto finally; @@ -4845,13 +4842,10 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) } #endif -cleanup: - // XXX Shouldn't this happen in the error cases too (i.e. in "finally")? +finally: if (fp) { fclose(fp); } - -finally: _Py_ext_module_loader_info_clear(&info); return mod; } From 4504c93e122f40430022a90484171c183f35f35e Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Thu, 18 Dec 2025 01:00:41 +0100 Subject: [PATCH 2/2] fixup! gh-142776: Ensure fp file descriptor is closed on all code paths in import.c Address review comments and add a NEWS entry --- .../2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst | 1 + Python/import.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst new file mode 100644 index 00000000000000..3039b04d89cb88 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst @@ -0,0 +1 @@ +Fix a file descriptor leak in import.c diff --git a/Python/import.c b/Python/import.c index 4e86a7660ad9fd..466c5868ab7ee8 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4843,7 +4843,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) #endif finally: - if (fp) { + if (fp != NULL) { fclose(fp); } _Py_ext_module_loader_info_clear(&info);