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
|
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.
|
- Issue #17357: Add missing verbosity output when using -v/-vv.
|
||||||
|
|
||||||
Library
|
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'
|
Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper functions.
|
||||||
structure, which incorporates the additional structures used for numbers,
|
|
||||||
sequences and mappings.
|
The table is ordered by offsets relative to the 'PyHeapTypeObject' structure,
|
||||||
Note that multiple names may map to the same slot (e.g. __eq__,
|
which incorporates the additional structures used for numbers, sequences and
|
||||||
__ne__ etc. all map to tp_richcompare) and one name may map to multiple
|
mappings. Note that multiple names may map to the same slot (e.g. __eq__,
|
||||||
slots (e.g. __str__ affects tp_str as well as tp_repr). The table is
|
__ne__ etc. all map to tp_richcompare) and one name may map to multiple slots
|
||||||
terminated with an all-zero entry. (This table is further initialized and
|
(e.g. __str__ affects tp_str as well as tp_repr). The table is terminated with
|
||||||
sorted in init_slotdefs() below.) */
|
an all-zero entry. (This table is further initialized in init_slotdefs().)
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct wrapperbase slotdef;
|
typedef struct wrapperbase slotdef;
|
||||||
|
|
||||||
|
@ -5725,43 +5726,53 @@ typedef struct wrapperbase slotdef;
|
||||||
"x." NAME "(y) <==> " DOC)
|
"x." NAME "(y) <==> " DOC)
|
||||||
|
|
||||||
static slotdef slotdefs[] = {
|
static slotdef slotdefs[] = {
|
||||||
SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,
|
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
|
||||||
"x.__len__() <==> len(x)"),
|
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
|
||||||
/* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.
|
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
|
||||||
The logic in abstract.c always falls back to nb_add/nb_multiply in
|
TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
|
||||||
this case. Defining both the nb_* and the sq_* slots to call the
|
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc,
|
||||||
user-defined methods has unexpected side-effects, as shown by
|
"x.__repr__() <==> repr(x)"),
|
||||||
test_descr.notimplemented() */
|
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
|
||||||
SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,
|
"x.__hash__() <==> hash(x)"),
|
||||||
"x.__add__(y) <==> x+y"),
|
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
|
||||||
SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,
|
"x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
|
||||||
"x.__mul__(n) <==> x*n"),
|
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
|
||||||
SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,
|
"x.__str__() <==> str(x)"),
|
||||||
"x.__rmul__(n) <==> n*x"),
|
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
|
||||||
SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,
|
wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
|
||||||
"x.__getitem__(y) <==> x[y]"),
|
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
|
||||||
SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem,
|
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
|
||||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
"x.__setattr__('name', value) <==> x.name = value"),
|
||||||
SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem,
|
TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr,
|
||||||
"x.__delitem__(y) <==> del x[y]"),
|
"x.__delattr__('name') <==> del x.name"),
|
||||||
SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc,
|
TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt,
|
||||||
"x.__contains__(y) <==> y in x"),
|
"x.__lt__(y) <==> x<y"),
|
||||||
SQSLOT("__iadd__", sq_inplace_concat, NULL,
|
TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le,
|
||||||
wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"),
|
"x.__le__(y) <==> x<=y"),
|
||||||
SQSLOT("__imul__", sq_inplace_repeat, NULL,
|
TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq,
|
||||||
wrap_indexargfunc, "x.__imul__(y) <==> x*=y"),
|
"x.__eq__(y) <==> x==y"),
|
||||||
|
TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne,
|
||||||
MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
|
"x.__ne__(y) <==> x!=y"),
|
||||||
"x.__len__() <==> len(x)"),
|
TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt,
|
||||||
MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
|
"x.__gt__(y) <==> x>y"),
|
||||||
wrap_binaryfunc,
|
TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge,
|
||||||
"x.__getitem__(y) <==> x[y]"),
|
"x.__ge__(y) <==> x>=y"),
|
||||||
MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc,
|
||||||
wrap_objobjargproc,
|
"x.__iter__() <==> iter(x)"),
|
||||||
"x.__setitem__(i, y) <==> x[i]=y"),
|
TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next,
|
||||||
MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript,
|
"x.__next__() <==> next(x)"),
|
||||||
wrap_delitem,
|
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get,
|
||||||
"x.__delitem__(y) <==> del x[y]"),
|
"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,
|
BINSLOT("__add__", nb_add, slot_nb_add,
|
||||||
"+"),
|
"+"),
|
||||||
|
@ -5808,8 +5819,6 @@ static slotdef slotdefs[] = {
|
||||||
"int(x)"),
|
"int(x)"),
|
||||||
UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
|
UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc,
|
||||||
"float(x)"),
|
"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,
|
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
|
||||||
wrap_binaryfunc, "+="),
|
wrap_binaryfunc, "+="),
|
||||||
IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
|
IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
|
||||||
|
@ -5838,54 +5847,47 @@ static slotdef slotdefs[] = {
|
||||||
slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
|
slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"),
|
||||||
IBSLOT("__itruediv__", nb_inplace_true_divide,
|
IBSLOT("__itruediv__", nb_inplace_true_divide,
|
||||||
slot_nb_inplace_true_divide, wrap_binaryfunc, "/"),
|
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}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6066,21 +6068,6 @@ update_slots_callback(PyTypeObject *type, void *data)
|
||||||
return 0;
|
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
|
/* Initialize the slotdefs table by adding interned string objects for the
|
||||||
names and sorting the entries. */
|
names and sorting the entries. */
|
||||||
static void
|
static void
|
||||||
|
@ -6092,12 +6079,12 @@ init_slotdefs(void)
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return;
|
return;
|
||||||
for (p = slotdefs; p->name; p++) {
|
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);
|
p->name_strobj = PyUnicode_InternFromString(p->name);
|
||||||
if (!p->name_strobj)
|
if (!p->name_strobj)
|
||||||
Py_FatalError("Out of memory interning slotdef names");
|
Py_FatalError("Out of memory interning slotdef names");
|
||||||
}
|
}
|
||||||
qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),
|
|
||||||
slotdef_cmp);
|
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue