]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-126219: Fix crash in tkinter.Tk with non-BMP className on Tcl/Tk 8.x (GH...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 24 Jun 2026 06:31:24 +0000 (08:31 +0200)
committerGitHub <noreply@github.com>
Wed, 24 Jun 2026 06:31:24 +0000 (09:31 +0300)
Tcl 8.x crashes when title-casing a non-BMP character during Tk
initialization, so such a className is now rejected with a ValueError.
(cherry picked from commit 124c7cd91be8cff76d1eec0adef65991c23c4419)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Lib/test/test_tkinter/test_misc.py
Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst [new file with mode: 0644]
Modules/_tkinter.c

index 702f4488f350dd3d89bf17042daf98f88c38c723..c2d64d63d04a1b23e5c8112237a81ca45b176fed 100644 (file)
@@ -7,7 +7,8 @@ from test import support
 from test.support import os_helper
 from test.test_tkinter.support import setUpModule  # noqa: F401
 from test.test_tkinter.support import (AbstractTkTest, AbstractDefaultRootTest,
-                                       requires_tk, get_tk_patchlevel)
+                                       requires_tk, get_tk_patchlevel,
+                                       tcl_version)
 
 support.requires('gui')
 
@@ -641,6 +642,30 @@ class MiscTest(AbstractTkTest, unittest.TestCase):
         self.assertEqual(widget.selection_get(), '\u20ac\0abc\x00def')
 
 
+class TkTest(AbstractTkTest, unittest.TestCase):
+
+    def test_className(self):
+        # The className argument sets the class of the root window.  Tk
+        # title-cases it: the first letter is upper-cased, the rest lower-cased.
+        cases = [
+            ('fooBAR', 'Foobar'),
+            ('éÉ', 'Éé'),  # small and capital E WITH ACUTE
+        ]
+        if tcl_version >= (9, 0):
+            # small and capital DESERET LETTER LONG I (a non-BMP script)
+            cases.append(('\U00010428\U00010400', '\U00010400\U00010428'))
+        for className, klass in cases:
+            root = tkinter.Tk(className=className)
+            try:
+                self.assertEqual(root.winfo_class(), klass)
+            finally:
+                root.destroy()
+        if tcl_version < (9, 0):
+            # gh-126219: title-casing a non-BMP first letter crashed Tcl 8.x;
+            # such a class name is now rejected.
+            self.assertRaises(ValueError, tkinter.Tk, className='\U00010428')
+
+
 class WinfoTest(AbstractTkTest, unittest.TestCase):
 
     def test_winfo_rgb(self):
diff --git a/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst b/Misc/NEWS.d/next/Library/2026-06-23-13-27-14.gh-issue-126219.kOfv2g.rst
new file mode 100644 (file)
index 0000000..8cc8c64
--- /dev/null
@@ -0,0 +1,3 @@
+Fixed a crash in :class:`tkinter.Tk` when *className* contains a non-BMP
+character and tkinter is built against Tcl/Tk 8.x.  Such a name is now
+rejected with a :exc:`ValueError`.
index 56d1a1cba0ad42d64d0c806daee1e6ed0e72f1d9..ab302240b4fb1362d3b9c413aa10210010670354 100644 (file)
@@ -3204,6 +3204,20 @@ _tkinter_create_impl(PyObject *module, const char *screenName,
     CHECK_STRING_LENGTH(className);
     CHECK_STRING_LENGTH(use);
 
+#if TCL_MAJOR_VERSION < 9
+    /* className is title-cased during Tk initialization.  Tcl 8.x does not
+     * support non-BMP characters (encoded as 4-byte UTF-8 sequences) there
+     * and crashes in Tcl_UtfToTitle (see gh-126219).  Reject them up front. */
+    for (const unsigned char *p = (const unsigned char *)className; *p; p++) {
+        if (*p >= 0xF0) {
+            PyErr_SetString(PyExc_ValueError,
+                            "className must not contain non-BMP characters "
+                            "with this version of Tcl/Tk");
+            return NULL;
+        }
+    }
+#endif
+
     return (PyObject *) Tkapp_New(screenName, className,
                                   interactive, wantobjects, wantTk,
                                   sync, use);