- Notifications
You must be signed in to change notification settings - Fork749
Description
Problem:bpo-37931 demonstrates that even Python itself can't re-initialize on all platforms without crashing. Major third-party packages including numpy and PySide also crash when you Py_Initialize after a Py_Finalize and reimport the package.
The reason we Py_Finalize in Shutdown is because otherwise, the python side has live objects that have function pointers into C#. If the C# domain is reloaded (which frequently happens in the Unity3d editor) then those pointers are pointing to garbage. So, calling any C#-implemented function on those python objects causes the PC to jump to garbage and thus "undefined behaviour" (usually a crash).
New proposedsolution:
- Don't Py_Finalize in Shutdown.
- Find all the function pointers from Python to C# and set them to a reasonable value so that they have a reasonably pythonic exception rather than jumping to garbage.
@BadSingleton on our team has prototyped this. It seems the only place we jump to C# is in thetp_*
slots of a type. Setting them to null, as most slots are set in Python's noddy example, seems to work fine (except for the slots for garbage collection, which must point to something, so we still need that silly native code page for now).
Example: we have a proxy to a C# object in python and we callToString()
on it. Before domain reload, Python calls the tp_getattro slot which is implemented in C# and it does the reflection to find ToString, and then it calls tp_call which is implemented in C# and it calls the function. After domain reload, Python sees that tp_getattro is null so it uses the default getattr implementation, which has never heard of ToString, so it throws an AttributeError. If we cached ToString on the python side, then Python looks at the tp_call slot which is null and throws a TypeError because it's not callable.