Skip to content

Commit 1c90186

Browse files
miss-islingtonyihong0618picnixz
authored
[3.14] pythongh-128636: Fix crash in PyREPL when os.environ is overwritten with an invalid value for macOS (pythonGH-138089) (python#138938)
Co-authored-by: yihong <[email protected]> Co-authored-by: Bénédikt Tran <[email protected]>
1 parent dc4d016 commit 1c90186

File tree

5 files changed

+33
-9
lines changed

5 files changed

+33
-9
lines changed

Lib/_colorize.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,21 +273,29 @@ def decolor(text: str) -> str:
273273

274274

275275
def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool:
276+
277+
def _safe_getenv(k: str, fallback: str | None = None) -> str | None:
278+
"""Exception-safe environment retrieval. See gh-128636."""
279+
try:
280+
return os.environ.get(k, fallback)
281+
except Exception:
282+
return fallback
283+
276284
if file is None:
277285
file = sys.stdout
278286

279287
if not sys.flags.ignore_environment:
280-
if os.environ.get("PYTHON_COLORS") == "0":
288+
if _safe_getenv("PYTHON_COLORS") == "0":
281289
return False
282-
if os.environ.get("PYTHON_COLORS") == "1":
290+
if _safe_getenv("PYTHON_COLORS") == "1":
283291
return True
284-
if os.environ.get("NO_COLOR"):
292+
if _safe_getenv("NO_COLOR"):
285293
return False
286294
if not COLORIZE:
287295
return False
288-
if os.environ.get("FORCE_COLOR"):
296+
if _safe_getenv("FORCE_COLOR"):
289297
return True
290-
if os.environ.get("TERM") == "dumb":
298+
if _safe_getenv("TERM") == "dumb":
291299
return False
292300

293301
if not hasattr(file, "fileno"):
@@ -330,7 +338,8 @@ def get_theme(
330338
environment (including environment variable state and console configuration
331339
on Windows) can also change in the course of the application life cycle.
332340
"""
333-
if force_color or (not force_no_color and can_colorize(file=tty_file)):
341+
if force_color or (not force_no_color and
342+
can_colorize(file=tty_file)):
334343
return _theme
335344
return theme_no_color
336345

Lib/_pyrepl/unix_console.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ def __init__(
159159
self.pollob.register(self.input_fd, select.POLLIN)
160160
self.terminfo = terminfo.TermInfo(term or None)
161161
self.term = term
162+
self.is_apple_terminal = (
163+
platform.system() == "Darwin"
164+
and os.getenv("TERM_PROGRAM") == "Apple_Terminal"
165+
)
162166

163167
@overload
164168
def _my_getstr(cap: str, optional: Literal[False] = False) -> bytes: ...
@@ -339,7 +343,7 @@ def prepare(self):
339343
tcsetattr(self.input_fd, termios.TCSADRAIN, raw)
340344

341345
# In macOS terminal we need to deactivate line wrap via ANSI escape code
342-
if platform.system() == "Darwin" and os.getenv("TERM_PROGRAM") == "Apple_Terminal":
346+
if self.is_apple_terminal:
343347
os.write(self.output_fd, b"\033[?7l")
344348

345349
self.screen = []
@@ -370,7 +374,7 @@ def restore(self):
370374
self.flushoutput()
371375
tcsetattr(self.input_fd, termios.TCSADRAIN, self.__svtermstate)
372376

373-
if platform.system() == "Darwin" and os.getenv("TERM_PROGRAM") == "Apple_Terminal":
377+
if self.is_apple_terminal:
374378
os.write(self.output_fd, b"\033[?7h")
375379

376380
if hasattr(self, "old_sigwinch"):

Lib/test/support/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2899,7 +2899,7 @@ def force_color(color: bool):
28992899
from .os_helper import EnvironmentVarGuard
29002900

29012901
with (
2902-
swap_attr(_colorize, "can_colorize", lambda file=None: color),
2902+
swap_attr(_colorize, "can_colorize", lambda *, file=None: color),
29032903
EnvironmentVarGuard() as env,
29042904
):
29052905
env.unset("FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS")

Lib/test/test_pyrepl/test_unix_console.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,12 @@ def test_getheightwidth_with_invalid_environ(self, _os_write):
303303
self.assertIsInstance(console.getheightwidth(), tuple)
304304
os.environ = []
305305
self.assertIsInstance(console.getheightwidth(), tuple)
306+
307+
@unittest.skipUnless(sys.platform == "darwin", "requires macOS")
308+
def test_restore_with_invalid_environ_on_macos(self, _os_write):
309+
# gh-128636 for macOS
310+
console = UnixConsole(term="xterm")
311+
with os_helper.EnvironmentVarGuard():
312+
os.environ = []
313+
console.prepare() # needed to call restore()
314+
console.restore() # this should succeed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash in PyREPL when os.environ is overwritten with an invalid value for
2+
mac

0 commit comments

Comments
 (0)