mirror of https://github.com/python/cpython
list slotdefs in offset order rather than sorting them (closes #17610)
This means we can remove our usage of qsort() than relied on undefined behavior.
This commit is contained in:
parent
f8ffec0617
commit
6395241471
|
@ -12,6 +12,8 @@ What's New in Python 3.3.2?
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #17610: Don't rely on non-standard behavior of the C qsort() function.
|
||||
|
||||
- Issue #17357: Add missing verbosity output when using -v/-vv.
|
||||
|
||||
Library
|
||||
|
|
|
@ -5667,15 +5667,16 @@ slot_tp_del(PyObject *self)
|
|||
}
|
||||
|
||||
|
||||
/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper
|
||||
functions. The offsets here are relative to the 'PyHeapTypeObject'
|
||||
structure, which incorporates the additional structures used for numbers,
|
||||
sequences and mappings.
|
||||
Note that multiple names may map to the same slot (e.g. __eq__,
|
||||
__ne__ etc. all map to tp_richcompare) and one name may map to multiple
|
||||
slots (e.g. __str__ affects tp_str as well as tp_repr). The table is
|
||||
terminated with an all-zero entry. (This table is further initialized and
|
||||
sorted in init_slotdefs() below.) */
|
||||
/*
|
||||
Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper functions.
|
||||
|
||||
The table is ordered by offsets relative to the 'PyHeapTypeObject' structure,
|
||||
which incorporates the additional structures used for numbers, sequences and
|
||||
mappings. Note that multiple names may map to the same slot (e.g. __eq__,
|
||||
__ne__ etc. all map to tp_richcompare) and one name may map to multiple slots
|
||||
(e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with
|
||||
an all-zero entry. (This table is further initialized in init_slotdefs().)
|
||||
*/
|
||||
|
||||
typedef struct wrapperbase slotdef;
|
||||
|
||||
|
@ -5725,43 +5726,53 @@ typedef struct wrapperbase slotdef;
|
|||
"x." NAME "(y) <==> " DOC)
|
||||
|
||||
static slotdef slotdefs[] = {
|
||||
SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
|
||||
"x.__len__() <==> len(x)"),
|
||||
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
|
||||
The logic in abstract.c always falls back to nb_add/nb_multiply in
|
||||
this case. Defining both the nb_* and the sq_* slots to call the
|
||||
user-defined methods has unexpected side-effects, as shown by
|
||||
test_descr.notimplemented() */
|
||||
SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
|
||||
"x.__add__(y) <==> x+y"),
|
||||
SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
|
||||
"x.__mul__(n) <==> x*n"),
|
||||
SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
|
||||
"x.__rmul__(n) <==> n*x"),
|
||||
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
|
||||
"x.__getitem__(y) <==> x[y]"),
|
||||
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
|
||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
||||
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
|
||||
"x.__delitem__(y) <==> del x[y]"),
|
||||
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
|
||||
"x.__contains__(y) <==> y in x"),
|
||||
SQSLOT("__iadd__", sq_inplace_concat, NULL,
|
||||
wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
|
||||
SQSLOT("__imul__", sq_inplace_repeat, NULL,
|
||||
wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
|
||||
|
||||
MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
|
||||
"x.__len__() <==> len(x)"),
|
||||
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
|
||||
wrap_binaryfunc,
|
||||
"x.__getitem__(y) <==> x[y]"),
|
||||
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
||||
wrap_objobjargproc,
|
||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
||||
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
||||
wrap_delitem,
|
||||
"x.__delitem__(y) <==> del x[y]"),
|
||||
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
|
||||
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
|
||||
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
|
||||
TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
|
||||
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
|
||||
"x.__repr__() <==> repr(x)"),
|
||||
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
|
||||
"x.__hash__() <==> hash(x)"),
|
||||
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
|
||||
"x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
|
||||
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
|
||||
"x.__str__() <==> str(x)"),
|
||||
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
|
||||
wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
|
||||
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
|
||||
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
|
||||
"x.__setattr__('name', value) <==> x.name = value"),
|
||||
TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
|
||||
"x.__delattr__('name') <==> del x.name"),
|
||||
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
|
||||
"x.__lt__(y) <==> x<y"),
|
||||
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
|
||||
"x.__le__(y) <==> x<=y"),
|
||||
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
|
||||
"x.__eq__(y) <==> x==y"),
|
||||
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
|
||||
"x.__ne__(y) <==> x!=y"),
|
||||
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
|
||||
"x.__gt__(y) <==> x>y"),
|
||||
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
|
||||
"x.__ge__(y) <==> x>=y"),
|
||||
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
|
||||
"x.__iter__() <==> iter(x)"),
|
||||
TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next,
|
||||
"x.__next__() <==> next(x)"),
|
||||
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
|
||||
"descr.__get__(obj[, type]) -> value"),
|
||||
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
|
||||
"descr.__set__(obj, value)"),
|
||||
TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
|
||||
wrap_descr_delete, "descr.__delete__(obj)"),
|
||||
FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
|
||||
"x.__init__(...) initializes x; "
|
||||
"see help(type(x)) for signature",
|
||||
PyWrapperFlag_KEYWORDS),
|
||||
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
|
||||
TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
|
||||
|
||||
BINSLOT("__add__", nb_add, slot_nb_add,
|
||||
"+"),
|
||||
|
@ -5808,8 +5819,6 @@ static slotdef slotdefs[] = {
|
|||
"int(x)"),
|
||||
UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
|
||||
"float(x)"),
|
||||
NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
|
||||
"x[y:z] <==> x[y.__index__():z.__index__()]"),
|
||||
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
|
||||
wrap_binaryfunc, "+="),
|
||||
IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
|
||||
|
@ -5838,54 +5847,47 @@ static slotdef slotdefs[] = {
|
|||
slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
|
||||
IBSLOT("__itruediv__", nb_inplace_true_divide,
|
||||
slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
|
||||
NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
|
||||
"x[y:z] <==> x[y.__index__():z.__index__()]"),
|
||||
|
||||
MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
|
||||
"x.__len__() <==> len(x)"),
|
||||
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
|
||||
wrap_binaryfunc,
|
||||
"x.__getitem__(y) <==> x[y]"),
|
||||
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
||||
wrap_objobjargproc,
|
||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
||||
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
||||
wrap_delitem,
|
||||
"x.__delitem__(y) <==> del x[y]"),
|
||||
|
||||
SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
|
||||
"x.__len__() <==> len(x)"),
|
||||
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
|
||||
The logic in abstract.c always falls back to nb_add/nb_multiply in
|
||||
this case. Defining both the nb_* and the sq_* slots to call the
|
||||
user-defined methods has unexpected side-effects, as shown by
|
||||
test_descr.notimplemented() */
|
||||
SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
|
||||
"x.__add__(y) <==> x+y"),
|
||||
SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
|
||||
"x.__mul__(n) <==> x*n"),
|
||||
SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
|
||||
"x.__rmul__(n) <==> n*x"),
|
||||
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
|
||||
"x.__getitem__(y) <==> x[y]"),
|
||||
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
|
||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
||||
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
|
||||
"x.__delitem__(y) <==> del x[y]"),
|
||||
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
|
||||
"x.__contains__(y) <==> y in x"),
|
||||
SQSLOT("__iadd__", sq_inplace_concat, NULL,
|
||||
wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
|
||||
SQSLOT("__imul__", sq_inplace_repeat, NULL,
|
||||
wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
|
||||
|
||||
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
|
||||
"x.__str__() <==> str(x)"),
|
||||
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
|
||||
"x.__repr__() <==> repr(x)"),
|
||||
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
|
||||
"x.__hash__() <==> hash(x)"),
|
||||
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
|
||||
"x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
|
||||
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
|
||||
wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
|
||||
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
|
||||
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
|
||||
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
|
||||
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
|
||||
"x.__setattr__('name', value) <==> x.name = value"),
|
||||
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
|
||||
TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
|
||||
"x.__delattr__('name') <==> del x.name"),
|
||||
TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
|
||||
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
|
||||
"x.__lt__(y) <==> x<y"),
|
||||
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
|
||||
"x.__le__(y) <==> x<=y"),
|
||||
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
|
||||
"x.__eq__(y) <==> x==y"),
|
||||
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
|
||||
"x.__ne__(y) <==> x!=y"),
|
||||
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
|
||||
"x.__gt__(y) <==> x>y"),
|
||||
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
|
||||
"x.__ge__(y) <==> x>=y"),
|
||||
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
|
||||
"x.__iter__() <==> iter(x)"),
|
||||
TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next,
|
||||
"x.__next__() <==> next(x)"),
|
||||
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
|
||||
"descr.__get__(obj[, type]) -> value"),
|
||||
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
|
||||
"descr.__set__(obj, value)"),
|
||||
TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set,
|
||||
wrap_descr_delete, "descr.__delete__(obj)"),
|
||||
FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
|
||||
"x.__init__(...) initializes x; "
|
||||
"see help(type(x)) for signature",
|
||||
PyWrapperFlag_KEYWORDS),
|
||||
TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
|
||||
TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
@ -6066,21 +6068,6 @@ update_slots_callback(PyTypeObject *type, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Comparison function for qsort() to compare slotdefs by their offset, and
|
||||
for equal offset by their address (to force a stable sort). */
|
||||
static int
|
||||
slotdef_cmp(const void *aa, const void *bb)
|
||||
{
|
||||
const slotdef *a = (const slotdef *)aa, *b = (const slotdef *)bb;
|
||||
int c = a->offset - b->offset;
|
||||
if (c != 0)
|
||||
return c;
|
||||
else
|
||||
/* Cannot use a-b, as this gives off_t,
|
||||
which may lose precision when converted to int. */
|
||||
return (a > b) ? 1 : (a < b) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Initialize the slotdefs table by adding interned string objects for the
|
||||
names and sorting the entries. */
|
||||
static void
|
||||
|
@ -6092,12 +6079,12 @@ init_slotdefs(void)
|
|||
if (initialized)
|
||||
return;
|
||||
for (p = slotdefs; p->name; p++) {
|
||||
/* Slots must be ordered by their offset in the PyHeapTypeObject. */
|
||||
assert(!p[1].name || p->offset <= p[1].offset);
|
||||
p->name_strobj = PyUnicode_InternFromString(p->name);
|
||||
if (!p->name_strobj)
|
||||
Py_FatalError("Out of memory interning slotdef names");
|
||||
}
|
||||
qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),
|
||||
slotdef_cmp);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue