Commit 3a568a1
committed
[mypyc] Fix memory leak in Exception and dict subclasses with instance attributes
Fixes #21716.
On Python <3.12, when mypyc compiles a subclass of a builtin type
(`Exception` or `dict`) that has instance attributes, it appends a
`__dict__` slot onto the end of the base struct at
`tp_dictoffset = sizeof(builtin_base)` to hold them. But no custom
`tp_dealloc`/`tp_clear`/`tp_traverse` is emitted for this case, so the
type inherits the base's slots — which only clear the base's own fields
and know nothing about the extra slot mypyc added. The dict (and every
object it references) leaks on every instance destruction.
Hit downstream in sqlglot[c] (tobymao/sqlglot#7853): every
raised-and-caught `ParseError` leaked ~1 KB. On 3.12+ mypyc already
skips adding the extra offset for these bases, so only <3.12 is
affected.
Changes in `mypyc/codegen/emitclass.py`:
* Extend the gate that emits `tp_dealloc`/`tp_clear`/`tp_traverse` to
fire for any `builtin_base` subclass with `has_dict` under
`capi < 3.12`. The existing builtin-base dealloc dance (untrack →
subtype clear → re-track → base dealloc) then does the right thing:
our clear frees the extra slot, then the base's dealloc frees its
own state and the object.
* Set `Py_TPFLAGS_HAVE_GC` explicitly. `PyType_Ready` only inherits
`HAVE_GC` from the base when it also inherits both `tp_traverse`
and `tp_dealloc`; overriding either drops the inheritance and
without it the type's inherited `tp_new` would allocate without a
GC header.
* Fix a latent offset bug in `generate_traverse_for_class` /
`generate_clear_for_class`: the code that visits/clears the extra
dict slot used `sizeof(struct_name)`, but for `builtin_base` classes
`tp_dictoffset` is `sizeof(builtin_base)`. This mismatch was
previously unreachable because the emission gate never fired for
`builtin_base` classes.
Regression test in `mypyc/test-data/run-classes.test` uses a `Payload`
class with a `__del__` counter: without the fix, 1000 fresh exceptions
each keep their fresh payload alive; with it, all payloads are freed.1 parent d5daed2 commit 3a568a1
2 files changed
Lines changed: 56 additions & 29 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
267 | 267 | | |
268 | 268 | | |
269 | 269 | | |
270 | | - | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
271 | 280 | | |
272 | 281 | | |
273 | 282 | | |
| |||
340 | 349 | | |
341 | 350 | | |
342 | 351 | | |
343 | | - | |
| 352 | + | |
344 | 353 | | |
345 | 354 | | |
346 | 355 | | |
| |||
386 | 395 | | |
387 | 396 | | |
388 | 397 | | |
389 | | - | |
| 398 | + | |
| 399 | + | |
390 | 400 | | |
391 | 401 | | |
392 | 402 | | |
| |||
882 | 892 | | |
883 | 893 | | |
884 | 894 | | |
885 | | - | |
886 | | - | |
887 | | - | |
888 | | - | |
889 | | - | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
890 | 898 | | |
891 | | - | |
892 | | - | |
| 899 | + | |
893 | 900 | | |
894 | 901 | | |
895 | 902 | | |
| |||
908 | 915 | | |
909 | 916 | | |
910 | 917 | | |
911 | | - | |
912 | | - | |
913 | | - | |
914 | | - | |
915 | | - | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
916 | 921 | | |
917 | | - | |
918 | | - | |
| 922 | + | |
919 | 923 | | |
920 | 924 | | |
921 | 925 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
956 | 956 | | |
957 | 957 | | |
958 | 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 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
959 | 993 | | |
960 | 994 | | |
961 | 995 | | |
| |||
3452 | 3486 | | |
3453 | 3487 | | |
3454 | 3488 | | |
3455 | | - | |
3456 | | - | |
3457 | 3489 | | |
3458 | 3490 | | |
3459 | 3491 | | |
3460 | 3492 | | |
3461 | | - | |
3462 | | - | |
3463 | | - | |
3464 | | - | |
3465 | | - | |
3466 | | - | |
3467 | | - | |
3468 | | - | |
3469 | | - | |
3470 | | - | |
| 3493 | + | |
3471 | 3494 | | |
3472 | 3495 | | |
3473 | 3496 | | |
| |||
0 commit comments