diff options
author | Raymond Hettinger <python@rcn.com> | 2007-11-07 01:13:09 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2007-11-07 01:13:09 (GMT) |
commit | 12e94200c0b12487e129ce7e325d9315c12ca88a (patch) | |
tree | 0cbe02ff1f2a163d2e2c3c2cfb496f73e8c108e7 | |
parent | 9b847b432cda06cb1c1fd58a46efb7f0eca1cad1 (diff) | |
download | cpython-12e94200c0b12487e129ce7e325d9315c12ca88a.zip cpython-12e94200c0b12487e129ce7e325d9315c12ca88a.tar.gz cpython-12e94200c0b12487e129ce7e325d9315c12ca88a.tar.bz2 |
Fix marshal's incorrect handling of subclasses of builtin types (backport candidate).
-rw-r--r-- | Doc/library/marshal.rst | 6 | ||||
-rw-r--r-- | Lib/test/test_marshal.py | 11 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Python/marshal.c | 20 |
4 files changed, 25 insertions, 16 deletions
diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst index 19a56d7..4f5b16a 100644 --- a/Doc/library/marshal.rst +++ b/Doc/library/marshal.rst @@ -45,12 +45,6 @@ themselves supported; and recursive lists and dictionaries should not be written (they will cause infinite loops). .. warning:: - - Some unsupported types such as subclasses of builtins will appear to marshal - and unmarshal correctly, but in fact, their type will change and the - additional subclass functionality and instance attributes will be lost. - -.. warning:: On machines where C's ``long int`` type has more than 32 bits (such as the DEC Alpha), it is possible to create plain Python integers that are longer diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 656fc1f..1b2c8b7 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -244,6 +244,17 @@ class BugsTestCase(unittest.TestCase): last.append([0]) self.assertRaises(ValueError, marshal.dumps, head) + def test_exact_type_match(self): + # Former bug: + # >>> class Int(int): pass + # >>> type(loads(dumps(Int()))) + # <type 'int'> + for typ in (int, long, float, complex, tuple, list, dict, set, frozenset): + # Note: str and unicode sublclasses are not tested because they get handled + # by marshal's routines for objects supporting the buffer API. + subtyp = type('subtyp', (typ,), {}) + self.assertRaises(ValueError, marshal.dumps, subtyp()) + def test_main(): test_support.run_unittest(IntTestCase, FloatTestCase, @@ -812,6 +812,10 @@ Library Extension Modules ----------------- +- Marshal.dumps() now expects exact type matches for int, long, float, complex, + tuple, list, dict, set, and frozenset. Formerly, it would silently miscode + subclasses of those types. Now, it raises a ValueError instead. + - Patch #1388440: Add set_completion_display_matches_hook and get_completion_type to readline. diff --git a/Python/marshal.c b/Python/marshal.c index 897c15e..0c611b6 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -144,7 +144,7 @@ w_object(PyObject *v, WFILE *p) else if (v == Py_True) { w_byte(TYPE_TRUE, p); } - else if (PyInt_Check(v)) { + else if (PyInt_CheckExact(v)) { long x = PyInt_AS_LONG((PyIntObject *)v); #if SIZEOF_LONG > 4 long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); @@ -159,7 +159,7 @@ w_object(PyObject *v, WFILE *p) w_long(x, p); } } - else if (PyLong_Check(v)) { + else if (PyLong_CheckExact(v)) { PyLongObject *ob = (PyLongObject *)v; w_byte(TYPE_LONG, p); n = ob->ob_size; @@ -169,7 +169,7 @@ w_object(PyObject *v, WFILE *p) for (i = 0; i < n; i++) w_short(ob->ob_digit[i], p); } - else if (PyFloat_Check(v)) { + else if (PyFloat_CheckExact(v)) { if (p->version > 1) { unsigned char buf[8]; if (_PyFloat_Pack8(PyFloat_AsDouble(v), @@ -190,7 +190,7 @@ w_object(PyObject *v, WFILE *p) } } #ifndef WITHOUT_COMPLEX - else if (PyComplex_Check(v)) { + else if (PyComplex_CheckExact(v)) { if (p->version > 1) { unsigned char buf[8]; if (_PyFloat_Pack8(PyComplex_RealAsDouble(v), @@ -236,7 +236,7 @@ w_object(PyObject *v, WFILE *p) } } #endif - else if (PyString_Check(v)) { + else if (PyString_CheckExact(v)) { if (p->strings && PyString_CHECK_INTERNED(v)) { PyObject *o = PyDict_GetItem(p->strings, v); if (o) { @@ -273,7 +273,7 @@ w_object(PyObject *v, WFILE *p) w_string(PyString_AS_STRING(v), (int)n, p); } #ifdef Py_USING_UNICODE - else if (PyUnicode_Check(v)) { + else if (PyUnicode_CheckExact(v)) { PyObject *utf8; utf8 = PyUnicode_AsUTF8String(v); if (utf8 == NULL) { @@ -293,7 +293,7 @@ w_object(PyObject *v, WFILE *p) Py_DECREF(utf8); } #endif - else if (PyTuple_Check(v)) { + else if (PyTuple_CheckExact(v)) { w_byte(TYPE_TUPLE, p); n = PyTuple_Size(v); w_long((long)n, p); @@ -301,7 +301,7 @@ w_object(PyObject *v, WFILE *p) w_object(PyTuple_GET_ITEM(v, i), p); } } - else if (PyList_Check(v)) { + else if (PyList_CheckExact(v)) { w_byte(TYPE_LIST, p); n = PyList_GET_SIZE(v); w_long((long)n, p); @@ -309,7 +309,7 @@ w_object(PyObject *v, WFILE *p) w_object(PyList_GET_ITEM(v, i), p); } } - else if (PyDict_Check(v)) { + else if (PyDict_CheckExact(v)) { Py_ssize_t pos; PyObject *key, *value; w_byte(TYPE_DICT, p); @@ -321,7 +321,7 @@ w_object(PyObject *v, WFILE *p) } w_object((PyObject *)NULL, p); } - else if (PyAnySet_Check(v)) { + else if (PyAnySet_CheckExact(v)) { PyObject *value, *it; if (PyObject_TypeCheck(v, &PySet_Type)) |