From bc76d987cc5e07ef2f9fbc291c27f9a430d58f53 Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Wed, 7 May 2025 17:26:02 +0200 Subject: [PATCH 1/6] gh-46927: Prevent readline from overriding environment Readline library will set the LINES and COLUMNS environment variables during initialization. One might expect these variables to be updated later on SIGWINCH, but this is not the case with cpython. As a consequence, when the readline module is imported, any process launched from cpython with the default environment will have LINES and COLUMNS variables set, potentially to a wrong value. Use the rl_change_environment global variable to disable this initial setup of the environment variables. --- .../2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst | 2 ++ Modules/readline.c | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst new file mode 100644 index 00000000000000..e83840083e70cb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst @@ -0,0 +1,2 @@ +Prevent readline from overriding COLUMNS and LINES environment variables, as +values are not updated on terminal resize. diff --git a/Modules/readline.c b/Modules/readline.c index 0dd99dc66c08e9..52c7182e885aac 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1323,6 +1323,13 @@ setup_readline(readlinestate *mod_state) /* The name must be defined before initialization */ rl_readline_name = "python"; +#ifndef WITH_EDITLINE + /* Prevent readline from changing environment variables such as LINES and + * COLUMNS. + */ + rl_change_environment = 0; +#endif + /* the libedit readline emulation resets key bindings etc * when calling rl_initialize. So call it upfront */ From c2e4e290a3dbb68839aeb7d6dd96da1bacefe5d4 Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Thu, 8 May 2025 08:55:36 +0200 Subject: [PATCH 2/6] Disable rl_change_environment on apple --- Modules/readline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/readline.c b/Modules/readline.c index 52c7182e885aac..f60bdd33b00e2d 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1323,7 +1323,7 @@ setup_readline(readlinestate *mod_state) /* The name must be defined before initialization */ rl_readline_name = "python"; -#ifndef WITH_EDITLINE +#if !defined(__APPLE__) /* Prevent readline from changing environment variables such as LINES and * COLUMNS. */ From 23999d93f7ebdf618f7c352ca952f56a7ac4a80b Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Mon, 12 May 2025 17:49:06 +0200 Subject: [PATCH 3/6] Fix NEWS --- .../2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst index e83840083e70cb..3ba9757c8acb5d 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-18-31-31.gh-issue-46927.sF02gj.rst @@ -1,2 +1,2 @@ -Prevent readline from overriding COLUMNS and LINES environment variables, as -values are not updated on terminal resize. +Prevent :mod:`readline` from overriding the ``COLUMNS`` and ``LINES`` +environment variables, as values are not updated on terminal resize. From 31599198676fe95d2ee040f914942c3db282b023 Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Mon, 12 May 2025 17:49:20 +0200 Subject: [PATCH 4/6] Add test --- Lib/test/test_readline.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index b9d082b3597f13..a22bb9b7a57bdb 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -3,12 +3,14 @@ """ import locale import os +import subprocess import sys import tempfile import textwrap import threading import unittest from test import support +from test.support import requires_subprocess from test.support import threading_helper from test.support import verbose from test.support.import_helper import import_module @@ -405,6 +407,17 @@ def test_write_read_limited_history(self): # So, we've only tested that the read did not fail. # See TestHistoryManipulation for the full test. + @requires_subprocess() + def test_environment_is_not_modified(self): + env_output = subprocess.check_output(["env"]) + env_lines = env_output.decode('utf-8', 'surrogateescape').splitlines() + current_env = dict([line.split('=', 1) for line in env_lines]) + + changes = {k for k in set(os.environ).union(current_env) + if os.getenv(k) != current_env.get(k)} + + self.assertEqual(len(changes), 0) + @unittest.skipUnless(support.Py_GIL_DISABLED, 'these tests can only possibly fail with GIL disabled') class FreeThreadingTest(unittest.TestCase): From f14a8d6d8a8d1d656b58d87d3dadfe72c5c60eb8 Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Mon, 12 May 2025 20:10:14 +0200 Subject: [PATCH 5/6] Use os.reload_environ() in test --- Lib/test/test_readline.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index a22bb9b7a57bdb..5d0d66e685261e 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -409,14 +409,9 @@ def test_write_read_limited_history(self): @requires_subprocess() def test_environment_is_not_modified(self): - env_output = subprocess.check_output(["env"]) - env_lines = env_output.decode('utf-8', 'surrogateescape').splitlines() - current_env = dict([line.split('=', 1) for line in env_lines]) - - changes = {k for k in set(os.environ).union(current_env) - if os.getenv(k) != current_env.get(k)} - - self.assertEqual(len(changes), 0) + original_env = dict(os.environ) + os.reload_environ() + self.assertEqual(dict(os.environ), original_env) @unittest.skipUnless(support.Py_GIL_DISABLED, 'these tests can only possibly fail with GIL disabled') From a91fe5dc64f038236d4a6dc4290a0f6203f5bf7d Mon Sep 17 00:00:00 2001 From: Mathieu Dubois-Briand Date: Wed, 14 May 2025 15:39:14 +0200 Subject: [PATCH 6/6] test: remove subprocess dependency --- Lib/test/test_readline.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py index 5d0d66e685261e..6f793939fe298a 100644 --- a/Lib/test/test_readline.py +++ b/Lib/test/test_readline.py @@ -3,14 +3,12 @@ """ import locale import os -import subprocess import sys import tempfile import textwrap import threading import unittest from test import support -from test.support import requires_subprocess from test.support import threading_helper from test.support import verbose from test.support.import_helper import import_module @@ -407,7 +405,6 @@ def test_write_read_limited_history(self): # So, we've only tested that the read did not fail. # See TestHistoryManipulation for the full test. - @requires_subprocess() def test_environment_is_not_modified(self): original_env = dict(os.environ) os.reload_environ()