@@ -102,8 +102,22 @@ class loader_life_support {
102102inline std::pair<decltype (internals::registered_types_py)::iterator, bool >
103103all_type_info_get_cache (PyTypeObject *type);
104104
105+ // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
106+ inline void all_type_info_add_base_most_derived_first (std::vector<type_info *> &bases,
107+ type_info *addl_base) {
108+ for (auto it = bases.begin (); it != bases.end (); it++) {
109+ type_info *existing_base = *it;
110+ if (PyType_IsSubtype (addl_base->type , existing_base->type ) != 0 ) {
111+ bases.insert (it, addl_base);
112+ return ;
113+ }
114+ }
115+ bases.push_back (addl_base);
116+ }
117+
105118// Populates a just-created cache entry.
106119PYBIND11_NOINLINE void all_type_info_populate (PyTypeObject *t, std::vector<type_info *> &bases) {
120+ assert (bases.empty ());
107121 std::vector<PyTypeObject *> check;
108122 for (handle parent : reinterpret_borrow<tuple>(t->tp_bases )) {
109123 check.push_back ((PyTypeObject *) parent.ptr ());
@@ -136,7 +150,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
136150 }
137151 }
138152 if (!found) {
139- bases. push_back ( tinfo);
153+ all_type_info_add_base_most_derived_first (bases, tinfo);
140154 }
141155 }
142156 } else if (type->tp_bases ) {
@@ -322,18 +336,29 @@ struct values_and_holders {
322336 explicit values_and_holders (instance *inst)
323337 : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}
324338
339+ explicit values_and_holders (PyObject *obj)
340+ : inst{nullptr }, tinfo(all_type_info(Py_TYPE(obj))) {
341+ if (!tinfo.empty ()) {
342+ inst = reinterpret_cast <instance *>(obj);
343+ }
344+ }
345+
325346 struct iterator {
326347 private:
327348 instance *inst = nullptr ;
328349 const type_vec *types = nullptr ;
329350 value_and_holder curr;
330351 friend struct values_and_holders ;
331- iterator (instance *inst, const type_vec *tinfo)
332- : inst{inst}, types{tinfo},
333- curr (inst /* instance */ ,
334- types->empty () ? nullptr : (*types)[0] /* type info */ ,
335- 0, /* vpos: (non-simple types only): the first vptr comes first */
336- 0 /* index */ ) {}
352+ iterator (instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} {
353+ if (inst != nullptr ) {
354+ assert (!types->empty ());
355+ curr = value_and_holder (
356+ inst /* instance */ ,
357+ (*types)[0 ] /* type info */ ,
358+ 0 , /* vpos: (non-simple types only): the first vptr comes first */
359+ 0 /* index */ );
360+ }
361+ }
337362 // Past-the-end iterator:
338363 explicit iterator (size_t end) : curr(end) {}
339364
@@ -364,6 +389,16 @@ struct values_and_holders {
364389 }
365390
366391 size_t size () { return tinfo.size (); }
392+
393+ // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.
394+ bool is_redundant_value_and_holder (const value_and_holder &vh) {
395+ for (size_t i = 0 ; i < vh.index ; i++) {
396+ if (PyType_IsSubtype (tinfo[i]->type , tinfo[vh.index ]->type ) != 0 ) {
397+ return true ;
398+ }
399+ }
400+ return false ;
401+ }
367402};
368403
369404/* *
0 commit comments