From f65bb64e689952c02c930b46f71ebf0cd606426a Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 15:16:49 +0500 Subject: [PATCH 01/14] gh-157741: Prevent NULL 'environ' pointer after os.environ.clear() --- Lib/test/test_os/test_os.py | 12 ++++++++++++ .../Library/2026-09-18-14-30-00.gh-issue-157741.rst | 1 + Modules/posixmodule.c | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 81b3043eb7e75b..679a7b88ee3e20 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -1693,6 +1693,18 @@ def test_clearenv(self): self.assertRaises(TypeError, os.environ.clear, None) + def test_clearenv_environ_not_null(self): + import ctypes + os.environ.clear() + try: + c_environ = ctypes.c_void_p.in_dll(ctypes.CDLL(None), "environ") + self.assertIsNotNone( + c_environ.value, + "os.environ.clear() set the C 'environ' pointer to NULL" + ) + except AttributeError: + pass + class WalkTests(unittest.TestCase): """Tests for os.walk().""" diff --git a/Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst b/Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst new file mode 100644 index 00000000000000..cbe9cbca6a1910 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst @@ -0,0 +1 @@ +Fix crash in third-party C libraries (such as Tcl/Tk) after :func:`os.environ.clear` by ensuring the C ``environ`` pointer is not left as ``NULL``. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ead2371e341441..3838cd9239c148 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13893,7 +13893,8 @@ os_unsetenv_impl(PyObject *module, PyObject *name) } #endif /* !MS_WINDOWS */ - +static char *empty_environ[] = { NULL }; +/*NR8889*/ #ifdef HAVE_CLEARENV /*[clinic input] os._clearenv @@ -13912,6 +13913,12 @@ os__clearenv_impl(PyObject *module) if (err) { return posix_error(); } + + /* glibc's clearenv() sets 'environ' to NULL. Point it to a static empty + array to prevent crashes in third-party C libraries (e.g. Tcl/Tk) + that access 'environ' without a NULL check. */ + environ = empty_environ; + Py_RETURN_NONE; } #endif From 10b8d02361e9e5ae6e12a5071b09049333aadf0e Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 15:32:18 +0500 Subject: [PATCH 02/14] Fix NEWS filename and code formatting --- ...0-00.gh-issue-157741.rst => 2026-09-18-15-30-00.GH-157741.rst} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Misc/NEWS.d/next/Library/{2026-09-18-14-30-00.gh-issue-157741.rst => 2026-09-18-15-30-00.GH-157741.rst} (100%) diff --git a/Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst b/Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst similarity index 100% rename from Misc/NEWS.d/next/Library/2026-09-18-14-30-00.gh-issue-157741.rst rename to Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst From 5c50640c56a5df07b3365bca7162a5eb5e542058 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 15:39:13 +0500 Subject: [PATCH 03/14] Fix code style and remove extra comments in posixmodule.c --- Modules/posixmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3838cd9239c148..cc15121e5cf0b6 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13894,7 +13894,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #endif /* !MS_WINDOWS */ static char *empty_environ[] = { NULL }; -/*NR8889*/ + #ifdef HAVE_CLEARENV /*[clinic input] os._clearenv From 6c7fce27c2acbc4334e62af68556d476c7b6e5b5 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 15:53:48 +0500 Subject: [PATCH 04/14] Address review comments: refine test and C code structure --- Lib/test/test_os/test_os.py | 17 ++++++++--------- Modules/posixmodule.c | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 679a7b88ee3e20..4f6c6902f81725 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -1694,16 +1694,15 @@ def test_clearenv(self): self.assertRaises(TypeError, os.environ.clear, None) def test_clearenv_environ_not_null(self): - import ctypes + from test.support import import_helper + ctypes = import_helper.import_module('ctypes') + os.environ.clear() - try: - c_environ = ctypes.c_void_p.in_dll(ctypes.CDLL(None), "environ") - self.assertIsNotNone( - c_environ.value, - "os.environ.clear() set the C 'environ' pointer to NULL" - ) - except AttributeError: - pass + c_environ = ctypes.c_void_p.in_dll(ctypes.CDLL(None), "environ") + self.assertIsNotNone( + c_environ.value, + "os.environ.clear() set the C 'environ' pointer to NULL" + ) class WalkTests(unittest.TestCase): diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index cc15121e5cf0b6..0e7484c697e414 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13893,9 +13893,10 @@ os_unsetenv_impl(PyObject *module, PyObject *name) } #endif /* !MS_WINDOWS */ -static char *empty_environ[] = { NULL }; #ifdef HAVE_CLEARENV +static char *empty_environ[] = { NULL }; + /*[clinic input] os._clearenv [clinic start generated code]*/ From 41384b7a656d7c40df9ae09e75be5630f93c9933 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 16:03:04 +0500 Subject: [PATCH 05/14] Add NEWS entry via blurb --- .../Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst diff --git a/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst b/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst new file mode 100644 index 00000000000000..66566e7c42b641 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst @@ -0,0 +1,3 @@ +Fix crash in third-party C libraries (such as Tcl/Tk) after +:func:`os.environ.clear` by ensuring the C ``environ`` pointer is not left +as ``NULL``. From 9ac53bab693323cbf12ca9ba813c9ab94911ddf9 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 17:17:26 +0500 Subject: [PATCH 06/14] Remove duplicate news entry and update clinic files --- Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst diff --git a/Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst b/Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst deleted file mode 100644 index cbe9cbca6a1910..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-09-18-15-30-00.GH-157741.rst +++ /dev/null @@ -1 +0,0 @@ -Fix crash in third-party C libraries (such as Tcl/Tk) after :func:`os.environ.clear` by ensuring the C ``environ`` pointer is not left as ``NULL``. From ce9ac7328eed9a8a71717317c854b9e365c2d6c2 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 18:07:55 +0500 Subject: [PATCH 07/14] Fix news entry via blurb --- .../Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst | 3 --- .../Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst create mode 100644 Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst diff --git a/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst b/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst deleted file mode 100644 index 66566e7c42b641..00000000000000 --- a/Misc/NEWS.d/next/Library/2026-09-18-16-02-25.gh-issue-157741.wlKs4b.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix crash in third-party C libraries (such as Tcl/Tk) after -:func:`os.environ.clear` by ensuring the C ``environ`` pointer is not left -as ``NULL``. diff --git a/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst b/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst new file mode 100644 index 00000000000000..f3cb25f5ccb9f4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst @@ -0,0 +1,2 @@ +Fix crash in C libraries after os.environ.clear() by ensuring environ +pointer is not left as NULL. From b45a8a91f86efaeca04c6f8e09524daf333c4322 Mon Sep 17 00:00:00 2001 From: Arnold Date: Fri, 18 Sep 2026 21:55:58 +0500 Subject: [PATCH 08/14] Update Lib/test/test_os/test_os.py Co-authored-by: An Long --- Lib/test/test_os/test_os.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 4f6c6902f81725..425d168237da5f 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -1693,6 +1693,7 @@ def test_clearenv(self): self.assertRaises(TypeError, os.environ.clear, None) + @requires_os_func('_clearenv') def test_clearenv_environ_not_null(self): from test.support import import_helper ctypes = import_helper.import_module('ctypes') From 4f48d9e4cebb38a94baa19f874d8c08703af5b5a Mon Sep 17 00:00:00 2001 From: Arnold Date: Fri, 18 Sep 2026 21:56:45 +0500 Subject: [PATCH 09/14] Update Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst Co-authored-by: An Long --- .../Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst b/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst index f3cb25f5ccb9f4..cc50930d77afce 100644 --- a/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst +++ b/Misc/NEWS.d/next/Library/2026-09-18-18-07-38.gh-issue-157741.Bbt18o.rst @@ -1,2 +1,2 @@ -Fix crash in C libraries after os.environ.clear() by ensuring environ -pointer is not left as NULL. +Fix crash in C libraries after :meth:`!os.environ.clear` by ensuring ``environ`` +pointer is not left as ``NULL``. From 1e5cc742c72d33692cf300ca85020296c68edaaa Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 22:12:30 +0500 Subject: [PATCH 10/14] Move import_helper to top-level imports in test_os.py --- Lib/test/test_os/test_os.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py index 425d168237da5f..3349d06f9d5c6e 100644 --- a/Lib/test/test_os/test_os.py +++ b/Lib/test/test_os/test_os.py @@ -38,6 +38,7 @@ from test.support import requires_non_root_user from test.support import threading_helper from test.support import warnings_helper +from test.support import import_helper from platform import win32_is_iot from .utils import create_file @@ -1695,7 +1696,6 @@ def test_clearenv(self): @requires_os_func('_clearenv') def test_clearenv_environ_not_null(self): - from test.support import import_helper ctypes = import_helper.import_module('ctypes') os.environ.clear() From ec7d6ed4fcc364f8b3ddb320d27218d4a4fb0883 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Fri, 18 Sep 2026 23:45:17 +0500 Subject: [PATCH 11/14] Fix c-analyzer failure by declaring empty_environ as const --- Modules/posixmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0e7484c697e414..3c9c4b706b1bce 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13895,7 +13895,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #ifdef HAVE_CLEARENV -static char *empty_environ[] = { NULL }; +static char * const empty_environ[] = { NULL }; /*[clinic input] os._clearenv @@ -13918,7 +13918,7 @@ os__clearenv_impl(PyObject *module) /* glibc's clearenv() sets 'environ' to NULL. Point it to a static empty array to prevent crashes in third-party C libraries (e.g. Tcl/Tk) that access 'environ' without a NULL check. */ - environ = empty_environ; + environ = (char **)empty_environ; Py_RETURN_NONE; } From 53c0aef449787e32dd89808567f65fda72e5ac52 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Sat, 19 Sep 2026 11:25:07 +0500 Subject: [PATCH 12/14] Fix check-c-globals by adding empty_environ to ignored.tsv --- Modules/posixmodule.c | 2 +- Tools/c-analyzer/cpython/ignored.tsv | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 3c9c4b706b1bce..65c2cdd9f01239 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13895,7 +13895,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #ifdef HAVE_CLEARENV -static char * const empty_environ[] = { NULL }; +static const char * const empty_environ[] = { NULL }; /*[clinic input] os._clearenv diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index cddfeb02c4b859..773cd0212c1f62 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -794,3 +794,4 @@ Modules/_testcapi/unicode.c test_py_identifier real_id - ## False positives Python/specialize.c - _Py_InitCleanup - Python/pystate.c - _no_tstate_sentinel - +Modules/posixmodule.c - empty_environ - From 7807950b0bc19fc2e25dad49834082298a0a4c5d Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Sat, 19 Sep 2026 11:46:04 +0500 Subject: [PATCH 13/14] Fix check-c-globals by adding empty_environ to ignored.tsv --- Tools/c-analyzer/cpython/ignored.tsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 773cd0212c1f62..2654fed2e0b31d 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -794,4 +794,4 @@ Modules/_testcapi/unicode.c test_py_identifier real_id - ## False positives Python/specialize.c - _Py_InitCleanup - Python/pystate.c - _no_tstate_sentinel - -Modules/posixmodule.c - empty_environ - +Modules/posixmodule.c - empty_environ - From 9b7218b0c749c7aa1b4224ba6ac0aae214523b36 Mon Sep 17 00:00:00 2001 From: search1ofall-maker Date: Sat, 19 Sep 2026 20:46:22 +0500 Subject: [PATCH 14/14] Simplify empty_environ type and alphabetize entry in ignored.tsv --- Modules/posixmodule.c | 4 ++-- Tools/c-analyzer/cpython/ignored.tsv | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 65c2cdd9f01239..0e7484c697e414 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13895,7 +13895,7 @@ os_unsetenv_impl(PyObject *module, PyObject *name) #ifdef HAVE_CLEARENV -static const char * const empty_environ[] = { NULL }; +static char *empty_environ[] = { NULL }; /*[clinic input] os._clearenv @@ -13918,7 +13918,7 @@ os__clearenv_impl(PyObject *module) /* glibc's clearenv() sets 'environ' to NULL. Point it to a static empty array to prevent crashes in third-party C libraries (e.g. Tcl/Tk) that access 'environ' without a NULL check. */ - environ = (char **)empty_environ; + environ = empty_environ; Py_RETURN_NONE; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 2654fed2e0b31d..08f01bab93c7ae 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -719,6 +719,7 @@ Modules/_sqlite/module.c - pysqlite_BaseTypeAdapted - Modules/_sqlite/module.h - pysqlite_global_state - Modules/_testcapimodule.c - _PyBytesIOBuffer_Type - Modules/posixmodule.c - _Py_open_cloexec_works - +Modules/posixmodule.c - empty_environ - Modules/posixmodule.c - environ - Objects/object.c - _Py_GenericAliasIterType - Objects/object.c - _PyMemoryIter_Type - @@ -794,4 +795,3 @@ Modules/_testcapi/unicode.c test_py_identifier real_id - ## False positives Python/specialize.c - _Py_InitCleanup - Python/pystate.c - _no_tstate_sentinel - -Modules/posixmodule.c - empty_environ -