From 3f16b927b6791867124ec969049fde4d61df0157 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 9 Apr 2014 23:55:56 -0400 Subject: PEP 465: a dedicated infix operator for matrix multiplication (closes #21176) --- Objects/typeobject.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c21b397c04..6129523afc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4469,6 +4469,8 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) COPYNUM(nb_inplace_true_divide); COPYNUM(nb_inplace_floor_divide); COPYNUM(nb_index); + COPYNUM(nb_matrix_multiply); + COPYNUM(nb_inplace_matrix_multiply); } if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { @@ -5605,6 +5607,7 @@ slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__") SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__") SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__") +SLOT1BIN(slot_nb_matrix_multiply, nb_matrix_multiply, "__matmul__", "__rmatmul__") SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__") SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__") @@ -5698,6 +5701,7 @@ SLOT0(slot_nb_float, "__float__") SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O") SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O") SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O") +SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *, "O") SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O") /* Can't use SLOT1 here, because nb_inplace_power is ternary */ static PyObject * @@ -6278,6 +6282,12 @@ static slotdef slotdefs[] = { "__index__($self, /)\n--\n\n" "Return self converted to an integer, if self is suitable" "for use as an index into a list."), + BINSLOT("__matmul__", nb_matrix_multiply, slot_nb_matrix_multiply, + "@"), + RBINSLOT("__rmatmul__", nb_matrix_multiply, slot_nb_matrix_multiply, + "@"), + IBSLOT("__imatmul__", nb_inplace_matrix_multiply, slot_nb_inplace_matrix_multiply, + wrap_binaryfunc, "@="), MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, "__len__($self, /)\n--\n\nReturn len(self)."), MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, -- cgit v1.2.1 From e82a87757b45cebe780ec2b7d67ff477cefcdd2d Mon Sep 17 00:00:00 2001 From: "Martin v. L?wis" Date: Sat, 26 Jul 2014 15:25:04 +0200 Subject: slotdefs is no longer sorted. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c759204dc0..4f87817984 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6509,7 +6509,7 @@ update_slots_callback(PyTypeObject *type, void *data) } /* Initialize the slotdefs table by adding interned string objects for the - names and sorting the entries. */ + names. */ static void init_slotdefs(void) { -- cgit v1.2.1 From 3e91844dcfbdc8300cb5e31263d2c8806b1f274f Mon Sep 17 00:00:00 2001 From: "Martin v. L?wis" Date: Sat, 26 Jul 2014 16:44:07 +0200 Subject: Issue #22082: Clear interned strings in slotdefs. --- Objects/typeobject.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4f87817984..b97c32ecbf 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -54,6 +54,9 @@ _Py_IDENTIFIER(builtins); static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +static void +clear_slotdefs(); + /* * finds the beginning of the docstring's introspection signature. * if present, returns a pointer pointing to the first '('. @@ -177,6 +180,7 @@ void _PyType_Fini(void) { PyType_ClearCache(); + clear_slotdefs(); } void @@ -6508,15 +6512,15 @@ update_slots_callback(PyTypeObject *type, void *data) return 0; } +static int slotdefs_initialized = 0; /* Initialize the slotdefs table by adding interned string objects for the names. */ static void init_slotdefs(void) { slotdef *p; - static int initialized = 0; - if (initialized) + if (slotdefs_initialized) return; for (p = slotdefs; p->name; p++) { /* Slots must be ordered by their offset in the PyHeapTypeObject. */ @@ -6525,7 +6529,17 @@ init_slotdefs(void) if (!p->name_strobj) Py_FatalError("Out of memory interning slotdef names"); } - initialized = 1; + slotdefs_initialized = 1; +} + +/* Undo init_slotdefs, releasing the interned strings. */ +static void clear_slotdefs() +{ + slotdef *p; + for (p = slotdefs; p->name; p++) { + Py_CLEAR(p->name_strobj); + } + slotdefs_initialized = 0; } /* Update the slots after assignment to a class (type) attribute. */ -- cgit v1.2.1 From d0584ccde6a9f568c7cca69da39a0832fd288ba2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 27 Jul 2014 16:11:30 +0200 Subject: Issue #22082: Fix a compiler warning (function is not a prototype) --- Objects/typeobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b97c32ecbf..8e7c25a213 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -55,7 +55,7 @@ static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static void -clear_slotdefs(); +clear_slotdefs(void); /* * finds the beginning of the docstring's introspection signature. @@ -6533,7 +6533,7 @@ init_slotdefs(void) } /* Undo init_slotdefs, releasing the interned strings. */ -static void clear_slotdefs() +static void clear_slotdefs(void) { slotdef *p; for (p = slotdefs; p->name; p++) { -- cgit v1.2.1 From 7a5afc4d6d3c15d94642f16035e4dd9693bed039 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 15 Aug 2014 23:17:38 +0200 Subject: Issue #22156: Fix "comparison between signed and unsigned integers" compiler warnings in the Objects/ subdirectory. PyType_FromSpecWithBases() and PyType_FromSpec() now reject explicitly negative slot identifiers. --- Objects/typeobject.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8e7c25a213..7438dedfa6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2622,7 +2622,8 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) type->tp_itemsize = spec->itemsize; for (slot = spec->slots; slot->slot; slot++) { - if (slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) { + if (slot->slot < 0 + || (size_t)slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) { PyErr_SetString(PyExc_RuntimeError, "invalid slot offset"); goto fail; } @@ -2682,11 +2683,11 @@ PyType_FromSpec(PyType_Spec *spec) void * PyType_GetSlot(PyTypeObject *type, int slot) { - if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + if (!PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0) { PyErr_BadInternalCall(); return NULL; } - if (slot >= Py_ARRAY_LENGTH(slotoffsets)) { + if ((size_t)slot >= Py_ARRAY_LENGTH(slotoffsets)) { /* Extension module requesting slot from a future version */ return NULL; } -- cgit v1.2.1 From 6d2758b51aa9ead9ba2336ef62c17a4f3287c73b Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sat, 15 Nov 2014 00:56:27 +0100 Subject: Issue #22847: Improve method cache efficiency. --- Objects/typeobject.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 574314f77e..ffd313d2fc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -14,10 +14,11 @@ MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large strings are used as attribute names. */ #define MCACHE_MAX_ATTR_SIZE 100 -#define MCACHE_SIZE_EXP 9 +#define MCACHE_SIZE_EXP 12 #define MCACHE_HASH(version, name_hash) \ - (((unsigned int)(version) * (unsigned int)(name_hash)) \ - >> (8*sizeof(unsigned int) - MCACHE_SIZE_EXP)) + (((unsigned int)(version) ^ (unsigned int)(name_hash)) \ + & ((1 << MCACHE_SIZE_EXP) - 1)) + #define MCACHE_HASH_METHOD(type, name) \ MCACHE_HASH((type)->tp_version_tag, \ ((PyASCIIObject *)(name))->hash) @@ -35,6 +36,14 @@ struct method_cache_entry { static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; static unsigned int next_version_tag = 0; +#define MCACHE_STATS 0 + +#if MCACHE_STATS +static size_t method_cache_hits = 0; +static size_t method_cache_misses = 0; +static size_t method_cache_collisions = 0; +#endif + /* alphabetical order */ _Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__class__); @@ -165,6 +174,18 @@ PyType_ClearCache(void) Py_ssize_t i; unsigned int cur_version_tag = next_version_tag - 1; +#if MCACHE_STATS + size_t total = method_cache_hits + method_cache_collisions + method_cache_misses; + fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n", + method_cache_hits, (int) (100.0 * method_cache_hits / total)); + fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n", + method_cache_misses, (int) (100.0 * method_cache_misses / total)); + fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n", + method_cache_collisions, (int) (100.0 * method_cache_collisions / total)); + fprintf(stderr, "-- Method cache size = %zd KB\n", + sizeof(method_cache) / 1024); +#endif + for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { method_cache[i].version = 0; Py_CLEAR(method_cache[i].name); @@ -2708,8 +2729,12 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) /* fast path */ h = MCACHE_HASH_METHOD(type, name); if (method_cache[h].version == type->tp_version_tag && - method_cache[h].name == name) + method_cache[h].name == name) { +#if MCACHE_STATS + method_cache_hits++; +#endif return method_cache[h].value; + } } /* Look in tp_dict of types in MRO */ @@ -2743,6 +2768,13 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) method_cache[h].version = type->tp_version_tag; method_cache[h].value = res; /* borrowed */ Py_INCREF(name); + assert(((PyASCIIObject *)(name))->hash != -1); +#if MCACHE_STATS + if (method_cache[h].name != Py_None && method_cache[h].name != name) + method_cache_collisions++; + else + method_cache_misses++; +#endif Py_DECREF(method_cache[h].name); method_cache[h].name = name; } -- cgit v1.2.1 From 16eae13e2b94ab10d3d6b8885f3ebee9e237cef1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 16 Dec 2014 19:43:46 +0200 Subject: Issue #22783: Pickling now uses the NEWOBJ opcode instead of the NEWOBJ_EX opcode if possible. --- Objects/typeobject.c | 160 ++++++++++++++++++++------------------------------- 1 file changed, 62 insertions(+), 98 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 941dedb0fa..dd8a940b1c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3886,48 +3886,87 @@ _PyObject_GetItemsIter(PyObject *obj, PyObject **listitems, } static PyObject * -reduce_4(PyObject *obj) +reduce_newobj(PyObject *obj, int proto) { PyObject *args = NULL, *kwargs = NULL; PyObject *copyreg; PyObject *newobj, *newargs, *state, *listitems, *dictitems; PyObject *result; - _Py_IDENTIFIER(__newobj_ex__); - if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) { + if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) return NULL; - } + if (args == NULL) { args = PyTuple_New(0); - if (args == NULL) - return NULL; - } - if (kwargs == NULL) { - kwargs = PyDict_New(); - if (kwargs == NULL) + if (args == NULL) { + Py_XDECREF(kwargs); return NULL; + } } - copyreg = import_copyreg(); if (copyreg == NULL) { Py_DECREF(args); - Py_DECREF(kwargs); + Py_XDECREF(kwargs); return NULL; } - newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj_ex__); - Py_DECREF(copyreg); - if (newobj == NULL) { + if (kwargs == NULL || PyDict_Size(kwargs) == 0) { + _Py_IDENTIFIER(__newobj__); + PyObject *cls; + Py_ssize_t i, n; + + Py_XDECREF(kwargs); + newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__); + Py_DECREF(copyreg); + if (newobj == NULL) { + Py_DECREF(args); + return NULL; + } + n = PyTuple_GET_SIZE(args); + newargs = PyTuple_New(n+1); + if (newargs == NULL) { + Py_DECREF(args); + Py_DECREF(newobj); + return NULL; + } + cls = (PyObject *) Py_TYPE(obj); + Py_INCREF(cls); + PyTuple_SET_ITEM(newargs, 0, cls); + for (i = 0; i < n; i++) { + PyObject *v = PyTuple_GET_ITEM(args, i); + Py_INCREF(v); + PyTuple_SET_ITEM(newargs, i+1, v); + } + Py_DECREF(args); + } + else if (proto >= 4) { + _Py_IDENTIFIER(__newobj_ex__); + + newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj_ex__); + Py_DECREF(copyreg); + if (newobj == NULL) { + Py_DECREF(args); + Py_DECREF(kwargs); + return NULL; + } + newargs = PyTuple_Pack(3, Py_TYPE(obj), args, kwargs); Py_DECREF(args); Py_DECREF(kwargs); - return NULL; + if (newargs == NULL) { + Py_DECREF(newobj); + return NULL; + } } - newargs = PyTuple_Pack(3, Py_TYPE(obj), args, kwargs); - Py_DECREF(args); - Py_DECREF(kwargs); - if (newargs == NULL) { - Py_DECREF(newobj); + else { + PyErr_SetString(PyExc_ValueError, + "must use protocol 4 or greater to copy this " + "object; since __getnewargs_ex__ returned " + "keyword arguments."); + Py_DECREF(args); + Py_DECREF(kwargs); + Py_DECREF(copyreg); return NULL; } + state = _PyObject_GetState(obj); if (state == NULL) { Py_DECREF(newobj); @@ -3950,79 +3989,6 @@ reduce_4(PyObject *obj) return result; } -static PyObject * -reduce_2(PyObject *obj) -{ - PyObject *cls; - PyObject *args = NULL, *args2 = NULL, *kwargs = NULL; - PyObject *state = NULL, *listitems = NULL, *dictitems = NULL; - PyObject *copyreg = NULL, *newobj = NULL, *res = NULL; - Py_ssize_t i, n; - _Py_IDENTIFIER(__newobj__); - - if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) { - return NULL; - } - if (args == NULL) { - assert(kwargs == NULL); - args = PyTuple_New(0); - if (args == NULL) { - return NULL; - } - } - else if (kwargs != NULL) { - if (PyDict_Size(kwargs) > 0) { - PyErr_SetString(PyExc_ValueError, - "must use protocol 4 or greater to copy this " - "object; since __getnewargs_ex__ returned " - "keyword arguments."); - Py_DECREF(args); - Py_DECREF(kwargs); - return NULL; - } - Py_CLEAR(kwargs); - } - - state = _PyObject_GetState(obj); - if (state == NULL) - goto end; - - if (_PyObject_GetItemsIter(obj, &listitems, &dictitems) < 0) - goto end; - - copyreg = import_copyreg(); - if (copyreg == NULL) - goto end; - newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__); - if (newobj == NULL) - goto end; - - n = PyTuple_GET_SIZE(args); - args2 = PyTuple_New(n+1); - if (args2 == NULL) - goto end; - cls = (PyObject *) Py_TYPE(obj); - Py_INCREF(cls); - PyTuple_SET_ITEM(args2, 0, cls); - for (i = 0; i < n; i++) { - PyObject *v = PyTuple_GET_ITEM(args, i); - Py_INCREF(v); - PyTuple_SET_ITEM(args2, i+1, v); - } - - res = PyTuple_Pack(5, newobj, args2, state, listitems, dictitems); - - end: - Py_XDECREF(args); - Py_XDECREF(args2); - Py_XDECREF(state); - Py_XDECREF(listitems); - Py_XDECREF(dictitems); - Py_XDECREF(copyreg); - Py_XDECREF(newobj); - return res; -} - /* * There were two problems when object.__reduce__ and object.__reduce_ex__ * were implemented in the same function: @@ -4043,10 +4009,8 @@ _common_reduce(PyObject *self, int proto) { PyObject *copyreg, *res; - if (proto >= 4) - return reduce_4(self); - else if (proto >= 2) - return reduce_2(self); + if (proto >= 2) + return reduce_newobj(self, proto); copyreg = import_copyreg(); if (!copyreg) -- cgit v1.2.1 From f02544f978557594adee2deb15c1a1b034df41a7 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 30 Jan 2015 13:33:42 -0500 Subject: allow changing __class__ between a heaptype and non-heaptype in some cases (closes #22986) Patch by Nathaniel Smith. --- Objects/typeobject.c | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 26 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 41771295e3..b911a0f7f2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1196,8 +1196,11 @@ subtype_dealloc(PyObject *self) assert(basedealloc); basedealloc(self); - /* Can't reference self beyond this point */ - Py_DECREF(type); + /* Can't reference self beyond this point. It's possible tp_del switched + our type from a HEAPTYPE to a non-HEAPTYPE, so be careful about + reference counting. */ + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_DECREF(type); endlabel: ++_PyTrash_delete_nesting; @@ -3425,17 +3428,18 @@ object_get_class(PyObject *self, void *closure) } static int -equiv_structs(PyTypeObject *a, PyTypeObject *b) +compatible_with_tp_base(PyTypeObject *child) { - return a == b || - (a != NULL && - b != NULL && - a->tp_basicsize == b->tp_basicsize && - a->tp_itemsize == b->tp_itemsize && - a->tp_dictoffset == b->tp_dictoffset && - a->tp_weaklistoffset == b->tp_weaklistoffset && - ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == - (b->tp_flags & Py_TPFLAGS_HAVE_GC))); + PyTypeObject *parent = child->tp_base; + return (parent != NULL && + child->tp_basicsize == parent->tp_basicsize && + child->tp_itemsize == parent->tp_itemsize && + child->tp_dictoffset == parent->tp_dictoffset && + child->tp_weaklistoffset == parent->tp_weaklistoffset && + ((child->tp_flags & Py_TPFLAGS_HAVE_GC) == + (parent->tp_flags & Py_TPFLAGS_HAVE_GC)) && + (child->tp_dealloc == subtype_dealloc || + child->tp_dealloc == parent->tp_dealloc)); } static int @@ -3453,6 +3457,10 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b) size += sizeof(PyObject *); /* Check slots compliance */ + if (!(a->tp_flags & Py_TPFLAGS_HEAPTYPE) || + !(b->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + return 0; + } slots_a = ((PyHeapTypeObject *)a)->ht_slots; slots_b = ((PyHeapTypeObject *)b)->ht_slots; if (slots_a && slots_b) { @@ -3468,9 +3476,7 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) { PyTypeObject *newbase, *oldbase; - if (newto->tp_dealloc != oldto->tp_dealloc || - newto->tp_free != oldto->tp_free) - { + if (newto->tp_free != oldto->tp_free) { PyErr_Format(PyExc_TypeError, "%s assignment: " "'%s' deallocator differs from '%s'", @@ -3479,11 +3485,21 @@ compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) oldto->tp_name); return 0; } + /* + It's tricky to tell if two arbitrary types are sufficiently compatible as + to be interchangeable; e.g., even if they have the same tp_basicsize, they + might have totally different struct fields. It's much easier to tell if a + type and its supertype are compatible; e.g., if they have the same + tp_basicsize, then that means they have identical fields. So to check + whether two arbitrary types are compatible, we first find the highest + supertype that each is compatible with, and then if those supertypes are + compatible then the original types must also be compatible. + */ newbase = newto; oldbase = oldto; - while (equiv_structs(newbase, newbase->tp_base)) + while (compatible_with_tp_base(newbase)) newbase = newbase->tp_base; - while (equiv_structs(oldbase, oldbase->tp_base)) + while (compatible_with_tp_base(oldbase)) oldbase = oldbase->tp_base; if (newbase != oldbase && (newbase->tp_base != oldbase->tp_base || @@ -3518,17 +3534,12 @@ object_set_class(PyObject *self, PyObject *value, void *closure) return -1; } newto = (PyTypeObject *)value; - if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) || - !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE)) - { - PyErr_Format(PyExc_TypeError, - "__class__ assignment: only for heap types"); - return -1; - } if (compatible_for_assignment(oldto, newto, "__class__")) { - Py_INCREF(newto); + if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_INCREF(newto); Py_TYPE(self) = newto; - Py_DECREF(oldto); + if (oldto->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_DECREF(oldto); return 0; } else { -- cgit v1.2.1 From 5fa611f66db5e0d62a6e0bf3258ec87b04d4c0ce Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 1 Mar 2015 10:03:02 +0200 Subject: Issue #20204: Deprecation warning is now raised for builtin type without the __module__ attribute. --- Objects/typeobject.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0ad7fd560..d59108ef2c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2808,6 +2808,12 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) _PyDict_SetItemId(type->tp_dict, &PyId___module__, PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name))); + else { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "builtin type %.200s has no the __module__ attribute", + spec->name)) + goto fail; + } return (PyObject*)res; -- cgit v1.2.1 From 0c393cd09d485c7756566c96c4c01e55d0dcfdf3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 1 Mar 2015 14:39:20 +0200 Subject: Fixed a typo. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d59108ef2c..be53868d93 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2810,7 +2810,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) spec->name, (Py_ssize_t)(s - spec->name))); else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "builtin type %.200s has no the __module__ attribute", + "builtin type %.200s has no __module__ attribute", spec->name)) goto fail; } -- cgit v1.2.1 From a6a9e6d9d2f1f73e3411fce9468b8dcf8478b707 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Mon, 13 Apr 2015 20:10:06 +0200 Subject: Issue #23726: Don't enable GC for user subclasses of non-GC types that don't add any new fields. Patch by Eugene Toder. --- Objects/typeobject.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 030dc1f836..0e54fe60b0 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2645,9 +2645,10 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } type->tp_dealloc = subtype_dealloc; - /* Enable GC unless there are really no instance variables possible */ - if (!(type->tp_basicsize == sizeof(PyObject) && - type->tp_itemsize == 0)) + /* Enable GC unless this class is not adding new instance variables and + the base class did not use GC. */ + if ((base->tp_flags & Py_TPFLAGS_HAVE_GC) || + type->tp_basicsize > base->tp_basicsize) type->tp_flags |= Py_TPFLAGS_HAVE_GC; /* Always override allocation strategy to use regular heap */ -- cgit v1.2.1 From 605ad6a026d02b5101c2d746d31e17ad52f902b1 Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Mon, 13 Apr 2015 18:22:35 -0500 Subject: Issue #20586: Argument Clinic now ensures signatures on functions without docstrings. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0e54fe60b0..4b992878bf 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -137,7 +137,7 @@ _PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc) { const char *doc = _PyType_DocWithoutSignature(name, internal_doc); - if (!doc) { + if (!doc || *doc == '\0') { Py_INCREF(Py_None); return Py_None; } -- cgit v1.2.1 From ea639832c36905ecb07caba111f614c4bbf9bdd6 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Mon, 11 May 2015 22:57:16 -0400 Subject: PEP 0492 -- Coroutines with async and await syntax. Issue #24017. --- Objects/typeobject.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 10 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4b992878bf..9522ac5809 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2506,6 +2506,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) type->tp_flags |= Py_TPFLAGS_HAVE_GC; /* Initialize essential fields */ + type->tp_as_async = &et->as_async; type->tp_as_number = &et->as_number; type->tp_as_sequence = &et->as_sequence; type->tp_as_mapping = &et->as_mapping; @@ -2751,6 +2752,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) } /* Initialize essential fields */ + type->tp_as_async = &res->as_async; type->tp_as_number = &res->as_number; type->tp_as_sequence = &res->as_sequence; type->tp_as_mapping = &res->as_mapping; @@ -4566,6 +4568,7 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) #define COPYSLOT(SLOT) \ if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT +#define COPYASYNC(SLOT) COPYSLOT(tp_as_async->SLOT) #define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT) #define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT) #define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT) @@ -4615,6 +4618,15 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) COPYNUM(nb_inplace_matrix_multiply); } + if (type->tp_as_async != NULL && base->tp_as_async != NULL) { + basebase = base->tp_base; + if (basebase->tp_as_async == NULL) + basebase = NULL; + COPYASYNC(am_await); + COPYASYNC(am_aiter); + COPYASYNC(am_anext); + } + if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { basebase = base->tp_base; if (basebase->tp_as_sequence == NULL) @@ -4884,6 +4896,8 @@ PyType_Ready(PyTypeObject *type) /* Some more special stuff */ base = type->tp_base; if (base != NULL) { + if (type->tp_as_async == NULL) + type->tp_as_async = base->tp_as_async; if (type->tp_as_number == NULL) type->tp_as_number = base->tp_as_number; if (type->tp_as_sequence == NULL) @@ -4904,16 +4918,6 @@ PyType_Ready(PyTypeObject *type) goto error; } - /* Warn for a type that implements tp_compare (now known as - tp_reserved) but not tp_richcompare. */ - if (type->tp_reserved && !type->tp_richcompare) { - PyErr_Format(PyExc_TypeError, - "Type %.100s defines tp_reserved (formerly tp_compare) " - "but not tp_richcompare. Comparisons may not behave as intended.", - type->tp_name); - goto error; - } - /* All done -- set the ready flag */ assert(type->tp_dict != NULL); type->tp_flags = @@ -6265,6 +6269,59 @@ slot_tp_finalize(PyObject *self) PyErr_Restore(error_type, error_value, error_traceback); } +static PyObject * +slot_am_await(PyObject *self) +{ + PyObject *func, *res; + _Py_IDENTIFIER(__await__); + + func = lookup_method(self, &PyId___await__); + if (func != NULL) { + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + return res; + } + PyErr_Format(PyExc_AttributeError, + "object %.50s does not have __await__ method", + Py_TYPE(self)->tp_name); + return NULL; +} + +static PyObject * +slot_am_aiter(PyObject *self) +{ + PyObject *func, *res; + _Py_IDENTIFIER(__aiter__); + + func = lookup_method(self, &PyId___aiter__); + if (func != NULL) { + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + return res; + } + PyErr_Format(PyExc_AttributeError, + "object %.50s does not have __aiter__ method", + Py_TYPE(self)->tp_name); + return NULL; +} + +static PyObject * +slot_am_anext(PyObject *self) +{ + PyObject *func, *res; + _Py_IDENTIFIER(__anext__); + + func = lookup_method(self, &PyId___anext__); + if (func != NULL) { + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + return res; + } + PyErr_Format(PyExc_AttributeError, + "object %.50s does not have __anext__ method", + Py_TYPE(self)->tp_name); + return NULL; +} /* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper functions. @@ -6281,6 +6338,7 @@ typedef struct wrapperbase slotdef; #undef TPSLOT #undef FLSLOT +#undef AMSLOT #undef ETSLOT #undef SQSLOT #undef MPSLOT @@ -6299,6 +6357,8 @@ typedef struct wrapperbase slotdef; #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC)} +#define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC) #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC) #define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ @@ -6378,6 +6438,13 @@ static slotdef slotdefs[] = { "Create and return new object. See help(type) for accurate signature."), TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), + AMSLOT("__await__", am_await, slot_am_await, wrap_unaryfunc, + "__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."), + AMSLOT("__aiter__", am_aiter, slot_am_aiter, wrap_unaryfunc, + "__aiter__($self, /)\n--\n\nReturn an awaitable, that resolves in asynchronous iterator."), + AMSLOT("__anext__", am_anext, slot_am_anext, wrap_unaryfunc, + "__anext__($self, /)\n--\n\nReturn a value or raise StopAsyncIteration."), + BINSLOT("__add__", nb_add, slot_nb_add, "+"), RBINSLOT("__radd__", nb_add, slot_nb_add, @@ -6530,6 +6597,10 @@ slotptr(PyTypeObject *type, int ioffset) ptr = (char *)type->tp_as_number; offset -= offsetof(PyHeapTypeObject, as_number); } + else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_async)) { + ptr = (char *)type->tp_as_async; + offset -= offsetof(PyHeapTypeObject, as_async); + } else { ptr = (char *)type; } -- cgit v1.2.1 From f6e3e7c93dbc3a08d386c440525fbfc7c004166f Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 24 May 2015 01:03:46 +1000 Subject: Issue #24268: Address some PEP 489 refleaks - missing DECREF in PyModule_FromDefAndSpec2 - missing DECREF in PyType_FromSpecAndBases2 - missing DECREF in _testmultiphase module Patch by Petr Viktorin --- Objects/typeobject.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9522ac5809..2f1779f970 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2694,6 +2694,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) { PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); PyTypeObject *type, *base; + PyObject *modname; char *s; char *res_start = (char*)res; PyType_Slot *slot; @@ -2807,11 +2808,15 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) /* Set type.__module__ */ s = strrchr(spec->name, '.'); - if (s != NULL) - _PyDict_SetItemId(type->tp_dict, &PyId___module__, - PyUnicode_FromStringAndSize( - spec->name, (Py_ssize_t)(s - spec->name))); - else { + if (s != NULL) { + modname = PyUnicode_FromStringAndSize( + spec->name, (Py_ssize_t)(s - spec->name)); + if (modname == NULL) { + goto fail; + } + _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + Py_DECREF(modname); + } else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "builtin type %.200s has no __module__ attribute", spec->name)) -- cgit v1.2.1 From 1f0eea05f78b032be72ee5b5787421acef61588d Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Fri, 3 Jul 2015 01:04:23 -0400 Subject: Issue #19235: Add new RecursionError exception. Patch by Georg Brandl. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 82c8710824..1beed72458 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4142,7 +4142,7 @@ reduce_newobj(PyObject *obj, int proto) * were implemented in the same function: * - trying to pickle an object with a custom __reduce__ method that * fell back to object.__reduce__ in certain circumstances led to - * infinite recursion at Python level and eventual RuntimeError. + * infinite recursion at Python level and eventual RecursionError. * - Pickling objects that lied about their type by overwriting the * __class__ descriptor could lead to infinite recursion at C level * and eventual segfault. -- cgit v1.2.1 From c3bbbe473406338fe66ea8e3fd76201ff981c68a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 3 Sep 2015 12:16:49 +0200 Subject: type_call() now detect bugs in type new and init * Call _Py_CheckFunctionResult() to check for bugs in type constructors (tp_new) * Add assertions to ensure an exception was raised if tp_init failed or that no exception was raised if tp_init succeed Refactor also the function to have less indentation. --- Objects/typeobject.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1beed72458..10115ef48c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -906,25 +906,33 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) #endif obj = type->tp_new(type, args, kwds); - if (obj != NULL) { - /* Ugly exception: when the call was type(something), - don't call tp_init on the result. */ - if (type == &PyType_Type && - PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && - (kwds == NULL || - (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) - return obj; - /* If the returned object is not an instance of type, - it won't be initialized. */ - if (!PyType_IsSubtype(Py_TYPE(obj), type)) - return obj; - type = Py_TYPE(obj); - if (type->tp_init != NULL) { - int res = type->tp_init(obj, args, kwds); - if (res < 0) { - Py_DECREF(obj); - obj = NULL; - } + obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL); + if (obj == NULL) + return NULL; + + /* Ugly exception: when the call was type(something), + don't call tp_init on the result. */ + if (type == &PyType_Type && + PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && + (kwds == NULL || + (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) + return obj; + + /* If the returned object is not an instance of type, + it won't be initialized. */ + if (!PyType_IsSubtype(Py_TYPE(obj), type)) + return obj; + + type = Py_TYPE(obj); + if (type->tp_init != NULL) { + int res = type->tp_init(obj, args, kwds); + if (res < 0) { + assert(PyErr_Occurred()); + Py_DECREF(obj); + obj = NULL; + } + else { + assert(!PyErr_Occurred()); } } return obj; -- cgit v1.2.1 From 9dba6a9c00ed30a53e2c98ff294eb7ea9add3c1b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 4 Sep 2015 20:54:07 -0700 Subject: Issue #24912: Prevent __class__ assignment to immutable built-in objects. --- Objects/typeobject.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1beed72458..bb83530d58 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3666,6 +3666,65 @@ object_set_class(PyObject *self, PyObject *value, void *closure) return -1; } newto = (PyTypeObject *)value; + /* In versions of CPython prior to 3.5, the code in + compatible_for_assignment was not set up to correctly check for memory + layout / slot / etc. compatibility for non-HEAPTYPE classes, so we just + disallowed __class__ assignment in any case that wasn't HEAPTYPE -> + HEAPTYPE. + + During the 3.5 development cycle, we fixed the code in + compatible_for_assignment to correctly check compatibility between + arbitrary types, and started allowing __class__ assignment in all cases + where the old and new types did in fact have compatible slots and + memory layout (regardless of whether they were implemented as HEAPTYPEs + or not). + + Just before 3.5 was released, though, we discovered that this led to + problems with immutable types like int, where the interpreter assumes + they are immutable and interns some values. Formerly this wasn't a + problem, because they really were immutable -- in particular, all the + types where the interpreter applied this interning trick happened to + also be statically allocated, so the old HEAPTYPE rules were + "accidentally" stopping them from allowing __class__ assignment. But + with the changes to __class__ assignment, we started allowing code like + + class MyInt(int): + ... + # Modifies the type of *all* instances of 1 in the whole program, + # including future instances (!), because the 1 object is interned. + (1).__class__ = MyInt + + (see https://bugs.python.org/issue24912). + + In theory the proper fix would be to identify which classes rely on + this invariant and somehow disallow __class__ assignment only for them, + perhaps via some mechanism like a new Py_TPFLAGS_IMMUTABLE flag (a + "blacklisting" approach). But in practice, since this problem wasn't + noticed late in the 3.5 RC cycle, we're taking the conservative + approach and reinstating the same HEAPTYPE->HEAPTYPE check that we used + to have, plus a "whitelist". For now, the whitelist consists only of + ModuleType subtypes, since those are the cases that motivated the patch + in the first place -- see https://bugs.python.org/issue22986 -- and + since module objects are mutable we can be sure that they are + definitely not being interned. So now we allow HEAPTYPE->HEAPTYPE *or* + ModuleType subtype -> ModuleType subtype. + + So far as we know, all the code beyond the following 'if' statement + will correctly handle non-HEAPTYPE classes, and the HEAPTYPE check is + needed only to protect that subset of non-HEAPTYPE classes for which + the interpreter has baked in the assumption that all instances are + truly immutable. + */ + if (!(PyType_IsSubtype(newto, &PyModule_Type) && + PyType_IsSubtype(oldto, &PyModule_Type)) && + (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) || + !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))) { + PyErr_Format(PyExc_TypeError, + "__class__ assignment only supported for heap types " + "or ModuleType subclasses"); + return -1; + } + if (compatible_for_assignment(oldto, newto, "__class__")) { if (newto->tp_flags & Py_TPFLAGS_HEAPTYPE) Py_INCREF(newto); -- cgit v1.2.1 From d27a1d900d4ab8640d81864e9bf33ecf43663bd3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 10 Oct 2015 22:42:18 +0300 Subject: Issue #24164: Objects that need calling ``__new__`` with keyword arguments, can now be pickled using pickle protocols older than protocol version 4. --- Objects/typeobject.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4b091f5dfd..bf0d30cac3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4101,7 +4101,7 @@ _PyObject_GetItemsIter(PyObject *obj, PyObject **listitems, } static PyObject * -reduce_newobj(PyObject *obj, int proto) +reduce_newobj(PyObject *obj) { PyObject *args = NULL, *kwargs = NULL; PyObject *copyreg; @@ -4153,7 +4153,7 @@ reduce_newobj(PyObject *obj, int proto) } Py_DECREF(args); } - else if (proto >= 4) { + else { _Py_IDENTIFIER(__newobj_ex__); newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj_ex__); @@ -4171,16 +4171,6 @@ reduce_newobj(PyObject *obj, int proto) return NULL; } } - else { - PyErr_SetString(PyExc_ValueError, - "must use protocol 4 or greater to copy this " - "object; since __getnewargs_ex__ returned " - "keyword arguments."); - Py_DECREF(args); - Py_DECREF(kwargs); - Py_DECREF(copyreg); - return NULL; - } state = _PyObject_GetState(obj); if (state == NULL) { @@ -4225,7 +4215,7 @@ _common_reduce(PyObject *self, int proto) PyObject *copyreg, *res; if (proto >= 2) - return reduce_newobj(self, proto); + return reduce_newobj(self); copyreg = import_copyreg(); if (!copyreg) -- cgit v1.2.1 From 585a1eed45faea53f836b1db2ac211d7f14b44c8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 24 Dec 2015 10:35:59 +0200 Subject: Issue #20440: Massive replacing unsafe attribute setting code with special macro Py_SETREF. --- Objects/typeobject.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0b94fc5263..5b858bde03 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -315,9 +315,8 @@ assign_version_tag(PyTypeObject *type) are borrowed reference */ for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { method_cache[i].value = NULL; - Py_XDECREF(method_cache[i].name); - method_cache[i].name = Py_None; Py_INCREF(Py_None); + Py_SETREF(method_cache[i].name, Py_None); } /* mark all version tags as invalid */ PyType_Modified(&PyBaseObject_Type); @@ -462,8 +461,7 @@ type_set_qualname(PyTypeObject *type, PyObject *value, void *context) et = (PyHeapTypeObject*)type; Py_INCREF(value); - Py_DECREF(et->ht_qualname); - et->ht_qualname = value; + Py_SETREF(et->ht_qualname, value); return 0; } @@ -2910,8 +2908,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) else method_cache_misses++; #endif - Py_DECREF(method_cache[h].name); - method_cache[h].name = name; + Py_SETREF(method_cache[h].name, name); } return res; } -- cgit v1.2.1 From d1ba93f9a6a441ac31c5fd1890ce730b9e6d330d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Dec 2015 19:53:18 +0200 Subject: Issue #25923: Added the const qualifier to static constant arrays. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 341e18c455..b4d23b257a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2690,7 +2690,7 @@ error: return NULL; } -static short slotoffsets[] = { +static const short slotoffsets[] = { -1, /* invalid slot */ #include "typeslots.inc" }; -- cgit v1.2.1 From 5c633fc25fc6f9beee3ccb9ebc06633d1c9a1bc3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Dec 2015 20:01:53 +0200 Subject: Issue #25923: Added more const qualifiers to signatures of static and private functions. --- Objects/typeobject.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b4d23b257a..2e75ec378d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -564,7 +564,7 @@ type_get_bases(PyTypeObject *type, void *context) static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *, PyObject **); Py_LOCAL_INLINE(int) type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); -static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); +static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, const char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); static void remove_subclass(PyTypeObject *, PyTypeObject *); @@ -1435,7 +1435,7 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *o, _Py_Identifier *nameid, char *format, ...) +call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; PyObject *args, *func = 0, *retval; @@ -1471,7 +1471,7 @@ call_method(PyObject *o, _Py_Identifier *nameid, char *format, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *o, _Py_Identifier *nameid, char *format, ...) +call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; PyObject *args, *func = 0, *retval; @@ -3609,7 +3609,7 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b) } static int -compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) +compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, const char* attr) { PyTypeObject *newbase, *oldbase; @@ -5348,7 +5348,7 @@ wrap_delitem(PyObject *self, PyObject *args, void *wrapped) /* Helper to check for object.__setattr__ or __delattr__ applied to a type. This is called the Carlo Verre hack after its discoverer. */ static int -hackcheck(PyObject *self, setattrofunc func, char *what) +hackcheck(PyObject *self, setattrofunc func, const char *what) { PyTypeObject *type = Py_TYPE(self); while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE) -- cgit v1.2.1 From c97e8ffd1bf41d72f12266e67464ed89d8d395a5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Dec 2015 21:04:29 +0200 Subject: Issue #22995: Instances of extension types with a state that aren't subclasses of list or dict and haven't implemented any pickle-related methods (__reduce__, __reduce_ex__, __getnewargs__, __getnewargs_ex__, or __getstate__), can no longer be pickled. Including memoryview. --- Objects/typeobject.c | 51 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5b858bde03..f3c0c38ee6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3831,7 +3831,7 @@ _PyType_GetSlotNames(PyTypeObject *cls) } Py_LOCAL(PyObject *) -_PyObject_GetState(PyObject *obj) +_PyObject_GetState(PyObject *obj, int required) { PyObject *state; PyObject *getstate; @@ -3846,6 +3846,13 @@ _PyObject_GetState(PyObject *obj) } PyErr_Clear(); + if (required && obj->ob_type->tp_itemsize) { + PyErr_Format(PyExc_TypeError, + "can't pickle %.200s objects", + Py_TYPE(obj)->tp_name); + return NULL; + } + { PyObject **dict; dict = _PyObject_GetDictPtr(obj); @@ -3870,6 +3877,24 @@ _PyObject_GetState(PyObject *obj) } assert(slotnames == Py_None || PyList_Check(slotnames)); + if (required) { + Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize; + if (obj->ob_type->tp_dictoffset) + basicsize += sizeof(PyObject *); + if (obj->ob_type->tp_weaklistoffset) + basicsize += sizeof(PyObject *); + if (slotnames != Py_None) + basicsize += sizeof(PyObject *) * Py_SIZE(slotnames); + if (obj->ob_type->tp_basicsize > basicsize) { + Py_DECREF(slotnames); + Py_DECREF(state); + PyErr_Format(PyExc_TypeError, + "can't pickle %.200s objects", + Py_TYPE(obj)->tp_name); + return NULL; + } + } + if (slotnames != Py_None && Py_SIZE(slotnames) > 0) { PyObject *slots; Py_ssize_t slotnames_size, i; @@ -4099,29 +4124,24 @@ reduce_newobj(PyObject *obj, int proto) PyObject *copyreg; PyObject *newobj, *newargs, *state, *listitems, *dictitems; PyObject *result; + int hasargs; if (Py_TYPE(obj)->tp_new == NULL) { PyErr_Format(PyExc_TypeError, - "can't pickle %s objects", + "can't pickle %.200s objects", Py_TYPE(obj)->tp_name); return NULL; } if (_PyObject_GetNewArguments(obj, &args, &kwargs) < 0) return NULL; - if (args == NULL) { - args = PyTuple_New(0); - if (args == NULL) { - Py_XDECREF(kwargs); - return NULL; - } - } copyreg = import_copyreg(); if (copyreg == NULL) { - Py_DECREF(args); + Py_XDECREF(args); Py_XDECREF(kwargs); return NULL; } + hasargs = (args != NULL); if (kwargs == NULL || PyDict_Size(kwargs) == 0) { _Py_IDENTIFIER(__newobj__); PyObject *cls; @@ -4131,13 +4151,13 @@ reduce_newobj(PyObject *obj, int proto) newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj__); Py_DECREF(copyreg); if (newobj == NULL) { - Py_DECREF(args); + Py_XDECREF(args); return NULL; } - n = PyTuple_GET_SIZE(args); + n = args ? PyTuple_GET_SIZE(args) : 0; newargs = PyTuple_New(n+1); if (newargs == NULL) { - Py_DECREF(args); + Py_XDECREF(args); Py_DECREF(newobj); return NULL; } @@ -4149,7 +4169,7 @@ reduce_newobj(PyObject *obj, int proto) Py_INCREF(v); PyTuple_SET_ITEM(newargs, i+1, v); } - Py_DECREF(args); + Py_XDECREF(args); } else if (proto >= 4) { _Py_IDENTIFIER(__newobj_ex__); @@ -4180,7 +4200,8 @@ reduce_newobj(PyObject *obj, int proto) return NULL; } - state = _PyObject_GetState(obj); + state = _PyObject_GetState(obj, + !hasargs && !PyList_Check(obj) && !PyDict_Check(obj)); if (state == NULL) { Py_DECREF(newobj); Py_DECREF(newargs); -- cgit v1.2.1 From 20cb777d0019af42d191eaf5d425cc8671960a89 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Dec 2015 15:51:32 +0200 Subject: Issue #20440: Cleaning up the code by using Py_SETREF and Py_CLEAR. Old code is correct, but with Py_SETREF and Py_CLEAR it can be cleaner. This patch doesn't fix bugs and hence there is no need to backport it. --- Objects/typeobject.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4fac9e889b..78ef6acb13 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -401,7 +401,6 @@ type_qualname(PyTypeObject *type, void *context) static int type_set_name(PyTypeObject *type, PyObject *value, void *context) { - PyHeapTypeObject* et; char *tp_name; PyObject *tmp; @@ -430,17 +429,9 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context) if (tp_name == NULL) return -1; - et = (PyHeapTypeObject*)type; - - Py_INCREF(value); - - /* Wait until et is a sane state before Py_DECREF'ing the old et->ht_name - value. (Bug #16447.) */ - tmp = et->ht_name; - et->ht_name = value; - type->tp_name = tp_name; - Py_DECREF(tmp); + Py_INCREF(value); + Py_SETREF(((PyHeapTypeObject*)type)->ht_name, value); return 0; } -- cgit v1.2.1 From 90b6e92589b676bb61451143afe2a3b41c9464ca Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 30 Dec 2015 21:40:49 +0200 Subject: Issue #25961: Disallowed null characters in the type name. Simplified testing for null characters in __name__ setter. --- Objects/typeobject.c | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f3c0c38ee6..2e68043053 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -401,9 +401,8 @@ type_qualname(PyTypeObject *type, void *context) static int type_set_name(PyTypeObject *type, PyObject *value, void *context) { - PyHeapTypeObject* et; - char *tp_name; - PyObject *tmp; + const char *tp_name; + Py_ssize_t name_size; if (!check_set_special_type_attr(type, value, "__name__")) return -1; @@ -414,33 +413,18 @@ type_set_name(PyTypeObject *type, PyObject *value, void *context) return -1; } - /* Check absence of null characters */ - tmp = PyUnicode_FromStringAndSize("\0", 1); - if (tmp == NULL) + tp_name = PyUnicode_AsUTF8AndSize(value, &name_size); + if (tp_name == NULL) return -1; - if (PyUnicode_Contains(value, tmp) != 0) { - Py_DECREF(tmp); - PyErr_Format(PyExc_ValueError, - "__name__ must not contain null bytes"); + if (strlen(tp_name) != (size_t)name_size) { + PyErr_SetString(PyExc_ValueError, + "type name must not contain null characters"); return -1; } - Py_DECREF(tmp); - - tp_name = _PyUnicode_AsString(value); - if (tp_name == NULL) - return -1; - - et = (PyHeapTypeObject*)type; - - Py_INCREF(value); - - /* Wait until et is a sane state before Py_DECREF'ing the old et->ht_name - value. (Bug #16447.) */ - tmp = et->ht_name; - et->ht_name = value; type->tp_name = tp_name; - Py_DECREF(tmp); + Py_INCREF(value); + Py_SETREF(((PyHeapTypeObject*)type)->ht_name, value); return 0; } @@ -2285,8 +2269,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) PyTypeObject *type = NULL, *base, *tmptype, *winner; PyHeapTypeObject *et; PyMemberDef *mp; - Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; - int j, may_add_dict, may_add_weak; + Py_ssize_t i, nbases, nslots, slotoffset, name_size; + int j, may_add_dict, may_add_weak, add_dict, add_weak; _Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__slots__); @@ -2509,9 +2493,14 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) type->tp_as_sequence = &et->as_sequence; type->tp_as_mapping = &et->as_mapping; type->tp_as_buffer = &et->as_buffer; - type->tp_name = _PyUnicode_AsString(name); + type->tp_name = PyUnicode_AsUTF8AndSize(name, &name_size); if (!type->tp_name) goto error; + if (strlen(type->tp_name) != (size_t)name_size) { + PyErr_SetString(PyExc_ValueError, + "type name must not contain null characters"); + goto error; + } /* Set tp_base and tp_bases */ type->tp_bases = bases; -- cgit v1.2.1 From 93c98b688bef3bf08c027315a744869b590ceef3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Jan 2016 21:27:54 +0200 Subject: Issue #20440: Cleaning up the code by using Py_SETREF. --- Objects/typeobject.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c62255c5b0..db15cf6768 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2092,7 +2092,7 @@ subtype_dict(PyObject *obj, void *context) static int subtype_setdict(PyObject *obj, PyObject *value, void *context) { - PyObject *dict, **dictptr; + PyObject **dictptr; PyTypeObject *base; base = get_builtin_base_with_dict(Py_TYPE(obj)); @@ -2123,10 +2123,8 @@ subtype_setdict(PyObject *obj, PyObject *value, void *context) "not a '%.200s'", Py_TYPE(value)->tp_name); return -1; } - dict = *dictptr; Py_XINCREF(value); - *dictptr = value; - Py_XDECREF(dict); + Py_SETREF(*dictptr, value); return 0; } -- cgit v1.2.1 From 1271ab3c67c3d6f9bdc2c4323aabbe0b2e3efd27 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Mon, 11 Jan 2016 13:24:02 -0500 Subject: Issue #22995: [UPDATE] Comment out the one of the pickleability tests in _PyObject_GetState() due to regressions observed in Cython-based projects. --- Objects/typeobject.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2e68043053..ff4ae11164 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3866,6 +3866,14 @@ _PyObject_GetState(PyObject *obj, int required) } assert(slotnames == Py_None || PyList_Check(slotnames)); +#if 0 + /* 2016-01-11 barry - This clause breaks at least three packages which + rely on Cython: kivy, pysam, and s3ql. Cython may be doing + something funny under the hood, but as this is clearly a regression + and the rationale for this prohibition is suspect, I am commenting + this out. Perhaps it should just be removed. See issue #22995 for + details. + */ if (required) { Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize; if (obj->ob_type->tp_dictoffset) @@ -3883,6 +3891,7 @@ _PyObject_GetState(PyObject *obj, int required) return NULL; } } +#endif if (slotnames != Py_None && Py_SIZE(slotnames) > 0) { PyObject *slots; -- cgit v1.2.1 From 028051a2a3459e763954ad2e6712a9b4e5e0b6f6 Mon Sep 17 00:00:00 2001 From: Barry Warsaw Date: Mon, 11 Jan 2016 15:14:53 -0500 Subject: Comment out some tests that won't pass now that we've reverted the picklability regression. Also, as per further discussion, remove the regressing code. --- Objects/typeobject.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ff4ae11164..415f91689f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3866,33 +3866,6 @@ _PyObject_GetState(PyObject *obj, int required) } assert(slotnames == Py_None || PyList_Check(slotnames)); -#if 0 - /* 2016-01-11 barry - This clause breaks at least three packages which - rely on Cython: kivy, pysam, and s3ql. Cython may be doing - something funny under the hood, but as this is clearly a regression - and the rationale for this prohibition is suspect, I am commenting - this out. Perhaps it should just be removed. See issue #22995 for - details. - */ - if (required) { - Py_ssize_t basicsize = PyBaseObject_Type.tp_basicsize; - if (obj->ob_type->tp_dictoffset) - basicsize += sizeof(PyObject *); - if (obj->ob_type->tp_weaklistoffset) - basicsize += sizeof(PyObject *); - if (slotnames != Py_None) - basicsize += sizeof(PyObject *) * Py_SIZE(slotnames); - if (obj->ob_type->tp_basicsize > basicsize) { - Py_DECREF(slotnames); - Py_DECREF(state); - PyErr_Format(PyExc_TypeError, - "can't pickle %.200s objects", - Py_TYPE(obj)->tp_name); - return NULL; - } - } -#endif - if (slotnames != Py_None && Py_SIZE(slotnames) > 0) { PyObject *slots; Py_ssize_t slotnames_size, i; -- cgit v1.2.1 From 6df5ed569792f159da524e1f85afd986cf26d038 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 18 Jan 2016 21:11:18 -0800 Subject: set tp_new from the class in the hierarchy that actually owns the descriptor (closes #25731) Debugging by Eryk Sun. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 415f91689f..810afd3d61 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6777,7 +6777,7 @@ update_one_slot(PyTypeObject *type, slotdef *p) sanity checks and constructing a new argument list. Cut all that nonsense short -- this speeds up instance creation tremendously. */ - specific = (void *)type->tp_new; + specific = (void *)((PyTypeObject *)PyCFunction_GET_SELF(descr))->tp_new; /* XXX I'm not 100% sure that there isn't a hole in this reasoning that requires additional sanity checks. I'll buy the first person to -- cgit v1.2.1 From 04feb0393f788b3479a8d13b2bf4aaa9bb431c99 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Fri, 29 Apr 2016 16:54:10 +0300 Subject: Fix typos. Reported by andportnoy on GitHub. --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2086e9d243..9e7b4e6483 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3944,7 +3944,7 @@ _PyObject_GetState(PyObject *obj, int required) } /* If we found some slot attributes, pack them in a tuple along - the orginal attribute dictionary. */ + the original attribute dictionary. */ if (PyDict_Size(slots) > 0) { PyObject *state2; -- cgit v1.2.1 From 3c597ab05e274ee6c8a9eb2c6a0c8e2e34a9d1e4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 May 2016 16:14:55 +0300 Subject: Issue #27118: Clean up Py_XINCREF/Py_XDECREF in typeobject.c. Patch by Xiang Zhang. --- Objects/typeobject.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9e7b4e6483..f869c8d835 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -460,7 +460,7 @@ type_module(PyTypeObject *type, void *context) PyErr_Format(PyExc_AttributeError, "__module__"); return 0; } - Py_XINCREF(mod); + Py_INCREF(mod); return mod; } else { @@ -500,7 +500,7 @@ type_abstractmethods(PyTypeObject *type, void *context) PyErr_SetObject(PyExc_AttributeError, message); return NULL; } - Py_XINCREF(mod); + Py_INCREF(mod); return mod; } @@ -1534,7 +1534,6 @@ class_name(PyObject *cls) PyObject *name = _PyObject_GetAttrId(cls, &PyId___name__); if (name == NULL) { PyErr_Clear(); - Py_XDECREF(name); name = PyObject_Repr(cls); } if (name == NULL) @@ -5776,8 +5775,8 @@ slot_sq_item(PyObject *self, Py_ssize_t i) if (args != NULL) { PyTuple_SET_ITEM(args, 0, ival); retval = PyObject_Call(func, args, NULL); - Py_XDECREF(args); - Py_XDECREF(func); + Py_DECREF(args); + Py_DECREF(func); return retval; } } -- cgit v1.2.1 From b2bfc00b0792a26f499225fc5dd60b9b7e9287f3 Mon Sep 17 00:00:00 2001 From: Kushal Das Date: Sat, 4 Jun 2016 16:21:13 -0700 Subject: Issue #25548: Showing memory address of class objects in repl --- Objects/typeobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a64779177c..78d5c1ee51 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -859,9 +859,9 @@ type_repr(PyTypeObject *type) } if (mod != NULL && _PyUnicode_CompareWithId(mod, &PyId_builtins)) - rtn = PyUnicode_FromFormat("", mod, name); - else - rtn = PyUnicode_FromFormat("", type->tp_name); + rtn = PyUnicode_FromFormat("", mod, name, type); + else + rtn = PyUnicode_FromFormat("", type->tp_name, type); Py_XDECREF(mod); Py_DECREF(name); -- cgit v1.2.1 From daf3dbb16a92e9d37441b1e5ea737a41be5bc07f Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Wed, 13 Jul 2016 21:13:29 -0700 Subject: Backed out changeset af29d89083b3 (closes #25548) (closes #27498) --- Objects/typeobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 618d629acb..5227f6a609 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -859,9 +859,9 @@ type_repr(PyTypeObject *type) } if (mod != NULL && _PyUnicode_CompareWithId(mod, &PyId_builtins)) - rtn = PyUnicode_FromFormat("", mod, name, type); - else - rtn = PyUnicode_FromFormat("", type->tp_name, type); + rtn = PyUnicode_FromFormat("", mod, name); + else + rtn = PyUnicode_FromFormat("", type->tp_name); Py_XDECREF(mod); Py_DECREF(name); -- cgit v1.2.1 From cb4af3cc4c01baeea5ff7e41ca7de1f877222535 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 30 Jul 2016 16:26:03 +1000 Subject: Issue #27366: Implement PEP 487 - __init_subclass__ called when new subclasses defined - __set_name__ called when descriptors are part of a class definition --- Objects/typeobject.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 7 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5227f6a609..2498b1f6fd 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -53,10 +53,12 @@ _Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__getattribute__); _Py_IDENTIFIER(__getitem__); _Py_IDENTIFIER(__hash__); +_Py_IDENTIFIER(__init_subclass__); _Py_IDENTIFIER(__len__); _Py_IDENTIFIER(__module__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__new__); +_Py_IDENTIFIER(__set_name__); _Py_IDENTIFIER(__setitem__); _Py_IDENTIFIER(builtins); @@ -2027,6 +2029,8 @@ static void object_dealloc(PyObject *); static int object_init(PyObject *, PyObject *, PyObject *); static int update_slot(PyTypeObject *, PyObject *); static void fixup_slot_dispatchers(PyTypeObject *); +static int set_names(PyTypeObject *); +static int init_subclass(PyTypeObject *, PyObject *); /* * Helpers for __dict__ descriptor. We don't want to expose the dicts @@ -2202,7 +2206,8 @@ type_init(PyObject *cls, PyObject *args, PyObject *kwds) assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); - if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { + if (kwds != NULL && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && + PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { PyErr_SetString(PyExc_TypeError, "type.__init__() takes no keyword arguments"); return -1; @@ -2269,7 +2274,6 @@ static PyObject * type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { PyObject *name, *bases = NULL, *orig_dict, *dict = NULL; - static char *kwlist[] = {"name", "bases", "dict", 0}; PyObject *qualname, *slots = NULL, *tmp, *newslots; PyTypeObject *type = NULL, *base, *tmptype, *winner; PyHeapTypeObject *et; @@ -2296,7 +2300,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) /* SF bug 475327 -- if that didn't trigger, we need 3 arguments. but PyArg_ParseTupleAndKeywords below may give a msg saying type() needs exactly 3. */ - if (nargs + nkwds != 3) { + if (nargs != 3) { PyErr_SetString(PyExc_TypeError, "type() takes 1 or 3 arguments"); return NULL; @@ -2304,10 +2308,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } /* Check arguments: (name, bases, dict) */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "UO!O!:type", kwlist, - &name, - &PyTuple_Type, &bases, - &PyDict_Type, &orig_dict)) + if (!PyArg_ParseTuple(args, "UO!O!:type", &name, &PyTuple_Type, &bases, + &PyDict_Type, &orig_dict)) return NULL; /* Determine the proper metatype to deal with this: */ @@ -2587,6 +2589,20 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) Py_DECREF(tmp); } + /* Special-case __init_subclass__: if it's a plain function, + make it a classmethod */ + tmp = _PyDict_GetItemId(dict, &PyId___init_subclass__); + if (tmp != NULL && PyFunction_Check(tmp)) { + tmp = PyClassMethod_New(tmp); + if (tmp == NULL) + goto error; + if (_PyDict_SetItemId(dict, &PyId___init_subclass__, tmp) < 0) { + Py_DECREF(tmp); + goto error; + } + Py_DECREF(tmp); + } + /* Add descriptors for custom slots from __slots__, or for __dict__ */ mp = PyHeapType_GET_MEMBERS(et); slotoffset = base->tp_basicsize; @@ -2667,6 +2683,12 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) et->ht_cached_keys = _PyDict_NewKeysForClass(); } + if (set_names(type) < 0) + goto error; + + if (init_subclass(type, kwds) < 0) + goto error; + Py_DECREF(dict); return (PyObject *)type; @@ -4312,6 +4334,19 @@ PyDoc_STRVAR(object_subclasshook_doc, "NotImplemented, the normal algorithm is used. Otherwise, it\n" "overrides the normal algorithm (and the outcome is cached).\n"); +static PyObject * +object_init_subclass(PyObject *cls, PyObject *arg) +{ + Py_RETURN_NONE; +} + +PyDoc_STRVAR(object_init_subclass_doc, +"This method is called when a class is subclassed\n" +"\n" +"Whenever a class is subclassed, this method is called. The default\n" +"implementation does nothing. It may be overridden to extend\n" +"subclasses.\n"); + /* from PEP 3101, this code implements: @@ -4416,6 +4451,8 @@ static PyMethodDef object_methods[] = { PyDoc_STR("helper for pickle")}, {"__subclasshook__", object_subclasshook, METH_CLASS | METH_VARARGS, object_subclasshook_doc}, + {"__init_subclass__", object_init_subclass, METH_CLASS | METH_NOARGS, + object_init_subclass_doc}, {"__format__", object_format, METH_VARARGS, PyDoc_STR("default object formatter")}, {"__sizeof__", object_sizeof, METH_NOARGS, @@ -6925,6 +6962,54 @@ update_all_slots(PyTypeObject* type) } } +/* Call __set_name__ on all descriptors in a newly generated type */ +static int +set_names(PyTypeObject *type) +{ + PyObject *key, *value, *tmp; + Py_ssize_t i = 0; + + while (PyDict_Next(type->tp_dict, &i, &key, &value)) { + if (PyObject_HasAttr(value, _PyUnicode_FromId(&PyId___set_name__))) { + tmp = PyObject_CallMethodObjArgs( + value, _PyUnicode_FromId(&PyId___set_name__), + type, key, NULL); + if (tmp == NULL) + return -1; + else + Py_DECREF(tmp); + } + } + + return 0; +} + +/* Call __init_subclass__ on the parent of a newly generated type */ +static int +init_subclass(PyTypeObject *type, PyObject *kwds) +{ + PyObject *super, *func, *tmp, *tuple; + + super = PyObject_CallFunctionObjArgs((PyObject *) &PySuper_Type, + type, type, NULL); + func = _PyObject_GetAttrId(super, &PyId___init_subclass__); + Py_DECREF(super); + + if (func == NULL) + return -1; + + tuple = PyTuple_New(0); + tmp = PyObject_Call(func, tuple, kwds); + Py_DECREF(tuple); + Py_DECREF(func); + + if (tmp == NULL) + return -1; + + Py_DECREF(tmp); + return 0; +} + /* recurse_down_subclasses() and update_subclasses() are mutually recursive functions to call a callback for all subclasses, but refraining from recursing into subclasses that define 'name'. */ -- cgit v1.2.1 From 320abf0a0c2055e8f172c1aeab9fa51b37a9ac68 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Sat, 30 Jul 2016 14:06:15 +0300 Subject: Issue #27366: Tweak PEP 487 documentation * Added versionadded directives * Deleted duplicate sentence from __init_subclass__ docstring * Modernized tests --- Objects/typeobject.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2498b1f6fd..683484abb4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4341,11 +4341,10 @@ object_init_subclass(PyObject *cls, PyObject *arg) } PyDoc_STRVAR(object_init_subclass_doc, -"This method is called when a class is subclassed\n" +"This method is called when a class is subclassed.\n" "\n" -"Whenever a class is subclassed, this method is called. The default\n" -"implementation does nothing. It may be overridden to extend\n" -"subclasses.\n"); +"The default implementation does nothing. It may be\n" +"overridden to extend subclasses.\n"); /* from PEP 3101, this code implements: -- cgit v1.2.1 From 00e6e6f7a778b035d8d138c6955dbbede87c155f Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 18 Aug 2016 09:22:23 -0700 Subject: Anti-registration of various ABC methods. - Issue #25958: Support "anti-registration" of special methods from various ABCs, like __hash__, __iter__ or __len__. All these (and several more) can be set to None in an implementation class and the behavior will be as if the method is not defined at all. (Previously, this mechanism existed only for __hash__, to make mutable classes unhashable.) Code contributed by Andrew Barnert and Ivan Levkivskyi. --- Objects/typeobject.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b1686d258b..1b4c2613b5 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5856,6 +5856,13 @@ slot_sq_contains(PyObject *self, PyObject *value) _Py_IDENTIFIER(__contains__); func = lookup_maybe(self, &PyId___contains__); + if (func == Py_None) { + Py_DECREF(func); + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not a container", + Py_TYPE(self)->tp_name); + return -1; + } if (func != NULL) { args = PyTuple_Pack(1, value); if (args == NULL) @@ -6241,6 +6248,13 @@ slot_tp_iter(PyObject *self) _Py_IDENTIFIER(__iter__); func = lookup_method(self, &PyId___iter__); + if (func == Py_None) { + Py_DECREF(func); + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not iterable", + Py_TYPE(self)->tp_name); + return NULL; + } if (func != NULL) { PyObject *args; args = res = PyTuple_New(0); -- cgit v1.2.1 From 4966c1cb947fa33dbb34b49840a1fc8c191330c6 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Fri, 19 Aug 2016 11:04:07 +0300 Subject: Issue #27157: Make only type() itself accept the one-argument form Patch by Eryk Sun and Emanuel Barry. --- Objects/typeobject.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1b4c2613b5..d141bf4b40 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2287,11 +2287,13 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) assert(kwds == NULL || PyDict_Check(kwds)); /* Special case: type(x) should return x->ob_type */ - { + /* We only want type itself to accept the one-argument form (#27157) + Note: We don't call PyType_CheckExact as that also allows subclasses */ + if (metatype == &PyType_Type) { const Py_ssize_t nargs = PyTuple_GET_SIZE(args); const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); - if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) { + if (nargs == 1 && nkwds == 0) { PyObject *x = PyTuple_GET_ITEM(args, 0); Py_INCREF(Py_TYPE(x)); return (PyObject *) Py_TYPE(x); @@ -2308,8 +2310,8 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } /* Check arguments: (name, bases, dict) */ - if (!PyArg_ParseTuple(args, "UO!O!:type", &name, &PyTuple_Type, &bases, - &PyDict_Type, &orig_dict)) + if (!PyArg_ParseTuple(args, "UO!O!:type.__new__", &name, &PyTuple_Type, + &bases, &PyDict_Type, &orig_dict)) return NULL; /* Determine the proper metatype to deal with this: */ -- cgit v1.2.1 From 1434d8dc96f1738f62e8a4735404b1471a40688b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 17:48:51 +0200 Subject: contains and rich compare slots use fast call Issue #27128. Modify slot_sq_contains() and slot_tp_richcompare() to use fast call to avoid a temporary tuple to pass a single positional parameter. --- Objects/typeobject.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d141bf4b40..a190e7ae43 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5853,7 +5853,7 @@ slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) static int slot_sq_contains(PyObject *self, PyObject *value) { - PyObject *func, *res, *args; + PyObject *func, *res; int result = -1; _Py_IDENTIFIER(__contains__); @@ -5866,13 +5866,7 @@ slot_sq_contains(PyObject *self, PyObject *value) return -1; } if (func != NULL) { - args = PyTuple_Pack(1, value); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = _PyObject_FastCall(func, &value, 1, NULL); Py_DECREF(func); if (res != NULL) { result = PyObject_IsTrue(res); @@ -6225,20 +6219,14 @@ static _Py_Identifier name_op[] = { static PyObject * slot_tp_richcompare(PyObject *self, PyObject *other, int op) { - PyObject *func, *args, *res; + PyObject *func, *res; func = lookup_method(self, &name_op[op]); if (func == NULL) { PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - args = PyTuple_Pack(1, other); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = _PyObject_FastCall(func, &other, 1, NULL); Py_DECREF(func); return res; } -- cgit v1.2.1 From c44ca6083a84f6f2b0f46277b473ef870cd33612 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:01:41 +0200 Subject: Cleanup call_method() and call_maybe() Issue #27128. Move va_start/va_end around Py_VaBuildValue(). --- Objects/typeobject.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0440180028..10ced8b064 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1425,23 +1425,22 @@ call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; PyObject *args, *func = 0, *retval; - va_start(va, format); func = lookup_maybe(o, nameid); if (func == NULL) { - va_end(va); if (!PyErr_Occurred()) PyErr_SetObject(PyExc_AttributeError, nameid->object); return NULL; } - if (format && *format) + if (format && *format) { + va_start(va, format); args = Py_VaBuildValue(format, va); - else + va_end(va); + } + else { args = PyTuple_New(0); - - va_end(va); - + } if (args == NULL) { Py_DECREF(func); return NULL; @@ -1463,23 +1462,22 @@ call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; PyObject *args, *func = 0, *retval; - va_start(va, format); func = lookup_maybe(o, nameid); if (func == NULL) { - va_end(va); if (!PyErr_Occurred()) Py_RETURN_NOTIMPLEMENTED; return NULL; } - if (format && *format) + if (format && *format) { + va_start(va, format); args = Py_VaBuildValue(format, va); - else + va_end(va); + } + else { args = PyTuple_New(0); - - va_end(va); - + } if (args == NULL) { Py_DECREF(func); return NULL; -- cgit v1.2.1 From f725eb48b01fa96a43122a22ec995c461293c3f9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:05:37 +0200 Subject: call_method() and call_maybe() now use fast call Issue #27128. The call_method() and call_maybe() functions of typeobject.c now use fast call for empty format string to avoid the creation of a temporary empty tuple. --- Objects/typeobject.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 10ced8b064..4f01da01b9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1424,7 +1424,7 @@ static PyObject * call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; - PyObject *args, *func = 0, *retval; + PyObject *func = NULL, *retval; func = lookup_maybe(o, nameid); if (func == NULL) { @@ -1434,22 +1434,25 @@ call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) } if (format && *format) { + PyObject *args; + va_start(va, format); args = Py_VaBuildValue(format, va); va_end(va); + + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + assert(PyTuple_Check(args)); + + retval = PyObject_Call(func, args, NULL); + Py_DECREF(args); } else { - args = PyTuple_New(0); - } - if (args == NULL) { - Py_DECREF(func); - return NULL; + retval = _PyObject_FastCall(func, NULL, 0, NULL); } - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); Py_DECREF(func); return retval; @@ -1461,7 +1464,7 @@ static PyObject * call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; - PyObject *args, *func = 0, *retval; + PyObject *func = NULL, *retval; func = lookup_maybe(o, nameid); if (func == NULL) { @@ -1471,22 +1474,25 @@ call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) } if (format && *format) { + PyObject *args; + va_start(va, format); args = Py_VaBuildValue(format, va); va_end(va); + + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + assert(PyTuple_Check(args)); + + retval = PyObject_Call(func, args, NULL); + Py_DECREF(args); } else { - args = PyTuple_New(0); - } - if (args == NULL) { - Py_DECREF(func); - return NULL; + retval = _PyObject_FastCall(func, NULL, 0, NULL); } - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); Py_DECREF(func); return retval; -- cgit v1.2.1 From 4c1cb5a27fe59a4f5356279daa7b14221e1c1d48 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:17:37 +0200 Subject: Issue #27128: Cleanup slot_sq_item() * Invert condition of test to avoid levels of indentation * Remove useless Py_XDECREF(args) in the error block * Replace Py_XDECREF(func) with Py_DECREF(func) in the error block: func cannot be NULL when reaching the error block --- Objects/typeobject.c | 58 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4f01da01b9..ff9f0204e9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5808,38 +5808,46 @@ slot_sq_length(PyObject *self) static PyObject * slot_sq_item(PyObject *self, Py_ssize_t i) { - PyObject *func, *args = NULL, *ival = NULL, *retval = NULL; + PyObject *func, *ival = NULL, *args, *retval = NULL; descrgetfunc f; func = _PyType_LookupId(Py_TYPE(self), &PyId___getitem__); - if (func != NULL) { - if ((f = Py_TYPE(func)->tp_descr_get) == NULL) - Py_INCREF(func); - else { - func = f(func, self, (PyObject *)(Py_TYPE(self))); - if (func == NULL) { - return NULL; - } - } - ival = PyLong_FromSsize_t(i); - if (ival != NULL) { - args = PyTuple_New(1); - if (args != NULL) { - PyTuple_SET_ITEM(args, 0, ival); - retval = PyObject_Call(func, args, NULL); - Py_DECREF(args); - Py_DECREF(func); - return retval; - } - } - } - else { + if (func == NULL) { PyObject *getitem_str = _PyUnicode_FromId(&PyId___getitem__); PyErr_SetObject(PyExc_AttributeError, getitem_str); + return NULL; + } + + f = Py_TYPE(func)->tp_descr_get; + if (f == NULL) { + Py_INCREF(func); } - Py_XDECREF(args); + else { + func = f(func, self, (PyObject *)(Py_TYPE(self))); + if (func == NULL) { + return NULL; + } + } + + ival = PyLong_FromSsize_t(i); + if (ival == NULL) { + goto error; + } + + args = PyTuple_New(1); + if (args == NULL) { + goto error; + } + + PyTuple_SET_ITEM(args, 0, ival); + retval = PyObject_Call(func, args, NULL); + Py_DECREF(func); + Py_DECREF(args); + return retval; + +error: + Py_DECREF(func); Py_XDECREF(ival); - Py_XDECREF(func); return NULL; } -- cgit v1.2.1 From 107b191464d64458c03d036dcb133c30a27356e1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:19:42 +0200 Subject: Issue #27128: slot_sq_item() uses fast call slot_sq_item() now calls _PyObject_FastCall() to avoid the creation of a temporary tuple of 1 item to pass the 'item' argument to the slot function. --- Objects/typeobject.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ff9f0204e9..364841b0b4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5808,7 +5808,7 @@ slot_sq_length(PyObject *self) static PyObject * slot_sq_item(PyObject *self, Py_ssize_t i) { - PyObject *func, *ival = NULL, *args, *retval = NULL; + PyObject *func, *ival = NULL, *retval = NULL; descrgetfunc f; func = _PyType_LookupId(Py_TYPE(self), &PyId___getitem__); @@ -5834,20 +5834,13 @@ slot_sq_item(PyObject *self, Py_ssize_t i) goto error; } - args = PyTuple_New(1); - if (args == NULL) { - goto error; - } - - PyTuple_SET_ITEM(args, 0, ival); - retval = PyObject_Call(func, args, NULL); + retval = _PyObject_FastCall(func, &ival, 1, NULL); Py_DECREF(func); - Py_DECREF(args); + Py_DECREF(ival); return retval; error: Py_DECREF(func); - Py_XDECREF(ival); return NULL; } -- cgit v1.2.1 From 31433949bbc16164aef14a5af4a47640d2181ab2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:26:05 +0200 Subject: Issue #27128: Cleanup slot_nb_bool() Use an error label to reduce the level of indentation. --- Objects/typeobject.c | 66 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 25 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 364841b0b4..46f944c804 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5946,44 +5946,60 @@ SLOT0(slot_nb_absolute, "__abs__") static int slot_nb_bool(PyObject *self) { - PyObject *func, *args; - int result = -1; + PyObject *func, *args, *value; + int result; int using_len = 0; _Py_IDENTIFIER(__bool__); func = lookup_maybe(self, &PyId___bool__); if (func == NULL) { - if (PyErr_Occurred()) + if (PyErr_Occurred()) { return -1; + } + func = lookup_maybe(self, &PyId___len__); - if (func == NULL) - return PyErr_Occurred() ? -1 : 1; + if (func == NULL) { + if (PyErr_Occurred()) { + return -1; + } + return 1; + } using_len = 1; } + args = PyTuple_New(0); - if (args != NULL) { - PyObject *temp = PyObject_Call(func, args, NULL); - Py_DECREF(args); - if (temp != NULL) { - if (using_len) { - /* enforced by slot_nb_len */ - result = PyObject_IsTrue(temp); - } - else if (PyBool_Check(temp)) { - result = PyObject_IsTrue(temp); - } - else { - PyErr_Format(PyExc_TypeError, - "__bool__ should return " - "bool, returned %s", - Py_TYPE(temp)->tp_name); - result = -1; - } - Py_DECREF(temp); - } + if (args == NULL) { + goto error; + } + + value = PyObject_Call(func, args, NULL); + Py_DECREF(args); + if (value == NULL) { + goto error; + } + + if (using_len) { + /* bool type enforced by slot_nb_len */ + result = PyObject_IsTrue(value); + } + else if (PyBool_Check(value)) { + result = PyObject_IsTrue(value); } + else { + PyErr_Format(PyExc_TypeError, + "__bool__ should return " + "bool, returned %s", + Py_TYPE(value)->tp_name); + result = -1; + } + + Py_DECREF(value); Py_DECREF(func); return result; + +error: + Py_DECREF(func); + return -1; } -- cgit v1.2.1 From c5761642a0f022aff6887307c8539112193f07c2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:28:25 +0200 Subject: slot_nb_bool() now uses fast call Issue #27128: slot_nb_bool() now calls _PyObject_FastCall() to avoid a temporary empty tuple to call the slot function. --- Objects/typeobject.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 46f944c804..4d259275b4 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5946,7 +5946,7 @@ SLOT0(slot_nb_absolute, "__abs__") static int slot_nb_bool(PyObject *self) { - PyObject *func, *args, *value; + PyObject *func, *value; int result; int using_len = 0; _Py_IDENTIFIER(__bool__); @@ -5967,13 +5967,7 @@ slot_nb_bool(PyObject *self) using_len = 1; } - args = PyTuple_New(0); - if (args == NULL) { - goto error; - } - - value = PyObject_Call(func, args, NULL); - Py_DECREF(args); + value = _PyObject_FastCall(func, NULL, 0, NULL); if (value == NULL) { goto error; } -- cgit v1.2.1 From 9483ca3a2676f58de4d8283a818433897eb1fe49 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 18:41:02 +0200 Subject: slot_tp_iter() now uses fast call Issue #27128: slot_tp_iter() now calls _PyObject_FastCall() to avoid a temporary empty tuple. --- Objects/typeobject.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4d259275b4..68e4f90ab6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6264,16 +6264,13 @@ slot_tp_iter(PyObject *self) Py_TYPE(self)->tp_name); return NULL; } + if (func != NULL) { - PyObject *args; - args = res = PyTuple_New(0); - if (args != NULL) { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = _PyObject_FastCall(func, NULL, 0, NULL); Py_DECREF(func); return res; } + PyErr_Clear(); func = lookup_method(self, &PyId___getitem__); if (func == NULL) { -- cgit v1.2.1 From 2c2ff9db2a19f46cc47ecbf47a839dbca9927ca7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 20 Aug 2016 02:37:41 +0200 Subject: Issue #27366: Fix init_subclass() Handle PyTuple_New(0) failure. --- Objects/typeobject.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 68e4f90ab6..0f18355853 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7018,6 +7018,11 @@ init_subclass(PyTypeObject *type, PyObject *kwds) return -1; tuple = PyTuple_New(0); + if (tuple == NULL) { + Py_DECREF(func); + return 0; + } + tmp = PyObject_Call(func, tuple, kwds); Py_DECREF(tuple); Py_DECREF(func); -- cgit v1.2.1 From de03c6d8066496680a1ea99ff9e67e28852b0007 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 22:48:54 +0200 Subject: Rename _PyObject_FastCall() to _PyObject_FastCallDict() Issue #27809: * Rename _PyObject_FastCall() function to _PyObject_FastCallDict() * Add _PyObject_FastCall(), _PyObject_CallNoArg() and _PyObject_CallArg1() macros calling _PyObject_FastCallDict() --- Objects/typeobject.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0f18355853..544d0b5f4e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1450,7 +1450,7 @@ call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) Py_DECREF(args); } else { - retval = _PyObject_FastCall(func, NULL, 0, NULL); + retval = _PyObject_CallNoArg(func); } Py_DECREF(func); @@ -1490,7 +1490,7 @@ call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) Py_DECREF(args); } else { - retval = _PyObject_FastCall(func, NULL, 0, NULL); + retval = _PyObject_CallNoArg(func); } Py_DECREF(func); @@ -5834,7 +5834,7 @@ slot_sq_item(PyObject *self, Py_ssize_t i) goto error; } - retval = _PyObject_FastCall(func, &ival, 1, NULL); + retval = _PyObject_CallArg1(func, ival); Py_DECREF(func); Py_DECREF(ival); return retval; @@ -5875,7 +5875,7 @@ slot_sq_contains(PyObject *self, PyObject *value) return -1; } if (func != NULL) { - res = _PyObject_FastCall(func, &value, 1, NULL); + res = _PyObject_CallArg1(func, value); Py_DECREF(func); if (res != NULL) { result = PyObject_IsTrue(res); @@ -5967,7 +5967,7 @@ slot_nb_bool(PyObject *self) using_len = 1; } - value = _PyObject_FastCall(func, NULL, 0, NULL); + value = _PyObject_CallNoArg(func); if (value == NULL) { goto error; } @@ -6245,7 +6245,7 @@ slot_tp_richcompare(PyObject *self, PyObject *other, int op) PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - res = _PyObject_FastCall(func, &other, 1, NULL); + res = _PyObject_CallArg1(func, other); Py_DECREF(func); return res; } @@ -6266,7 +6266,7 @@ slot_tp_iter(PyObject *self) } if (func != NULL) { - res = _PyObject_FastCall(func, NULL, 0, NULL); + res = _PyObject_CallNoArg(func); Py_DECREF(func); return res; } -- cgit v1.2.1 From 04ca689091773fa19c16bcacfccae2914e3fae56 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 23:33:13 +0200 Subject: Issue #27809: Use _PyObject_FastCallDict() Modify: * init_subclass() * builtin___build_class__() Fix also a bug in init_subclass(): check for super() failure. --- Objects/typeobject.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 544d0b5f4e..63bfd66747 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7007,30 +7007,28 @@ set_names(PyTypeObject *type) static int init_subclass(PyTypeObject *type, PyObject *kwds) { - PyObject *super, *func, *tmp, *tuple; + PyObject *super, *func, *result; + PyObject *args[2] = {(PyObject *)type, (PyObject *)type}; + + super = _PyObject_FastCall((PyObject *)&PySuper_Type, args, 2); + if (super == NULL) { + return -1; + } - super = PyObject_CallFunctionObjArgs((PyObject *) &PySuper_Type, - type, type, NULL); func = _PyObject_GetAttrId(super, &PyId___init_subclass__); Py_DECREF(super); - - if (func == NULL) + if (func == NULL) { return -1; - - tuple = PyTuple_New(0); - if (tuple == NULL) { - Py_DECREF(func); - return 0; } - tmp = PyObject_Call(func, tuple, kwds); - Py_DECREF(tuple); - Py_DECREF(func); - if (tmp == NULL) + result = _PyObject_FastCallDict(func, NULL, 0, kwds); + Py_DECREF(func); + if (result == NULL) { return -1; + } - Py_DECREF(tmp); + Py_DECREF(result); return 0; } -- cgit v1.2.1 From 1de419b3db8739947ef8c2fe36ce3944d8576fd5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 01:04:14 +0200 Subject: method_call() and slot_tp_new() now uses fast call Issue #27841: Add _PyObject_Call_Prepend() helper function to prepend an argument to existing arguments to call a function. This helper uses fast calls. Modify method_call() and slot_tp_new() to use _PyObject_Call_Prepend(). --- Objects/typeobject.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 63bfd66747..9b3d1533e9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6356,29 +6356,16 @@ slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *func; - PyObject *newargs, *x; - Py_ssize_t i, n; + PyObject *func, *result; func = _PyObject_GetAttrId((PyObject *)type, &PyId___new__); - if (func == NULL) - return NULL; - assert(PyTuple_Check(args)); - n = PyTuple_GET_SIZE(args); - newargs = PyTuple_New(n+1); - if (newargs == NULL) + if (func == NULL) { return NULL; - Py_INCREF(type); - PyTuple_SET_ITEM(newargs, 0, (PyObject *)type); - for (i = 0; i < n; i++) { - x = PyTuple_GET_ITEM(args, i); - Py_INCREF(x); - PyTuple_SET_ITEM(newargs, i+1, x); } - x = PyObject_Call(func, newargs, kwds); - Py_DECREF(newargs); + + result = _PyObject_Call_Prepend(func, (PyObject *)type, args, kwds); Py_DECREF(func); - return x; + return result; } static void -- cgit v1.2.1 From 4846ba81c69ebc815b35a89ed54fef7b5ffb1417 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 30 Aug 2016 10:47:49 -0700 Subject: Issue #27895: Spelling fixes (Contributed by Ville Skytt?). --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9b3d1533e9..5f0db2b005 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3792,7 +3792,7 @@ import_copyreg(void) /* Try to fetch cached copy of copyreg from sys.modules first in an attempt to avoid the import overhead. Previously this was implemented by storing a reference to the cached module in a static variable, but - this broke when multiple embeded interpreters were in use (see issue + this broke when multiple embedded interpreters were in use (see issue #17408 and #19088). */ copyreg_module = PyDict_GetItemWithError(interp->modules, copyreg_str); if (copyreg_module != NULL) { -- cgit v1.2.1 From 823616bdc22856b5df918a443051ec6ec2e9073c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 5 Sep 2016 14:50:11 -0700 Subject: Issue #24254: Preserve class attribute definition order. --- Objects/typeobject.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5f0db2b005..6cffb4e8ff 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -48,6 +48,7 @@ static size_t method_cache_collisions = 0; _Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__delitem__); +_Py_IDENTIFIER(__definition_order__); _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__getattribute__); @@ -488,6 +489,23 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context) return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value); } +static PyObject * +type_deforder(PyTypeObject *type, void *context) +{ + if (type->tp_deforder == NULL) + Py_RETURN_NONE; + Py_INCREF(type->tp_deforder); + return type->tp_deforder; +} + +static int +type_set_deforder(PyTypeObject *type, PyObject *value, void *context) +{ + Py_XINCREF(value); + Py_XSETREF(type->tp_deforder, value); + return 0; +} + static PyObject * type_abstractmethods(PyTypeObject *type, void *context) { @@ -834,6 +852,8 @@ static PyGetSetDef type_getsets[] = { {"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, + {"__definition_order__", (getter)type_deforder, + (setter)type_set_deforder, NULL}, {"__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, @@ -2351,6 +2371,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) goto error; } + /* Copy the definition namespace into a new dict. */ dict = PyDict_Copy(orig_dict); if (dict == NULL) goto error; @@ -2559,6 +2580,48 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0) goto error; + /* Set tp_deforder to the extracted definition order, if any. */ + type->tp_deforder = _PyDict_GetItemId(dict, &PyId___definition_order__); + if (type->tp_deforder != NULL) { + Py_INCREF(type->tp_deforder); + + // Due to subclass lookup, __definition_order__ can't be in __dict__. + if (_PyDict_DelItemId(dict, &PyId___definition_order__) != 0) { + goto error; + } + + if (type->tp_deforder != Py_None) { + Py_ssize_t numnames; + + if (!PyTuple_Check(type->tp_deforder)) { + PyErr_SetString(PyExc_TypeError, + "__definition_order__ must be a tuple or None"); + goto error; + } + + // Make sure they are identifers. + numnames = PyTuple_Size(type->tp_deforder); + for (i = 0; i < numnames; i++) { + PyObject *name = PyTuple_GET_ITEM(type->tp_deforder, i); + if (name == NULL) { + goto error; + } + if (!PyUnicode_Check(name) || !PyUnicode_IsIdentifier(name)) { + PyErr_Format(PyExc_TypeError, + "__definition_order__ must " + "contain only identifiers, got '%s'", + name); + goto error; + } + } + } + } + else if (PyODict_Check(orig_dict)) { + type->tp_deforder = _PyODict_KeysAsTuple(orig_dict); + if (type->tp_deforder == NULL) + goto error; + } + /* Set tp_doc to a copy of dict['__doc__'], if the latter is there and is a string. The __doc__ accessor will first look for tp_doc; if that fails, it will still look into __dict__. @@ -3073,6 +3136,7 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); Py_XDECREF(type->tp_subclasses); + Py_XDECREF(type->tp_deforder); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. */ @@ -3115,7 +3179,7 @@ type_subclasses(PyTypeObject *type, PyObject *args_ignored) static PyObject * type_prepare(PyObject *self, PyObject *args, PyObject *kwds) { - return PyDict_New(); + return PyODict_New(); } /* -- cgit v1.2.1 From b10682a8d65eacac79b39a62ff45a15e0ac95f05 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 5 Sep 2016 17:53:15 -0700 Subject: Avoid inefficient way to call functions without argument Don't pass "()" format to PyObject_CallXXX() to call a function without argument: pass NULL as the format string instead. It avoids to have to parse a string to produce 0 argument. --- Objects/typeobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6cffb4e8ff..209d4fab1f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5758,7 +5758,7 @@ static PyObject * \ FUNCNAME(PyObject *self) \ { \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, "()"); \ + return call_method(self, &id, NULL); \ } #define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ @@ -5851,7 +5851,7 @@ FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \ static Py_ssize_t slot_sq_length(PyObject *self) { - PyObject *res = call_method(self, &PyId___len__, "()"); + PyObject *res = call_method(self, &PyId___len__, NULL); Py_ssize_t len; if (res == NULL) @@ -6065,7 +6065,7 @@ static PyObject * slot_nb_index(PyObject *self) { _Py_IDENTIFIER(__index__); - return call_method(self, &PyId___index__, "()"); + return call_method(self, &PyId___index__, NULL); } @@ -6351,7 +6351,7 @@ static PyObject * slot_tp_iternext(PyObject *self) { _Py_IDENTIFIER(__next__); - return call_method(self, &PyId___next__, "()"); + return call_method(self, &PyId___next__, NULL); } static PyObject * -- cgit v1.2.1 From 5249b35e30923b3c09496e98d40a9b2977f0098f Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Fri, 9 Sep 2016 00:21:22 +0200 Subject: Additional safe-guard against dereferencing NULL in reduce_newobj _PyObject_GetNewArguments() can leave args == NULL but the __newobj_ex__ branch expects args to be not-NULL. CID 1353201 --- Objects/typeobject.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 209d4fab1f..ae593636e6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4263,7 +4263,7 @@ reduce_newobj(PyObject *obj) } Py_XDECREF(args); } - else { + else if (args != NULL) { _Py_IDENTIFIER(__newobj_ex__); newobj = _PyObject_GetAttrId(copyreg, &PyId___newobj_ex__); @@ -4281,6 +4281,12 @@ reduce_newobj(PyObject *obj) return NULL; } } + else { + /* args == NULL */ + Py_DECREF(kwargs); + PyErr_BadInternalCall(); + return NULL; + } state = _PyObject_GetState(obj, !hasargs && !PyList_Check(obj) && !PyDict_Check(obj)); -- cgit v1.2.1 From 761928cf31626534ebb81a6326c61b42050ef388 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 8 Sep 2016 15:11:11 -0700 Subject: Issue #24254: Drop cls.__definition_order__. --- Objects/typeobject.c | 66 +--------------------------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ae593636e6..42054d42af 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -48,7 +48,6 @@ static size_t method_cache_collisions = 0; _Py_IDENTIFIER(__abstractmethods__); _Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__delitem__); -_Py_IDENTIFIER(__definition_order__); _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__getattribute__); @@ -489,23 +488,6 @@ type_set_module(PyTypeObject *type, PyObject *value, void *context) return _PyDict_SetItemId(type->tp_dict, &PyId___module__, value); } -static PyObject * -type_deforder(PyTypeObject *type, void *context) -{ - if (type->tp_deforder == NULL) - Py_RETURN_NONE; - Py_INCREF(type->tp_deforder); - return type->tp_deforder; -} - -static int -type_set_deforder(PyTypeObject *type, PyObject *value, void *context) -{ - Py_XINCREF(value); - Py_XSETREF(type->tp_deforder, value); - return 0; -} - static PyObject * type_abstractmethods(PyTypeObject *type, void *context) { @@ -852,8 +834,6 @@ static PyGetSetDef type_getsets[] = { {"__qualname__", (getter)type_qualname, (setter)type_set_qualname, NULL}, {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, {"__module__", (getter)type_module, (setter)type_set_module, NULL}, - {"__definition_order__", (getter)type_deforder, - (setter)type_set_deforder, NULL}, {"__abstractmethods__", (getter)type_abstractmethods, (setter)type_set_abstractmethods, NULL}, {"__dict__", (getter)type_dict, NULL, NULL}, @@ -2371,7 +2351,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) goto error; } - /* Copy the definition namespace into a new dict. */ dict = PyDict_Copy(orig_dict); if (dict == NULL) goto error; @@ -2580,48 +2559,6 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0) goto error; - /* Set tp_deforder to the extracted definition order, if any. */ - type->tp_deforder = _PyDict_GetItemId(dict, &PyId___definition_order__); - if (type->tp_deforder != NULL) { - Py_INCREF(type->tp_deforder); - - // Due to subclass lookup, __definition_order__ can't be in __dict__. - if (_PyDict_DelItemId(dict, &PyId___definition_order__) != 0) { - goto error; - } - - if (type->tp_deforder != Py_None) { - Py_ssize_t numnames; - - if (!PyTuple_Check(type->tp_deforder)) { - PyErr_SetString(PyExc_TypeError, - "__definition_order__ must be a tuple or None"); - goto error; - } - - // Make sure they are identifers. - numnames = PyTuple_Size(type->tp_deforder); - for (i = 0; i < numnames; i++) { - PyObject *name = PyTuple_GET_ITEM(type->tp_deforder, i); - if (name == NULL) { - goto error; - } - if (!PyUnicode_Check(name) || !PyUnicode_IsIdentifier(name)) { - PyErr_Format(PyExc_TypeError, - "__definition_order__ must " - "contain only identifiers, got '%s'", - name); - goto error; - } - } - } - } - else if (PyODict_Check(orig_dict)) { - type->tp_deforder = _PyODict_KeysAsTuple(orig_dict); - if (type->tp_deforder == NULL) - goto error; - } - /* Set tp_doc to a copy of dict['__doc__'], if the latter is there and is a string. The __doc__ accessor will first look for tp_doc; if that fails, it will still look into __dict__. @@ -3136,7 +3073,6 @@ type_dealloc(PyTypeObject *type) Py_XDECREF(type->tp_mro); Py_XDECREF(type->tp_cache); Py_XDECREF(type->tp_subclasses); - Py_XDECREF(type->tp_deforder); /* A type's tp_doc is heap allocated, unlike the tp_doc slots * of most other objects. It's okay to cast it to char *. */ @@ -3179,7 +3115,7 @@ type_subclasses(PyTypeObject *type, PyObject *args_ignored) static PyObject * type_prepare(PyObject *self, PyObject *args, PyObject *kwds) { - return PyODict_New(); + return PyDict_New(); } /* -- cgit v1.2.1 From 21f4abc1820999f668eee3f1d07e177d7f5d1bbd Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 9 Sep 2016 12:42:51 -0700 Subject: remove unconvincing use of Py_LOCAL --- Objects/typeobject.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 42054d42af..df0481dd58 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -549,7 +549,7 @@ type_get_bases(PyTypeObject *type, void *context) static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *, PyObject **); -Py_LOCAL_INLINE(int) type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); +static int type_is_subtype_base_chain(PyTypeObject *, PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, const char *); static int add_subclass(PyTypeObject*, PyTypeObject*); static int add_all_subclasses(PyTypeObject *type, PyObject *bases); @@ -1333,7 +1333,7 @@ static PyTypeObject *solid_base(PyTypeObject *type); /* type test with subclassing support */ -Py_LOCAL_INLINE(int) +static int type_is_subtype_base_chain(PyTypeObject *a, PyTypeObject *b) { do { @@ -3805,7 +3805,7 @@ import_copyreg(void) return PyImport_Import(copyreg_str); } -Py_LOCAL(PyObject *) +static PyObject * _PyType_GetSlotNames(PyTypeObject *cls) { PyObject *copyreg; @@ -3858,7 +3858,7 @@ _PyType_GetSlotNames(PyTypeObject *cls) return slotnames; } -Py_LOCAL(PyObject *) +static PyObject * _PyObject_GetState(PyObject *obj, int required) { PyObject *state; @@ -4004,7 +4004,7 @@ _PyObject_GetState(PyObject *obj, int required) return state; } -Py_LOCAL(int) +static int _PyObject_GetNewArguments(PyObject *obj, PyObject **args, PyObject **kwargs) { PyObject *getnewargs, *getnewargs_ex; @@ -4100,7 +4100,7 @@ _PyObject_GetNewArguments(PyObject *obj, PyObject **args, PyObject **kwargs) return 0; } -Py_LOCAL(int) +static int _PyObject_GetItemsIter(PyObject *obj, PyObject **listitems, PyObject **dictitems) { -- cgit v1.2.1 From c74454dfd1e0ca63fab81d575d4689f7ab5aa22e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 10 Sep 2016 00:53:02 +0300 Subject: Issue #25856: The __module__ attribute of extension classes and functions now is interned. This leads to more compact pickle data with protocol 4. --- Objects/typeobject.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index df0481dd58..2675a4897d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -454,27 +454,30 @@ type_set_qualname(PyTypeObject *type, PyObject *value, void *context) static PyObject * type_module(PyTypeObject *type, void *context) { - char *s; + PyObject *mod; if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { - PyObject *mod = _PyDict_GetItemId(type->tp_dict, &PyId___module__); - if (!mod) { + mod = _PyDict_GetItemId(type->tp_dict, &PyId___module__); + if (mod == NULL) { PyErr_Format(PyExc_AttributeError, "__module__"); - return 0; + return NULL; } Py_INCREF(mod); - return mod; } else { - PyObject *name; - s = strrchr(type->tp_name, '.'); - if (s != NULL) - return PyUnicode_FromStringAndSize( + const char *s = strrchr(type->tp_name, '.'); + if (s != NULL) { + mod = PyUnicode_FromStringAndSize( type->tp_name, (Py_ssize_t)(s - type->tp_name)); - name = _PyUnicode_FromId(&PyId_builtins); - Py_XINCREF(name); - return name; + if (mod != NULL) + PyUnicode_InternInPlace(&mod); + } + else { + mod = _PyUnicode_FromId(&PyId_builtins); + Py_XINCREF(mod); + } } + return mod; } static int -- cgit v1.2.1 From 0780d6cb0e6e406d0030dee40156a6dd00066147 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sun, 11 Sep 2016 14:45:49 +1000 Subject: Issue #23722: Initialize __class__ from type.__new__() The __class__ cell used by zero-argument super() is now initialized from type.__new__ rather than __build_class__, so class methods relying on that will now work correctly when called from metaclass methods during class creation. Patch by Martin Teichmann. --- Objects/typeobject.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 2675a4897d..5028304373 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2285,7 +2285,7 @@ static PyObject * type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { PyObject *name, *bases = NULL, *orig_dict, *dict = NULL; - PyObject *qualname, *slots = NULL, *tmp, *newslots; + PyObject *qualname, *slots = NULL, *tmp, *newslots, *cell; PyTypeObject *type = NULL, *base, *tmptype, *winner; PyHeapTypeObject *et; PyMemberDef *mp; @@ -2293,6 +2293,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) int j, may_add_dict, may_add_weak, add_dict, add_weak; _Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__slots__); + _Py_IDENTIFIER(__classcell__); assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); @@ -2559,7 +2560,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) } et->ht_qualname = qualname ? qualname : et->ht_name; Py_INCREF(et->ht_qualname); - if (qualname != NULL && PyDict_DelItem(dict, PyId___qualname__.object) < 0) + if (qualname != NULL && _PyDict_DelItemId(dict, &PyId___qualname__) < 0) goto error; /* Set tp_doc to a copy of dict['__doc__'], if the latter is there @@ -2685,6 +2686,14 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) else type->tp_free = PyObject_Del; + /* store type in class' cell */ + cell = _PyDict_GetItemId(dict, &PyId___classcell__); + if (cell != NULL && PyCell_Check(cell)) { + PyCell_Set(cell, (PyObject *) type); + _PyDict_DelItemId(dict, &PyId___classcell__); + PyErr_Clear(); + } + /* Initialize the rest */ if (PyType_Ready(type) < 0) goto error; -- cgit v1.2.1 From 16582c66bcf5e1af5baee6ee429caa52007c9f88 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 21 Sep 2016 15:54:59 +0300 Subject: Issue #28214: Now __set_name__ is looked up on the class instead of the instance. --- Objects/typeobject.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5028304373..e799a574d2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6990,19 +6990,21 @@ update_all_slots(PyTypeObject* type) static int set_names(PyTypeObject *type) { - PyObject *key, *value, *tmp; + PyObject *key, *value, *set_name, *tmp; Py_ssize_t i = 0; while (PyDict_Next(type->tp_dict, &i, &key, &value)) { - if (PyObject_HasAttr(value, _PyUnicode_FromId(&PyId___set_name__))) { - tmp = PyObject_CallMethodObjArgs( - value, _PyUnicode_FromId(&PyId___set_name__), - type, key, NULL); + set_name = lookup_maybe(value, &PyId___set_name__); + if (set_name != NULL) { + tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); + Py_DECREF(set_name); if (tmp == NULL) return -1; else Py_DECREF(tmp); } + else if (PyErr_Occurred()) + return -1; } return 0; -- cgit v1.2.1 From 8f17cb4484f9d9356473766bd214d40777e4b26f Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 13 Oct 2016 21:10:31 +0200 Subject: Check return value of _PyDict_SetItemId() --- Objects/typeobject.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1960c1aa56..1021a75308 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2848,13 +2848,16 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) /* Set type.__module__ */ s = strrchr(spec->name, '.'); if (s != NULL) { + int err; modname = PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name)); if (modname == NULL) { goto fail; } - _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); Py_DECREF(modname); + if (err != 0) + goto fail; } else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "builtin type %.200s has no __module__ attribute", -- cgit v1.2.1 From d83848ee57d8584e4709d42eb3350b946450fb2c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Oct 2016 17:13:31 +0300 Subject: Issue #28214: Improved exception reporting for problematic __set_name__ attributes. --- Objects/typeobject.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1021a75308..bfbeb40d2c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7022,8 +7022,13 @@ set_names(PyTypeObject *type) if (set_name != NULL) { tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); Py_DECREF(set_name); - if (tmp == NULL) + if (tmp == NULL) { + _PyErr_FormatFromCause(PyExc_RuntimeError, + "Error calling __set_name__ on '%.100s' instance %R " + "in '%.100s'", + value->ob_type->tp_name, key, type->tp_name); return -1; + } else Py_DECREF(tmp); } -- cgit v1.2.1 From 57c0f2e61c8a5893c37e576a3a03ba5e57c1132c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 20 Nov 2016 09:13:07 +0200 Subject: Replaced outdated macros _PyUnicode_AsString and _PyUnicode_AsStringAndSize with PyUnicode_AsUTF8 and PyUnicode_AsUTF8AndSize. --- Objects/typeobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index dc9a80a34f..606e08e449 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1626,7 +1626,7 @@ consistent method resolution\norder (MRO) for bases"); PyObject *name = class_name(k); char *name_str; if (name != NULL) { - name_str = _PyUnicode_AsString(name); + name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) name_str = "?"; } else @@ -2575,7 +2575,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) char *doc_str; char *tp_doc; - doc_str = _PyUnicode_AsString(doc); + doc_str = PyUnicode_AsUTF8(doc); if (doc_str == NULL) goto error; /* Silently truncate the docstring if it contains null bytes. */ @@ -2623,7 +2623,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) slotoffset = base->tp_basicsize; if (et->ht_slots != NULL) { for (i = 0; i < nslots; i++, mp++) { - mp->name = _PyUnicode_AsString( + mp->name = PyUnicode_AsUTF8( PyTuple_GET_ITEM(et->ht_slots, i)); if (mp->name == NULL) goto error; -- cgit v1.2.1 From 5d1b8611159db32c7a142602fdd7c1bbbac8b2f6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 29 Nov 2016 09:54:17 +0200 Subject: Issue #28797: Modifying the class __dict__ inside the __set_name__ method of a descriptor that is used inside that class no longer prevents calling the __set_name__ method of other descriptors. --- Objects/typeobject.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 606e08e449..04da32bdfa 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7004,10 +7004,14 @@ update_all_slots(PyTypeObject* type) static int set_names(PyTypeObject *type) { - PyObject *key, *value, *set_name, *tmp; + PyObject *names_to_set, *key, *value, *set_name, *tmp; Py_ssize_t i = 0; - while (PyDict_Next(type->tp_dict, &i, &key, &value)) { + names_to_set = PyDict_Copy(type->tp_dict); + if (names_to_set == NULL) + return -1; + + while (PyDict_Next(names_to_set, &i, &key, &value)) { set_name = lookup_maybe(value, &PyId___set_name__); if (set_name != NULL) { tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); @@ -7017,15 +7021,19 @@ set_names(PyTypeObject *type) "Error calling __set_name__ on '%.100s' instance %R " "in '%.100s'", value->ob_type->tp_name, key, type->tp_name); + Py_DECREF(names_to_set); return -1; } else Py_DECREF(tmp); } - else if (PyErr_Occurred()) + else if (PyErr_Occurred()) { + Py_DECREF(names_to_set); return -1; + } } + Py_DECREF(names_to_set); return 0; } -- cgit v1.2.1 From f1b02866add58317c7f9c6c813c282659981a147 Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Mon, 5 Dec 2016 16:47:55 +1000 Subject: Issue #23722: improve __classcell__ compatibility Handling zero-argument super() in __init_subclass__ and __set_name__ involved moving __class__ initialisation to type.__new__. This requires cooperation from custom metaclasses to ensure that the new __classcell__ entry is passed along appropriately. The initial implementation of that change resulted in abruptly broken zero-argument super() support in metaclasses that didn't adhere to the new requirements (such as Django's metaclass for Model definitions). The updated approach adopted here instead emits a deprecation warning for those cases, and makes them work the same way they did in Python 3.5. This patch also improves the related class machinery documentation to cover these details and to include more reader-friendly cross-references and index entries. --- Objects/typeobject.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'Objects/typeobject.c') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 04da32bdfa..329261b037 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2687,9 +2687,16 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) else type->tp_free = PyObject_Del; - /* store type in class' cell */ + /* store type in class' cell if one is supplied */ cell = _PyDict_GetItemId(dict, &PyId___classcell__); - if (cell != NULL && PyCell_Check(cell)) { + if (cell != NULL) { + /* At least one method requires a reference to its defining class */ + if (!PyCell_Check(cell)) { + PyErr_Format(PyExc_TypeError, + "__classcell__ must be a nonlocal cell, not %.200R", + Py_TYPE(cell)); + goto error; + } PyCell_Set(cell, (PyObject *) type); _PyDict_DelItemId(dict, &PyId___classcell__); PyErr_Clear(); -- cgit v1.2.1