Skip to content

Commit 98def19

Browse files
committed
Fix bindings of classes derived from a trampoline
Binding of deeper (>= 2 levels) class hierarchies that inherit from a trampoline class fail in Python 3.12+. For example, in the added test suite class ``SiameseCat``, this produces the following error message: Critical nanobind error: nanobind::detail::nb_type_new("SiameseCat"): type construction failed: TypeError: tp_basicsize for type 'test_classes_ext.SiameseCat' (56) is too small for base 'test_classes_ext.Cat' (88)! The trick to make Python happy is to carefully walk through the parent classes to look for trampolines. Previously, only the direct parent was checked.
1 parent d5b05b7 commit 98def19

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

src/nb_type.cpp

+22-5
Original file line numberDiff line numberDiff line change
@@ -1206,11 +1206,28 @@ PyObject *nb_type_new(const type_init_data *t) noexcept {
12061206

12071207
/* Handle a corner case (base class larger than derived class)
12081208
which can arise when extending trampoline base classes */
1209-
size_t base_basicsize = sizeof(nb_inst) + tb->size;
1210-
if (tb->align > ptr_size)
1211-
base_basicsize += tb->align - ptr_size;
1212-
if (base_basicsize > basicsize)
1213-
basicsize = base_basicsize;
1209+
1210+
PyTypeObject *base_2 = (PyTypeObject *) base;
1211+
type_data *tb_2 = tb;
1212+
1213+
do {
1214+
size_t base_basicsize = sizeof(nb_inst) + tb_2->size;
1215+
if (tb_2->align > ptr_size)
1216+
base_basicsize += tb_2->align - ptr_size;
1217+
if (base_basicsize > basicsize)
1218+
basicsize = base_basicsize;
1219+
1220+
#if !defined(Py_LIMITED_API)
1221+
base_2 = base_2->tp_base;
1222+
#else
1223+
base_2 = (PyTypeObject *) PyType_GetSlot(base_2, Py_tp_base);
1224+
#endif
1225+
1226+
if (!base_2 || !nb_type_check((PyObject *) base_2))
1227+
break;
1228+
1229+
tb_2 = nb_type_data(base_2);
1230+
} while (true);
12141231
}
12151232

12161233
bool base_intrusive_ptr =

tests/test_classes.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ NB_MODULE(test_classes_ext, m) {
261261
std::string s;
262262
};
263263

264+
struct SiameseCat : Cat { };
265+
264266
struct Foo { };
265267

266268
auto animal = nb::class_<Animal, PyAnimal>(m, "Animal")
@@ -274,6 +276,9 @@ NB_MODULE(test_classes_ext, m) {
274276
nb::class_<Cat>(m, "Cat", animal)
275277
.def(nb::init<const std::string &>());
276278

279+
nb::class_<SiameseCat, Cat> sc(m, "SiameseCat");
280+
(void) sc;
281+
277282
m.def("go", [](Animal *a) {
278283
return a->name() + " says " + a->what();
279284
});

0 commit comments

Comments
 (0)