Skip to content

Commit

Permalink
Fix marshal's incorrect handling of subclasses of builtin types (back…
Browse files Browse the repository at this point in the history
…port candidate).
  • Loading branch information
rhettinger committed Nov 7, 2007
1 parent 9b847b4 commit 12e9420
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 16 deletions.
6 changes: 0 additions & 6 deletions Doc/library/marshal.rst
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_marshal.py
Expand Up @@ -244,6 +244,17 @@ def test_recursion_limit(self):
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,
Expand Down
4 changes: 4 additions & 0 deletions Misc/NEWS
Expand Up @@ -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.

Expand Down
20 changes: 10 additions & 10 deletions Python/marshal.c
Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -293,23 +293,23 @@ 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);
for (i = 0; i < n; i++) {
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);
for (i = 0; i < n; i++) {
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);
Expand All @@ -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))
Expand Down

0 comments on commit 12e9420

Please sign in to comment.