Commit 9c414f5
committed
Fix segfault in GC traversal of Python subclasses with weak references (#1206)
When ``nb::is_weak_referenceable()`` is used, nanobind installs ``tp_traverse``
and ``tp_clear`` callbacks to handle garbage collection of instance dictionaries
and weak reference lists.
When a Python subclass is created, Python may add its own instance dictionary
(potentially using managed dictionaries on Python 3.12+) or weak reference
list. Python's ``subtype_traverse`` function walks up the MRO and calls our
``tp_traverse`` callback. However, our callback was reading ``tp_dictoffset``
and ``tp_weaklistoffset`` directly from the type object, which includes
Python's additions. This caused crashes because:
1. On Python 3.11+, negative offsets are used (measured from the end of
the object rather than the beginning) which we didn't handle
2. On Python 3.12+, managed dictionaries require special APIs that we weren't
using and that aren't even available in the stable ABI/limited API
The fix is to always cache ``dictoffset``/``weaklistoffset`` in ``type_data``
when creating nanobind types, and use these cached values in ``nb_dict_ptr()``
and ``nb_weaklist_ptr()``. This ensures we only access dicts and weaklists
that nanobind created, while Python's ``subtype_traverse`` handles any
additions made by Python subclasses.
This requires an ABI bump due to the addition of ``dictoffset``/``weaklistoffset``
fields to ``type_data`` unconditionally (previously only in ``Py_LIMITED_API``
builds). Fortunately, the ABI was just bumped in commit aa1c9fd.
The commit also removes some redundant ``Py_TYPE()`` calls that have a
nontrivial cost on stable ABI builds.
Fixes #12011 parent aa1c9fd commit 9c414f5
File tree
5 files changed
+57
-27
lines changed- include/nanobind
- src
- tests
5 files changed
+57
-27
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
131 | | - | |
132 | 131 | | |
133 | 132 | | |
134 | | - | |
135 | 133 | | |
136 | 134 | | |
137 | 135 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | | - | |
26 | | - | |
| 24 | + | |
27 | 25 | | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | 26 | | |
32 | 27 | | |
33 | 28 | | |
34 | | - | |
35 | | - | |
36 | | - | |
| 29 | + | |
37 | 30 | | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | 31 | | |
42 | 32 | | |
43 | 33 | | |
| |||
47 | 37 | | |
48 | 38 | | |
49 | 39 | | |
50 | | - | |
| 40 | + | |
| 41 | + | |
51 | 42 | | |
52 | 43 | | |
53 | 44 | | |
54 | 45 | | |
55 | 46 | | |
56 | 47 | | |
57 | | - | |
| 48 | + | |
| 49 | + | |
58 | 50 | | |
59 | 51 | | |
60 | 52 | | |
61 | | - | |
| 53 | + | |
62 | 54 | | |
63 | 55 | | |
64 | 56 | | |
| |||
227 | 219 | | |
228 | 220 | | |
229 | 221 | | |
230 | | - | |
| 222 | + | |
231 | 223 | | |
232 | 224 | | |
233 | 225 | | |
234 | 226 | | |
235 | 227 | | |
236 | 228 | | |
237 | | - | |
| 229 | + | |
238 | 230 | | |
239 | | - | |
| 231 | + | |
240 | 232 | | |
241 | 233 | | |
242 | 234 | | |
| |||
1362 | 1354 | | |
1363 | 1355 | | |
1364 | 1356 | | |
1365 | | - | |
1366 | | - | |
1367 | | - | |
1368 | | - | |
1369 | | - | |
1370 | | - | |
1371 | | - | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
1372 | 1361 | | |
1373 | 1362 | | |
1374 | 1363 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
644 | 644 | | |
645 | 645 | | |
646 | 646 | | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
647 | 652 | | |
648 | 653 | | |
649 | 654 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
945 | 945 | | |
946 | 946 | | |
947 | 947 | | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
281 | 281 | | |
282 | 282 | | |
283 | 283 | | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
284 | 287 | | |
285 | 288 | | |
286 | 289 | | |
| |||
0 commit comments