diff --git a/Lib/test/test_tcl.py b/Lib/test/test_tcl.py index 1d90ac10ad77ade..f1953e4a2371173 100644 --- a/Lib/test/test_tcl.py +++ b/Lib/test/test_tcl.py @@ -596,6 +596,35 @@ def test_returning_deeply_nested(self): % support.exceeds_recursion_limit()) self.assertRaises(RecursionError, interp.getvar, 'x') + def test_setvar_evil(self): + # gh-161388 + class StrRaises: + def __str__(self): + raise RuntimeError("setvar evil") + + default = StrRaises() + + for getvar, setvar, unsetvar in [ + ( + self.interp.tk.getvar, + self.interp.tk.setvar, + self.interp.tk.unsetvar, + ), + ( + self.interp.tk.globalgetvar, + self.interp.tk.globalsetvar, + self.interp.tk.globalunsetvar, + ) + ]: + with self.subTest(getvar=getvar, setvar=setvar, unsetvar=unsetvar): + with self.assertRaisesRegex(RuntimeError, "setvar evil"): + setvar("name1", "name2", default) + + self.assertRaises(TclError, getvar, "name1") + self.assertIsNone(setvar("name1", "name2")) + self.assertEqual(getvar("name1"), "name2") + self.assertIsNone(unsetvar("name1")) + def test_user_command(self): result = None def testfunc(arg): diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 9a09687e55b9817..70a10cea038348d 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1234,8 +1234,9 @@ AsObjNested(PyObject *value, int depth) { PyObject *v = PyObject_Str(value); - if (!v) - return 0; + if (!v) { + return NULL; + } result = AsObjNested(v, depth); Py_DECREF(v); return result; @@ -2101,6 +2102,9 @@ SetVar(TkappObject *self, PyObject *args, int flags) /* XXX must hold tcl lock already??? */ newval = AsObj(newValue); + if (newval == NULL) { + return NULL; + } if (self->trace) { if (flags & TCL_GLOBAL_ONLY) { TRACE(self, ("((sssNO))", "uplevel", "#0", "set",