-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
abstract_issubclass() doesn't take bases tuple item ref #83563
Comments
I encountered a crash using rpyc. Since rpyc is pure-Python, I guessed the problem is with Python itself. Originally tested on v3.7, the rest of this issue is based on v3.9.0a2 (compiling on an Ubuntu 18.04 docker). I narrowed down the rpyc-based snippet to this: # server side
class X: pass
x_instance = X()
from rpyc.core import SlaveService
from rpyc.utils.classic import DEFAULT_SERVER_PORT
from rpyc.utils.server import ThreadedServer
t = ThreadedServer(SlaveService, port=DEFAULT_SERVER_PORT, reuse_addr=True)
t.start()
# client side
import rpyc
conn = rpyc.classic.connect("localhost")
x = conn.modules.__main__.x_instance
y = x.__class__
issubclass(y, int) Client side gets a SIGSEGV in After some reference count debugging, I found that for the rpyc abstract_issubclass() calls abstract_get_bases() to get this refcount=1 tuple, and in the fastpath for single inheritance (tuple size = 1) it loads the single item from the tuple ( I tried to mimic the Python magic rpyc does to get the same crash without rpyc, and reached the following snippet (which doesn't exhibit the problem): class Meta(type):
def __getattribute__(self, attr):
if attr == "__bases__":
class Base: pass
return (Base, )
return type.__getattribute__(self, attr)
class X(metaclass=Meta):
pass
In this case, the refcount is decremented from 4 to 3 as abstract_issubclass() gets rid of the tuple (instead of from 1 to 0 as happens in the rpyc case). I don't know how rpyc does it. Attached is a patch that solves the problem (takes a ref of the tuple item before releasing the ref of the tuple itself). Anyway, if you do decide it's worth it, I'd be happy to improve the patch (it's quite messy the way this function is structured) and post it to GitHub :) Yonatan |
Thank you for your report and patch. Agree that the code does not look safe. Do you mind to create a pull request? Would be nice to add a test for it. The three references to the Python class are:
You can get rid of the first two by setting __slots__ = () in the class definition. But it is not so easy with the __mro__ tuple. I will try more. |
I posted a test on the PR |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: