-
-
Notifications
You must be signed in to change notification settings - Fork 22.4k
[3.x] Don't terminate library if other GDNative
s are still using it
#49467
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
Conversation
176e194
to
cbc79f8
Compare
71cb8d3
to
c58391c
Compare
cbc79f8
to
4452a8d
Compare
4452a8d
to
7f1f099
Compare
only merge after godotengine/godot#49467
I think this should probably be merged before 3.x is abandoned. The only ways to mitigate the issue are to forfeit reload ability or maybe to keep a dummy Maybe this will help make it clearer what's going wrong: now:
With this fix:
|
7f1f099
to
f95441e
Compare
CC @godotengine/gdextension @Bromeon |
GDNative
s are still using itGDNative
s are still using it
@@ -430,6 +433,10 @@ bool GDNative::terminate() { | |||
gdnatives->clear(); | |||
// whew this looks scary, but all it does is remove the entry completely | |||
GDNativeLibrary::loaded_libraries.erase(GDNativeLibrary::loaded_libraries.find(library->get_current_library_path())); | |||
} else { | |||
// in case user triggers a call to terminate in the callback below |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// in case user triggers a call to terminate in the callback below | |
// In case user triggers a call to terminate in the callback below. |
Per the comment style.
This PR is being made directly to 3.x because there are apparently so many massive changes to GDNative coming in 4.0 that I have no way to test this or even know if it will be relevant to 4.0.
If a GDNative library is marked as reloadable,
GDNative::terminate()
checksGDNativeLibrary::loaded_libraries
to see if any otherGDNative
objects are currently using the library before actually closing it, but they weren't actually being added to the list beyond the first one.Now that
NativeScriptLanguage::unregister_script()
callsGDNative::terminate()
whenNativeScript
s are left referencing the library (introduced by hot-reloading in 311ca0c), this means that libraries can be terminated out from underGDNative
objects just by freeing an object that happens to hold the lastNativeScript
using a library.This could happen previously by creating two
GDNative
objects referencing the same library, and then terminating one of them, but now it's relevant to the more widely-usedNativeScript
s as well. This is still a relatively rare scenario, using the same library for both a basicGDNative
object and creatingNativeScript
s from it, but this is exactly what the godot-rust tests do to verify that the bindings work both with and withoutNativeScript
functionality.There is one issue with this fix, which makes it technically a breaking change: without this fix, dropping the last
NativeScript
terminates the library, and creating a new one would re-initialize it; while with this fix,godot_nativescript_init
can end up being called multiple times without terminating the library. Since there is nogodot_nativescript_terminate
counterpart, libraries have no way of knowing that they can do anyNativeScript
-related cleanup untilgodot_gdnative_terminate
is called. However, if they were expectinggodot_gdnative_terminate
to be called beforegodot_nativescript_init
was called again, invariants could be broken and lead to crashes or even UB on the nextgodot_nativescript_init
callback.The workaround, whether this fix is applied or not, is to mark the library as not-reloadable (luckily this case was fixed by 5228871). However, since the current situation can very easily lead to undefined behavior, a solution needs to be decided on, and the changes in this PR appear to be the original intended behavior.