https://github.com/python/cpython/commit/5506734c9999628c0d91b025d42afc44c34a46a4
commit: 5506734c9999628c0d91b025d42afc44c34a46a4
branch: 3.13
author: Serhiy Storchaka <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2026-07-24T16:45:50Z
summary:

[3.13] gh-154580: Fix python-gdb.py pretty-printing non-ASCII strings in 
non-UTF-8 locales (GH-154581) (GH-154637)

The gdb pretty-printer used locale.getpreferredencoding() to decide whether to
escape a character, but gdb writes its output in its host charset.  Use
gdb.host_charset() instead.  test_strings had the same problem.
(cherry picked from commit 6cb93bd039ec1c5e0909d2d75cfc4fb3641c693b)

Co-authored-by: Claude Opus 4.8 <[email protected]>

files:
A Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst
M Lib/test/test_gdb/test_pretty_print.py
M Lib/test/test_gdb/util.py
M Tools/gdb/libpython.py

diff --git a/Lib/test/test_gdb/test_pretty_print.py 
b/Lib/test/test_gdb/test_pretty_print.py
index dfc77d65ab16a40..a258d7c0e60c7e1 100644
--- a/Lib/test/test_gdb/test_pretty_print.py
+++ b/Lib/test/test_gdb/test_pretty_print.py
@@ -107,29 +107,28 @@ def test_bytes(self):
     @support.requires_resource('cpu')
     def test_strings(self):
         'Verify the pretty-printing of unicode strings'
-        # We cannot simply call locale.getpreferredencoding() here,
-        # as GDB might have been linked against a different version
-        # of Python with a different encoding and coercion policy
-        # with respect to PEP 538 and PEP 540.
+        # gdb emits its output in the host charset, which is not necessarily 
the
+        # getpreferredencoding() of the (possibly differently coerced) embedded
+        # Python.
         stdout, stderr = run_gdb(
             '--eval-command',
-            'python import locale; print(locale.getpreferredencoding())')
+            'python import gdb; print(gdb.host_charset())')
 
-        encoding = stdout
+        encoding = stdout.strip()
         if stderr or not encoding:
             raise RuntimeError(
-                f'unable to determine the Python locale preferred encoding '
-                f'of embedded Python in GDB\n'
+                f'unable to determine the host charset of gdb\n'
                 f'stdout={stdout!r}\n'
                 f'stderr={stderr!r}')
 
         def check_repr(text):
             try:
                 text.encode(encoding)
-            except UnicodeEncodeError:
+            # LookupError or ValueError if the host charset is unknown or 
invalid.
+            except (UnicodeEncodeError, LookupError, ValueError):
                 self.assertGdbRepr(text, ascii(text))
             else:
-                self.assertGdbRepr(text)
+                self.assertGdbRepr(text, 
repr(text).encode(encoding).decode('ascii', 'surrogateescape'))
 
         self.assertGdbRepr('')
         self.assertGdbRepr('And now for something hopefully the same')
diff --git a/Lib/test/test_gdb/util.py b/Lib/test/test_gdb/util.py
index 54c6b2de7cc99d8..907632e5d09453d 100644
--- a/Lib/test/test_gdb/util.py
+++ b/Lib/test/test_gdb/util.py
@@ -58,7 +58,7 @@ def run_gdb(*args, exitcode=0, check=True, **env_vars):
         stdin=subprocess.PIPE,
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
-        encoding="utf8", errors="backslashreplace",
+        encoding="ascii", errors="surrogateescape",
         env=env)
 
     stdout = proc.stdout
diff --git 
a/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst 
b/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst
new file mode 100644
index 000000000000000..f6a039245b015ed
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Tools-Demos/2026-07-24-09-30-00.gh-issue-154580.Kp3nQ2.rst
@@ -0,0 +1,3 @@
+Fix ``python-gdb.py`` raising :exc:`UnicodeEncodeError` when pretty-printing a
+non-ASCII :class:`str` in a locale whose host charset cannot encode it, such as
+any non-ASCII string in the C locale.
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 42301dad4ff9a12..1039dd31d6b7caf 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -43,7 +43,6 @@
 
 import gdb
 import os
-import locale
 import sys
 
 
@@ -100,8 +99,6 @@ def _managed_dict_offset():
 
 hexdigits = "0123456789abcdef"
 
-ENCODING = locale.getpreferredencoding()
-
 FRAME_INFO_OPTIMIZED_OUT = '(frame information optimized out)'
 UNABLE_READ_INFO_PYTHON_FRAME = 'Unable to read information on python frame'
 EVALFRAME = '_PyEval_EvalFrameDefault'
@@ -1462,6 +1459,10 @@ def proxyval(self, visited):
     def write_repr(self, out, visited):
         # Write this out as a Python str literal
 
+        # gdb writes its output in the host charset, so a character is escaped
+        # unless it is printable and encodable in that charset.
+        encoding = gdb.host_charset()
+
         # Get a PyUnicodeObject* within the Python gdb process:
         proxy = self.proxyval(visited)
 
@@ -1509,8 +1510,10 @@ def write_repr(self, out, visited):
                 printable = ucs.isprintable()
                 if printable:
                     try:
-                        ucs.encode(ENCODING)
-                    except UnicodeEncodeError:
+                        ucs.encode(encoding)
+                    # LookupError or ValueError if the host charset is unknown
+                    # or invalid.
+                    except (UnicodeEncodeError, LookupError, ValueError):
                         printable = False
 
                 # Map Unicode whitespace and control characters

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to