Commit 1317e144 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #20368: The null character now correctly passed from Tcl to Python.

Improved error handling in variables-related commands.
parent fc055252
...@@ -55,6 +55,10 @@ class TclTest(unittest.TestCase): ...@@ -55,6 +55,10 @@ class TclTest(unittest.TestCase):
tcl.eval('set a 1') tcl.eval('set a 1')
self.assertEqual(tcl.eval('set a'),'1') self.assertEqual(tcl.eval('set a'),'1')
def test_eval_null_in_result(self):
tcl = self.interp
self.assertEqual(tcl.eval('set a "a\\0b"'), 'a\x00b')
def testEvalException(self): def testEvalException(self):
tcl = self.interp tcl = self.interp
self.assertRaises(TclError,tcl.eval,'set a') self.assertRaises(TclError,tcl.eval,'set a')
...@@ -127,20 +131,29 @@ class TclTest(unittest.TestCase): ...@@ -127,20 +131,29 @@ class TclTest(unittest.TestCase):
def testEvalFile(self): def testEvalFile(self):
tcl = self.interp tcl = self.interp
filename = "testEvalFile.tcl" with open(support.TESTFN, 'w') as f:
fd = open(filename,'w') self.addCleanup(support.unlink, support.TESTFN)
script = """set a 1 f.write("""set a 1
set b 2 set b 2
set c [ expr $a + $b ] set c [ expr $a + $b ]
""" """)
fd.write(script) tcl.evalfile(support.TESTFN)
fd.close()
tcl.evalfile(filename)
os.remove(filename)
self.assertEqual(tcl.eval('set a'),'1') self.assertEqual(tcl.eval('set a'),'1')
self.assertEqual(tcl.eval('set b'),'2') self.assertEqual(tcl.eval('set b'),'2')
self.assertEqual(tcl.eval('set c'),'3') self.assertEqual(tcl.eval('set c'),'3')
def test_evalfile_null_in_result(self):
tcl = self.interp
with open(support.TESTFN, 'w') as f:
self.addCleanup(support.unlink, support.TESTFN)
f.write("""
set a "a\0b"
set b "a\\0b"
""")
tcl.evalfile(support.TESTFN)
self.assertEqual(tcl.eval('set a'), 'a\x00b')
self.assertEqual(tcl.eval('set b'), 'a\x00b')
def testEvalFileException(self): def testEvalFileException(self):
tcl = self.interp tcl = self.interp
filename = "doesnotexists" filename = "doesnotexists"
...@@ -209,6 +222,7 @@ class TclTest(unittest.TestCase): ...@@ -209,6 +222,7 @@ class TclTest(unittest.TestCase):
check('"abc"', 'abc') check('"abc"', 'abc')
check('"a\xbd\u20ac"', 'a\xbd\u20ac') check('"a\xbd\u20ac"', 'a\xbd\u20ac')
check(r'"a\xbd\u20ac"', 'a\xbd\u20ac') check(r'"a\xbd\u20ac"', 'a\xbd\u20ac')
check(r'"a\0b"', 'a\x00b')
def test_exprdouble(self): def test_exprdouble(self):
tcl = self.interp tcl = self.interp
...@@ -320,6 +334,11 @@ class TclTest(unittest.TestCase): ...@@ -320,6 +334,11 @@ class TclTest(unittest.TestCase):
self.assertEqual(passValue(False), False if self.wantobjects else '0') self.assertEqual(passValue(False), False if self.wantobjects else '0')
self.assertEqual(passValue('string'), 'string') self.assertEqual(passValue('string'), 'string')
self.assertEqual(passValue('string\u20ac'), 'string\u20ac') self.assertEqual(passValue('string\u20ac'), 'string\u20ac')
self.assertEqual(passValue('str\x00ing'), 'str\x00ing')
self.assertEqual(passValue('str\x00ing\xbd'), 'str\x00ing\xbd')
self.assertEqual(passValue('str\x00ing\u20ac'), 'str\x00ing\u20ac')
self.assertEqual(passValue(b'str\x00ing'), 'str\x00ing')
self.assertEqual(passValue(b'str\xc0\x80ing'), 'str\x00ing')
for i in (0, 1, -1, 2**31-1, -2**31): for i in (0, 1, -1, 2**31-1, -2**31):
self.assertEqual(passValue(i), i if self.wantobjects else str(i)) self.assertEqual(passValue(i), i if self.wantobjects else str(i))
for f in (0.0, 1.0, -1.0, 1/3, for f in (0.0, 1.0, -1.0, 1/3,
...@@ -368,6 +387,13 @@ class TclTest(unittest.TestCase): ...@@ -368,6 +387,13 @@ class TclTest(unittest.TestCase):
check('string', 'string') check('string', 'string')
check('string\xbd', 'string\xbd') check('string\xbd', 'string\xbd')
check('string\u20ac', 'string\u20ac') check('string\u20ac', 'string\u20ac')
check(b'string', 'string')
check(b'string\xe2\x82\xac', 'string\u20ac')
check('str\x00ing', 'str\x00ing')
check('str\x00ing\xbd', 'str\x00ing\xbd')
check('str\x00ing\u20ac', 'str\x00ing\u20ac')
check(b'str\xc0\x80ing', 'str\x00ing')
check(b'str\xc0\x80ing\xe2\x82\xac', 'str\x00ing\u20ac')
for i in (0, 1, -1, 2**31-1, -2**31): for i in (0, 1, -1, 2**31-1, -2**31):
check(i, str(i)) check(i, str(i))
for f in (0.0, 1.0, -1.0): for f in (0.0, 1.0, -1.0):
...@@ -396,6 +422,7 @@ class TclTest(unittest.TestCase): ...@@ -396,6 +422,7 @@ class TclTest(unittest.TestCase):
(b'a\n b\t\r c\n ', ('a', 'b', 'c')), (b'a\n b\t\r c\n ', ('a', 'b', 'c')),
('a \u20ac', ('a', '\u20ac')), ('a \u20ac', ('a', '\u20ac')),
(b'a \xe2\x82\xac', ('a', '\u20ac')), (b'a \xe2\x82\xac', ('a', '\u20ac')),
(b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
('a {b c}', ('a', 'b c')), ('a {b c}', ('a', 'b c')),
(r'a b\ c', ('a', 'b c')), (r'a b\ c', ('a', 'b c')),
(('a', 'b c'), ('a', 'b c')), (('a', 'b c'), ('a', 'b c')),
...@@ -438,6 +465,9 @@ class TclTest(unittest.TestCase): ...@@ -438,6 +465,9 @@ class TclTest(unittest.TestCase):
(b'a\n b\t\r c\n ', ('a', 'b', 'c')), (b'a\n b\t\r c\n ', ('a', 'b', 'c')),
('a \u20ac', ('a', '\u20ac')), ('a \u20ac', ('a', '\u20ac')),
(b'a \xe2\x82\xac', ('a', '\u20ac')), (b'a \xe2\x82\xac', ('a', '\u20ac')),
(b'a\xc0\x80b', 'a\x00b'),
(b'a\xc0\x80b c\xc0\x80d', ('a\x00b', 'c\x00d')),
(b'{a\xc0\x80b c\xc0\x80d', '{a\x00b c\x00d'),
('a {b c}', ('a', ('b', 'c'))), ('a {b c}', ('a', ('b', 'c'))),
(r'a b\ c', ('a', ('b', 'c'))), (r'a b\ c', ('a', ('b', 'c'))),
(('a', b'b c'), ('a', ('b', 'c'))), (('a', b'b c'), ('a', ('b', 'c'))),
......
...@@ -68,6 +68,18 @@ class TestVariable(TestBase): ...@@ -68,6 +68,18 @@ class TestVariable(TestBase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
Variable(self.root, name=123) Variable(self.root, name=123)
def test_null_in_name(self):
with self.assertRaises(ValueError):
Variable(self.root, name='var\x00name')
with self.assertRaises(ValueError):
self.root.globalsetvar('var\x00name', "value")
with self.assertRaises(ValueError):
self.root.globalsetvar(b'var\x00name', "value")
with self.assertRaises(ValueError):
self.root.setvar('var\x00name', "value")
with self.assertRaises(ValueError):
self.root.setvar(b'var\x00name', "value")
def test_initialize(self): def test_initialize(self):
v = Var() v = Var()
self.assertFalse(v.side_effect) self.assertFalse(v.side_effect)
...@@ -87,6 +99,12 @@ class TestStringVar(TestBase): ...@@ -87,6 +99,12 @@ class TestStringVar(TestBase):
self.root.globalsetvar("name", "value") self.root.globalsetvar("name", "value")
self.assertEqual("value", v.get()) self.assertEqual("value", v.get())
def test_get_null(self):
v = StringVar(self.root, "abc\x00def", "name")
self.assertEqual("abc\x00def", v.get())
self.root.globalsetvar("name", "val\x00ue")
self.assertEqual("val\x00ue", v.get())
class TestIntVar(TestBase): class TestIntVar(TestBase):
......
...@@ -45,6 +45,9 @@ Core and Builtins ...@@ -45,6 +45,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20368: The null character now correctly passed from Tcl to Python.
Improved error handling in variables-related commands.
- Issue #20435: Fix _pyio.StringIO.getvalue() to take into account newline - Issue #20435: Fix _pyio.StringIO.getvalue() to take into account newline
translation settings. translation settings.
......
...@@ -418,6 +418,51 @@ Merge(PyObject *args) ...@@ -418,6 +418,51 @@ Merge(PyObject *args)
static PyObject *
unicodeFromTclStringAndSize(const char *s, Py_ssize_t size)
{
PyObject *r = PyUnicode_DecodeUTF8(s, size, NULL);
if (!r && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
/* Tcl encodes null character as \xc0\x80 */
if (memchr(s, '\xc0', size)) {
char *buf, *q;
const char *e = s + size;
PyErr_Clear();
q = buf = (char *)PyMem_Malloc(size);
if (buf == NULL)
return NULL;
while (s != e) {
if (s + 1 != e && s[0] == '\xc0' && s[1] == '\x80') {
*q++ = '\0';
s += 2;
}
else
*q++ = *s++;
}
s = buf;
size = q - s;
r = PyUnicode_DecodeUTF8(s, size, NULL);
PyMem_Free(buf);
}
}
return r;
}
static PyObject *
unicodeFromTclString(const char *s)
{
return unicodeFromTclStringAndSize(s, strlen(s));
}
static PyObject *
unicodeFromTclObj(Tcl_Obj *value)
{
int len;
char *s = Tcl_GetStringFromObj(value, &len);
return unicodeFromTclStringAndSize(s, len);
}
static PyObject * static PyObject *
Split(char *list) Split(char *list)
{ {
...@@ -435,13 +480,13 @@ Split(char *list) ...@@ -435,13 +480,13 @@ Split(char *list)
* Could be a quoted string containing funnies, e.g. {"}. * Could be a quoted string containing funnies, e.g. {"}.
* Return the string itself. * Return the string itself.
*/ */
return PyUnicode_FromString(list); return unicodeFromTclString(list);
} }
if (argc == 0) if (argc == 0)
v = PyUnicode_FromString(""); v = PyUnicode_FromString("");
else if (argc == 1) else if (argc == 1)
v = PyUnicode_FromString(argv[0]); v = unicodeFromTclString(argv[0]);
else if ((v = PyTuple_New(argc)) != NULL) { else if ((v = PyTuple_New(argc)) != NULL) {
int i; int i;
PyObject *w; PyObject *w;
...@@ -780,11 +825,8 @@ PyDoc_STRVAR(PyTclObject_string__doc__, ...@@ -780,11 +825,8 @@ PyDoc_STRVAR(PyTclObject_string__doc__,
static PyObject * static PyObject *
PyTclObject_string(PyTclObject *self, void *ignored) PyTclObject_string(PyTclObject *self, void *ignored)
{ {
char *s;
int len;
if (!self->string) { if (!self->string) {
s = Tcl_GetStringFromObj(self->value, &len); self->string = unicodeFromTclObj(self->value);
self->string = PyUnicode_FromStringAndSize(s, len);
if (!self->string) if (!self->string)
return NULL; return NULL;
} }
...@@ -795,15 +837,12 @@ PyTclObject_string(PyTclObject *self, void *ignored) ...@@ -795,15 +837,12 @@ PyTclObject_string(PyTclObject *self, void *ignored)
static PyObject * static PyObject *
PyTclObject_str(PyTclObject *self, void *ignored) PyTclObject_str(PyTclObject *self, void *ignored)
{ {
char *s; if (self->string) {
int len;
if (self->string && PyUnicode_Check(self->string)) {
Py_INCREF(self->string); Py_INCREF(self->string);
return self->string; return self->string;
} }
/* XXX Could chache result if it is non-ASCII. */ /* XXX Could chache result if it is non-ASCII. */
s = Tcl_GetStringFromObj(self->value, &len); return unicodeFromTclObj(self->value);
return PyUnicode_DecodeUTF8(s, len, "strict");
} }
static PyObject * static PyObject *
...@@ -873,7 +912,7 @@ PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type"); ...@@ -873,7 +912,7 @@ PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type");
static PyObject* static PyObject*
get_typename(PyTclObject* obj, void* ignored) get_typename(PyTclObject* obj, void* ignored)
{ {
return PyUnicode_FromString(obj->value->typePtr->name); return unicodeFromTclString(obj->value->typePtr->name);
} }
...@@ -985,6 +1024,8 @@ AsObj(PyObject *value) ...@@ -985,6 +1024,8 @@ AsObj(PyObject *value)
return NULL; return NULL;
} }
kind = PyUnicode_KIND(value); kind = PyUnicode_KIND(value);
if (kind == sizeof(Tcl_UniChar))
return Tcl_NewUnicodeObj(inbuf, size);
allocsize = ((size_t)size) * sizeof(Tcl_UniChar); allocsize = ((size_t)size) * sizeof(Tcl_UniChar);
outbuf = (Tcl_UniChar*)ckalloc(allocsize); outbuf = (Tcl_UniChar*)ckalloc(allocsize);
/* Else overflow occurred, and we take the next exit */ /* Else overflow occurred, and we take the next exit */
...@@ -1035,8 +1076,7 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) ...@@ -1035,8 +1076,7 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
TkappObject *app = (TkappObject*)tkapp; TkappObject *app = (TkappObject*)tkapp;
if (value->typePtr == NULL) { if (value->typePtr == NULL) {
return PyUnicode_FromStringAndSize(value->bytes, return unicodeFromTclStringAndSize(value->bytes, value->length);
value->length);
} }
if (value->typePtr == app->BooleanType) { if (value->typePtr == app->BooleanType) {
...@@ -1093,15 +1133,9 @@ FromObj(PyObject* tkapp, Tcl_Obj *value) ...@@ -1093,15 +1133,9 @@ FromObj(PyObject* tkapp, Tcl_Obj *value)
} }
if (value->typePtr == app->StringType) { if (value->typePtr == app->StringType) {
#if TCL_UTF_MAX==3
return PyUnicode_FromKindAndData(
PyUnicode_2BYTE_KIND, Tcl_GetUnicode(value),
Tcl_GetCharLength(value));
#else
return PyUnicode_FromKindAndData( return PyUnicode_FromKindAndData(
PyUnicode_4BYTE_KIND, Tcl_GetUnicode(value), sizeof(Tcl_UniChar), Tcl_GetUnicode(value),
Tcl_GetCharLength(value)); Tcl_GetCharLength(value));
#endif
} }
return newPyTclObject(value); return newPyTclObject(value);
...@@ -1195,8 +1229,8 @@ static PyObject* ...@@ -1195,8 +1229,8 @@ static PyObject*
Tkapp_CallResult(TkappObject *self) Tkapp_CallResult(TkappObject *self)
{ {
PyObject *res = NULL; PyObject *res = NULL;
Tcl_Obj *value = Tcl_GetObjResult(self->interp);
if(self->wantobjects) { if(self->wantobjects) {
Tcl_Obj *value = Tcl_GetObjResult(self->interp);
/* Not sure whether the IncrRef is necessary, but something /* Not sure whether the IncrRef is necessary, but something
may overwrite the interpreter result while we are may overwrite the interpreter result while we are
converting it. */ converting it. */
...@@ -1204,7 +1238,7 @@ Tkapp_CallResult(TkappObject *self) ...@@ -1204,7 +1238,7 @@ Tkapp_CallResult(TkappObject *self)
res = FromObj((PyObject*)self, value); res = FromObj((PyObject*)self, value);
Tcl_DecrRefCount(value); Tcl_DecrRefCount(value);
} else { } else {
res = PyUnicode_FromString(Tcl_GetStringResult(self->interp)); res = unicodeFromTclObj(value);
} }
return res; return res;
} }
...@@ -1395,7 +1429,7 @@ Tkapp_Eval(PyObject *self, PyObject *args) ...@@ -1395,7 +1429,7 @@ Tkapp_Eval(PyObject *self, PyObject *args)
if (err == TCL_ERROR) if (err == TCL_ERROR)
res = Tkinter_Error(self); res = Tkinter_Error(self);
else else
res = PyUnicode_FromString(Tkapp_Result(self)); res = unicodeFromTclString(Tkapp_Result(self));
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
return res; return res;
} }
...@@ -1445,9 +1479,8 @@ Tkapp_EvalFile(PyObject *self, PyObject *args) ...@@ -1445,9 +1479,8 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
ENTER_OVERLAP ENTER_OVERLAP
if (err == TCL_ERROR) if (err == TCL_ERROR)
res = Tkinter_Error(self); res = Tkinter_Error(self);
else else
res = PyUnicode_FromString(Tkapp_Result(self)); res = unicodeFromTclString(Tkapp_Result(self));
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
return res; return res;
} }
...@@ -1470,7 +1503,7 @@ Tkapp_Record(PyObject *self, PyObject *args) ...@@ -1470,7 +1503,7 @@ Tkapp_Record(PyObject *self, PyObject *args)
if (err == TCL_ERROR) if (err == TCL_ERROR)
res = Tkinter_Error(self); res = Tkinter_Error(self);
else else
res = PyUnicode_FromString(Tkapp_Result(self)); res = unicodeFromTclString(Tkapp_Result(self));
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
return res; return res;
} }
...@@ -1517,20 +1550,42 @@ typedef struct VarEvent { ...@@ -1517,20 +1550,42 @@ typedef struct VarEvent {
static int static int
varname_converter(PyObject *in, void *_out) varname_converter(PyObject *in, void *_out)
{ {
char *s;
char **out = (char**)_out; char **out = (char**)_out;
if (PyBytes_Check(in)) { if (PyBytes_Check(in)) {
*out = PyBytes_AsString(in); if (PyBytes_Size(in) > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "bytes object is too long");
return 0;
}
s = PyBytes_AsString(in);
if (strlen(s) != PyBytes_Size(in)) {
PyErr_SetString(PyExc_ValueError, "null byte in bytes object");
return 0;
}
*out = s;
return 1; return 1;
} }
if (PyUnicode_Check(in)) { if (PyUnicode_Check(in)) {
*out = _PyUnicode_AsString(in); Py_ssize_t size;
s = PyUnicode_AsUTF8AndSize(in, &size);
if (size > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "string is too long");
return 0;
}
if (strlen(s) != size) {
PyErr_SetString(PyExc_ValueError, "null character in string");
return 0;
}
*out = s;
return 1; return 1;
} }
if (PyTclObject_Check(in)) { if (PyTclObject_Check(in)) {
*out = PyTclObject_TclString(in); *out = PyTclObject_TclString(in);
return 1; return 1;
} }
/* XXX: Should give diagnostics. */ PyErr_Format(PyExc_TypeError,
"must be str, bytes or Tcl_Obj, not %.50s",
in->ob_type->tp_name);
return 0; return 0;
} }
...@@ -1616,8 +1671,11 @@ SetVar(PyObject *self, PyObject *args, int flags) ...@@ -1616,8 +1671,11 @@ SetVar(PyObject *self, PyObject *args, int flags)
PyObject *res = NULL; PyObject *res = NULL;
Tcl_Obj *newval, *ok; Tcl_Obj *newval, *ok;
if (PyArg_ParseTuple(args, "O&O:setvar", switch (PyTuple_GET_SIZE(args)) {
varname_converter, &name1, &newValue)) { case 2:
if (!PyArg_ParseTuple(args, "O&O:setvar",
varname_converter, &name1, &newValue))
return NULL;
/* XXX Acquire tcl lock??? */ /* XXX Acquire tcl lock??? */
newval = AsObj(newValue); newval = AsObj(newValue);
if (newval == NULL) if (newval == NULL)
...@@ -1633,27 +1691,27 @@ SetVar(PyObject *self, PyObject *args, int flags) ...@@ -1633,27 +1691,27 @@ SetVar(PyObject *self, PyObject *args, int flags)
Py_INCREF(res); Py_INCREF(res);
} }
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
} break;
else { case 3:
PyErr_Clear(); if (!PyArg_ParseTuple(args, "ssO:setvar",
if (PyArg_ParseTuple(args, "ssO:setvar", &name1, &name2, &newValue))
&name1, &name2, &newValue)) {
/* XXX must hold tcl lock already??? */
newval = AsObj(newValue);
ENTER_TCL
ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags);
ENTER_OVERLAP
if (!ok)
Tkinter_Error(self);
else {
res = Py_None;
Py_INCREF(res);
}
LEAVE_OVERLAP_TCL
}
else {
return NULL; return NULL;
/* XXX must hold tcl lock already??? */
newval = AsObj(newValue);
ENTER_TCL
ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags);
ENTER_OVERLAP
if (!ok)
Tkinter_Error(self);
else {
res = Py_None;
Py_INCREF(res);
} }
LEAVE_OVERLAP_TCL
break;
default:
PyErr_SetString(PyExc_TypeError, "setvar requires 2 to 3 arguments");
return NULL;
} }
return res; return res;
} }
...@@ -1693,7 +1751,7 @@ GetVar(PyObject *self, PyObject *args, int flags) ...@@ -1693,7 +1751,7 @@ GetVar(PyObject *self, PyObject *args, int flags)
res = FromObj(self, tres); res = FromObj(self, tres);
} }
else { else {
res = PyUnicode_FromString(Tcl_GetString(tres)); res = unicodeFromTclObj(tres);
} }
} }
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
...@@ -1831,7 +1889,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args) ...@@ -1831,7 +1889,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
if (retval == TCL_ERROR) if (retval == TCL_ERROR)
res = Tkinter_Error(self); res = Tkinter_Error(self);
else else
res = Py_BuildValue("s", Tkapp_Result(self)); res = unicodeFromTclString(Tkapp_Result(self));
LEAVE_OVERLAP_TCL LEAVE_OVERLAP_TCL
return res; return res;
} }
...@@ -1956,7 +2014,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args) ...@@ -1956,7 +2014,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args)
goto finally; goto finally;
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
PyObject *s = PyUnicode_FromString(argv[i]); PyObject *s = unicodeFromTclString(argv[i]);
if (!s || PyTuple_SetItem(v, i, s)) { if (!s || PyTuple_SetItem(v, i, s)) {
Py_DECREF(v); Py_DECREF(v);
v = NULL; v = NULL;
...@@ -2075,20 +2133,8 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) ...@@ -2075,20 +2133,8 @@ PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
return PythonCmd_Error(interp); return PythonCmd_Error(interp);
for (i = 0; i < (argc - 1); i++) { for (i = 0; i < (argc - 1); i++) {
PyObject *s = PyUnicode_FromString(argv[i + 1]); PyObject *s = unicodeFromTclString(argv[i + 1]);
if (!s) { if (!s || PyTuple_SetItem(arg, i, s)) {
/* Is Tk leaking 0xC080 in %A - a "modified" utf-8 null? */
if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError) &&
!strcmp(argv[i + 1], "\xC0\x80")) {
PyErr_Clear();
/* Convert to "strict" utf-8 null */
s = PyUnicode_FromString("\0");
} else {
Py_DECREF(arg);
return PythonCmd_Error(interp);
}
}
if (PyTuple_SetItem(arg, i, s)) {
Py_DECREF(arg); Py_DECREF(arg);
return PythonCmd_Error(interp); return PythonCmd_Error(interp);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment