Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Lib/test/test_tkinter/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
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')

Expand Down Expand Up @@ -710,6 +711,30 @@ def test_iterable_protocol(self):
widget in widget


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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
14 changes: 14 additions & 0 deletions Modules/_tkinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -3272,6 +3272,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);
Expand Down
Loading