From: Serhiy Storchaka Date: Sat, 19 Dec 2015 18:07:48 +0000 (+0200) Subject: Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size. X-Git-Tag: v2.7.12rc1~331 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c06a6d0958e2eb4449605069b9c10d656ab756e8;p=thirdparty%2FPython%2Fcpython.git Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size. This allows sys.getsize() to work correctly with their subclasses with __slots__ defined. --- diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index de13f2204b52..e6c17a2d35f7 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1,9 +1,12 @@ # -*- coding: iso-8859-1 -*- import unittest, test.test_support from test.script_helper import assert_python_ok, assert_python_failure -import sys, os, cStringIO -import struct +import cStringIO +import gc import operator +import os +import struct +import sys class SysModuleTest(unittest.TestCase): @@ -754,6 +757,32 @@ class SizeofTest(unittest.TestCase): check(xrange(1), size('3l')) check(xrange(66000), size('3l')) + def check_slots(self, obj, base, extra): + expected = sys.getsizeof(base) + struct.calcsize(extra) + if gc.is_tracked(obj) and not gc.is_tracked(base): + expected += struct.calcsize('3P') # PyGC_Head + self.assertEqual(sys.getsizeof(obj), expected) + + def test_slots(self): + # check all subclassable types defined in Objects/ that allow + # non-empty __slots__ + check = self.check_slots + class BA(bytearray): + __slots__ = 'a', 'b', 'c' + check(BA(), bytearray(), '3P') + class D(dict): + __slots__ = 'a', 'b', 'c' + check(D(x=[]), {'x': []}, '3P') + class L(list): + __slots__ = 'a', 'b', 'c' + check(L(), [], '3P') + class S(set): + __slots__ = 'a', 'b', 'c' + check(S(), set(), '3P') + class FS(frozenset): + __slots__ = 'a', 'b', 'c' + check(FS(), frozenset(), '3P') + def test_pythontypes(self): # check all types defined in Python/ size = test.test_support.calcobjsize diff --git a/Misc/NEWS b/Misc/NEWS index adb4a1556be0..315ebf0b9d16 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 2.7.12? Core and Builtins ----------------- +- Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size. + This allows sys.getsize() to work correctly with their subclasses with + __slots__ defined. + - Issue #19543: Added Py3k warning for decoding unicode. - Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index aaac660131a0..d4cc960af4e2 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1103,7 +1103,7 @@ deque_sizeof(dequeobject *deque, void *unused) Py_ssize_t res; Py_ssize_t blocks; - res = sizeof(dequeobject); + res = _PyObject_SIZE(Py_TYPE(deque)); blocks = (deque->leftindex + deque->len + BLOCKLEN - 1) / BLOCKLEN; assert(deque->leftindex + deque->len - 1 == (blocks - 1) * BLOCKLEN + deque->rightindex); diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index b4632edf44f7..dd518d7ac4e4 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -391,7 +391,7 @@ buffered_sizeof(buffered *self, void *unused) { Py_ssize_t res; - res = sizeof(buffered); + res = _PyObject_SIZE(Py_TYPE(self)); if (self->buffer) res += self->buffer_size; return PyLong_FromSsize_t(res); diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index f643e9124d5f..82f3851ea4cf 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -809,7 +809,7 @@ bytesio_sizeof(bytesio *self, void *unused) { Py_ssize_t res; - res = sizeof(bytesio); + res = _PyObject_SIZE(Py_TYPE(self)); if (self->buf) res += self->buf_size; return PyLong_FromSsize_t(res); diff --git a/Modules/_struct.c b/Modules/_struct.c index bca7a2e7ca4a..02dd7d369aaa 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -1737,7 +1737,7 @@ s_sizeof(PyStructObject *self, void *unused) { Py_ssize_t size; - size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1); + size = _PyObject_SIZE(Py_TYPE(self)) + sizeof(formatcode) * (self->s_len + 1); return PyLong_FromSsize_t(size); } diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 1d1f0d3845cc..f14711563c53 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -1541,7 +1541,7 @@ static PyObject * array_sizeof(arrayobject *self, PyObject *unused) { Py_ssize_t res; - res = sizeof(arrayobject) + self->allocated * self->ob_descr->itemsize; + res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * self->ob_descr->itemsize; return PyLong_FromSsize_t(res); } diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8fdf7f75e1ab..1ebccdfa82a5 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -655,7 +655,7 @@ mmap__sizeof__method(mmap_object *self, void *unused) { Py_ssize_t res; - res = sizeof(mmap_object); + res = _PyObject_SIZE(Py_TYPE(self)); if (self->tagname) res += strlen(self->tagname) + 1; return PyLong_FromSsize_t(res); diff --git a/Modules/parsermodule.c b/Modules/parsermodule.c index eb2d60068990..2434c6742ff8 100644 --- a/Modules/parsermodule.c +++ b/Modules/parsermodule.c @@ -720,7 +720,7 @@ parser_sizeof(PyST_Object *st, void *unused) { Py_ssize_t res; - res = sizeof(PyST_Object) + _PyNode_SizeOf(st->st_node); + res = _PyObject_SIZE(Py_TYPE(st)) + _PyNode_SizeOf(st->st_node); return PyLong_FromSsize_t(res); } diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 5276da51bdb7..1fdd9167fad7 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2780,7 +2780,7 @@ bytearray_sizeof(PyByteArrayObject *self) { Py_ssize_t res; - res = sizeof(PyByteArrayObject) + self->ob_alloc * sizeof(char); + res = _PyObject_SIZE(Py_TYPE(self)) + self->ob_alloc * sizeof(char); return PyInt_FromSsize_t(res); } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 50afa3f654a8..b281948be8f5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2152,7 +2152,7 @@ dict_sizeof(PyDictObject *mp) { Py_ssize_t res; - res = sizeof(PyDictObject); + res = _PyObject_SIZE(Py_TYPE(mp)); if (mp->ma_table != mp->ma_smalltable) res = res + (mp->ma_mask + 1) * sizeof(PyDictEntry); return PyInt_FromSsize_t(res); diff --git a/Objects/listobject.c b/Objects/listobject.c index 1f43ba292c39..27365b6e96bd 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2469,7 +2469,7 @@ list_sizeof(PyListObject *self) { Py_ssize_t res; - res = sizeof(PyListObject) + self->allocated * sizeof(void*); + res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*); return PyInt_FromSsize_t(res); } diff --git a/Objects/setobject.c b/Objects/setobject.c index 8a58d65d37dd..a9ebbec5a929 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1985,7 +1985,7 @@ set_sizeof(PySetObject *so) { Py_ssize_t res; - res = sizeof(PySetObject); + res = _PyObject_SIZE(Py_TYPE(so)); if (so->table != so->smalltable) res = res + (so->mask + 1) * sizeof(setentry); return PyInt_FromSsize_t(res);