Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[3.13] gh-143310: fix crash in Tcl object conversion with concurrent mutations (GH-143321)#143344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
picnixz merged 1 commit intopython:3.13frommiss-islington:backport-9712dc1-3.13
Jan 2, 2026
Merged
Show file tree
Hide file tree
Changes fromall 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
24 changes: 22 additions & 2 deletionsLib/test/test_tcl.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -40,6 +40,9 @@ def setUp(self):
self.interp = Tcl()
self.wantobjects = self.interp.tk.wantobjects()

def passValue(self, value):
return self.interp.call('set', '_', value)

def testEval(self):
tcl = self.interp
tcl.eval('set a 1')
Expand DownExpand Up@@ -490,8 +493,7 @@ def test_expr_bignum(self):
self.assertIsInstance(result, str)

def test_passing_values(self):
def passValue(value):
return self.interp.call('set', '_', value)
passValue = self.passValue

self.assertEqual(passValue(True), True if self.wantobjects else '1')
self.assertEqual(passValue(False), False if self.wantobjects else '0')
Expand DownExpand Up@@ -537,6 +539,24 @@ def passValue(value):
self.assertEqual(passValue(['a', ['b', 'c']]),
('a', ('b', 'c')) if self.wantobjects else 'a {b c}')

def test_set_object_concurrent_mutation_in_sequence_conversion(self):
# Prevent SIGSEV when the object to convert is concurrently mutated.
# See: https://github.com/python/cpython/issues/143310.

string = "value"

class Value:
def __str__(self):
values.clear()
return string

class List(list):
pass

expect = (string, "pad") if self.wantobjects else f"{string} pad"
self.assertEqual(self.passValue(values := [Value(), "pad"]), expect)
self.assertEqual(self.passValue(values := List([Value(), "pad"])), expect)

def test_user_command(self):
result = None
def testfunc(arg):
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
:mod:`tkinter`: fix a crash when a Python :class:`list` is mutated during
the conversion to a Tcl object (e.g., when setting a Tcl variable).
Patch by Bénédikt Tran.
63 changes: 43 additions & 20 deletionsModules/_tkinter.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -946,6 +946,40 @@ asBignumObj(PyObject *value)
return result;
}

static Tcl_Obj* AsObj(PyObject *value);

static Tcl_Obj*
TupleAsObj(PyObject *value, int wrapped)
{
Tcl_Obj *result = NULL;
Py_ssize_t size = PyTuple_GET_SIZE(value);
if (size == 0) {
return Tcl_NewListObj(0, NULL);
}
if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
PyErr_SetString(PyExc_OverflowError,
wrapped ? "list is too long" : "tuple is too long");
return NULL;
}
Tcl_Obj **argv = (Tcl_Obj **)PyMem_Malloc(((size_t)size) * sizeof(Tcl_Obj *));
if (argv == NULL) {
PyErr_NoMemory();
return NULL;
}
for (Py_ssize_t i = 0; i < size; i++) {
Tcl_Obj *item = AsObj(PyTuple_GET_ITEM(value, i));
if (item == NULL) {
goto exit;
}
argv[i] = item;
}
result = Tcl_NewListObj((int)size, argv);

exit:
PyMem_Free(argv);
return result;
}

static Tcl_Obj*
AsObj(PyObject *value)
{
Expand DownExpand Up@@ -992,28 +1026,17 @@ AsObj(PyObject *value)
if (PyFloat_Check(value))
return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));

if (PyTuple_Check(value) || PyList_Check(value)) {
Tcl_Obj **argv;
Py_ssize_t size, i;

size = PySequence_Fast_GET_SIZE(value);
if (size == 0)
return Tcl_NewListObj(0, NULL);
if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
PyErr_SetString(PyExc_OverflowError,
PyTuple_Check(value) ? "tuple is too long" :
"list is too long");
if (PyTuple_Check(value)) {
return TupleAsObj(value, false);
}

if (PyList_Check(value)) {
PyObject *value_as_tuple = PyList_AsTuple(value);
if (value_as_tuple == NULL) {
return NULL;
}
argv = (Tcl_Obj **) PyMem_Malloc(((size_t)size) * sizeof(Tcl_Obj *));
if (!argv) {
PyErr_NoMemory();
return NULL;
}
for (i = 0; i < size; i++)
argv[i] = AsObj(PySequence_Fast_GET_ITEM(value,i));
result = Tcl_NewListObj((int)size, argv);
PyMem_Free(argv);
result = TupleAsObj(value_as_tuple, true);
Py_DECREF(value_as_tuple);
return result;
}

Expand Down
Loading

[8]ページ先頭

©2009-2026 Movatter.jp