Fix marshal's incorrect handling of subclasses of builtin types (backport candidate).

This commit is contained in:
Raymond Hettinger 2007-11-07 01:13:09 +00:00
parent 9b847b432c
commit 12e94200c0
4 changed files with 25 additions and 16 deletions

View File

@ -44,12 +44,6 @@ and dictionaries are only supported as long as the values contained therein are
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

View File

@ -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,

View File

@ -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.

View File

@ -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))