Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Segfault when __dealloc__ calls a non-existent method. #6022

Closed
iphydf opened this issue Feb 22, 2024 · 2 comments · Fixed by #6089
Closed

[BUG] Segfault when __dealloc__ calls a non-existent method. #6022

iphydf opened this issue Feb 22, 2024 · 2 comments · Fixed by #6089

Comments

@iphydf
Copy link

iphydf commented Feb 22, 2024

Describe the bug

Segmentation fault at https://github.com/python/cpython/blob/3.11/Objects/dictobject.c#L5582

Reproducer in Dockerfile: https://github.com/iphydf/toktok-stack/tree/cython-example/third_party/python/cython/bug6022

#13 0.769 AttributeError: 'Derived' object has no attribute 'cleanup'
#13 0.769 Exception ignored in: 'helloworld.Foo.__dealloc__'
#13 0.769 AttributeError: 'Derived' object has no attribute 'cleanup'
#13 2.084 warning: 5582	Objects/dictobject.c: No such file or directory
#13 2.084
#13 2.084 Program received signal SIGSEGV, Segmentation fault.
#13 2.084 _PyObject_FreeInstanceAttributes (self=0x7f4be34316d0)
#13 2.084     at Objects/dictobject.c:5582
#13 2.085 #0  _PyObject_FreeInstanceAttributes (self=0x7f4be34316d0)
#13 2.085     at Objects/dictobject.c:5582
#13 2.085 #1  subtype_dealloc (self=0x7f4be34316d0) at Objects/typeobject.c:1433
#13 2.085 #2  0x00007f4be384199c in _Py_Dealloc (op=<optimized out>)
#13 2.085     at Objects/object.c:2390
#13 2.085 #3  Py_DECREF (op=<optimized out>) at ./Include/object.h:538
#13 2.085 #4  AttributeError_clear (self=0x7f4be3618cf0) at Objects/exceptions.c:2287
#13 2.085 #5  AttributeError_dealloc (self=0x7f4be3618cf0) at Objects/exceptions.c:2296
#13 2.085 #6  0x00007f4be380d967 in _Py_Dealloc (op=<optimized out>)
#13 2.085     at Objects/object.c:2390
#13 2.085 #7  Py_DECREF (op=<optimized out>) at ./Include/object.h:538
#13 2.085 #8  Py_XDECREF (op=<optimized out>) at ./Include/object.h:602
#13 2.086 #9  insertdict (mp=0x7f4be36693c0, key=0x7f4be36b8030,
#13 2.086     hash=3280292777369596347, value=0x7f4be3b42a20 <_Py_NoneStruct>)
#13 2.086     at Objects/dictobject.c:1304
#13 2.086 #10 0x00007f4be3870de9 in _PyModule_ClearDict (d=0x7f4be36693c0)
#13 2.086     at Objects/moduleobject.c:634
#13 2.086 #11 0x00007f4be38ced8c in finalize_clear_sys_builtins_dict (verbose=0,
#13 2.086     interp=0x7f4be3b58f58 <_PyRuntime+58936>) at Python/pylifecycle.c:1512
#13 2.086 #12 finalize_modules (tstate=tstate@entry=0x7f4be3b732d8 <_PyRuntime+166328>)
#13 2.086     at Python/pylifecycle.c:1586
#13 2.086 #13 0x00007f4be38bb775 in Py_FinalizeEx () at Python/pylifecycle.c:1833
#13 2.087 #14 0x00007f4be38c8036 in Py_RunMain () at Modules/main.c:682
#13 2.087 #15 0x00007f4be388ece7 in Py_BytesMain (argc=<optimized out>,
#13 2.087     argv=<optimized out>) at Modules/main.c:734
#13 2.088 #16 0x00007f4be3bd26d1 in libc_start_main_stage2 (main=0x558c3009a180 <main>,
#13 2.088     argc=2, argv=0x7ffd921e9a88) at src/env/__libc_start_main.c:95
#13 2.088 #17 0x0000558c3009a046 in _start ()
#13 2.090 Cannot access memory at address 0x7f4be33ff028
#13 2.090 $1 = 0x7f4be341b2a0 "Derived"
#13 2.090 $2 = (PyDictKeysObject *) 0x7f4be33ff010

Code to reproduce the behaviour:

helloworld.pyx:

# cython: language_level=3, linetrace=True
import sys


cdef class Foo:

    def __init__(self):
        print("Foo init", file=sys.stderr)

    def __dealloc__(self):
        print("__dealloc__", file=sys.stderr)
        self.cleanup()

main.py:

import helloworld
import sys


class Derived(helloworld.Foo):

    def __init__(self):
        super().__init__()
        print("DerivedWorking init", file=sys.stderr)


class Main:
    ob = Derived()


Main()

Expected behaviour

I expect python to not segfault.

OS

Linux

Python version

3.11

Cython version

53ff506

Additional context

If ob is not in a class but in a function, e.g. def Main(): ob = Derived(), the segfault happens elsewhere:

#13 2.205 #0  0x00007f263dd878b4 in _PyObject_IS_GC (obj=0x7f263d9a9610)
#13 2.205     at ./Include/internal/pycore_object.h:214
...

Reproducible on both 3.0.8 release and current master (53ff506).

@da-woods
Copy link
Contributor

I think the basic issue is that __dealloc__ ends up being called twice. I really can't work out why or where though - I suspect a stray reference is kept to ob somewhere (maybe in a traceback or a stack frame saved somewhere or something like that)

@iphydf
Copy link
Author

iphydf commented Mar 16, 2024

I've moved away from __dealloc__ entirely, and use __del__ only. Works for me, but I still wanted to report it.

da-woods added a commit to da-woods/cython that referenced this issue Mar 16, 2024
I'm not 100% sure what causes the error, but I think it's
that _PyErr_PrintEx stashes away some illicit references to
invalid objects on sys.last_exc.

There's no reason to do this, so just do the print without the
stash.

Fixes cython#6022
da-woods added a commit that referenced this issue May 21, 2024
I'm not 100% sure what causes the error, but I think it's
that _PyErr_PrintEx stashes away some illicit references to
invalid objects on sys.last_exc.

There's no reason to do this, so just do the print without the
stash.

Fixes #6022
da-woods added a commit that referenced this issue May 21, 2024
I'm not 100% sure what causes the error, but I think it's
that _PyErr_PrintEx stashes away some illicit references to
invalid objects on sys.last_exc.

There's no reason to do this, so just do the print without the
stash.

Fixes #6022
@da-woods da-woods modified the milestones: 3.0.10, 3.0.11 May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants