X Tutup
Skip to content

Fix late destruction access violation with OpenXRAPIExtension object#110868

Merged
Repiteo merged 1 commit intogodotengine:masterfrom
brycehutchings:openxr_late_destruction_crash_fix
Sep 25, 2025
Merged

Fix late destruction access violation with OpenXRAPIExtension object#110868
Repiteo merged 1 commit intogodotengine:masterfrom
brycehutchings:openxr_late_destruction_crash_fix

Conversation

@brycehutchings
Copy link
Contributor

I have a game using a GDExtension with an OpenXRExtensionWrapper class, and once I added code to call get_openxr_api() I started observing crashes when the exported game process would exit. Just to make sure it's not something I am doing wrong, I exported and ran the "godot-xr-template" demo project and saw the same thing.

What I found was a change to refactor this class moved the Ref<OpenXRAPIExtension> from a member variable to a static delay-initialized variable instead. I can see why this was done because then you don't pay for it if you don't need it, and if you do need it, you only pay for it once. But the problem is that this static variable holds the last reference to this object and so the cleanup will happen at the very end, after the WinMain() function has returned and the C runtime code runs to clean up global variables. At this point it seems like there is some "instance binding" with pointers that are no longer valid (perhaps pointers into the GDExtension DLL?).

I am not familiar with this system to know what the best fix is, so I opted to revert this back to the prior behavior. The object that it creates looks light weight (no initialization code, no member variables) so I think having separate copies per OpenXRExtensionWrapper and initializing them immediately is not bad. As I said, I don't know enough about this area to say whether something different or better is needed. See #104087 "OpenXR: Clean-up OpenXRExtensionWrapper by removing multiple inheritance and deprecating OpenXRExtensionWrapperExtension" for more details on the commit that changed this from member variable to static.

Stack and crash details below:

 	00007ffc33720eb0()	Unknown
>	OpenXR Demo.exe!Object::_instance_binding_reference(bool p_reference) Line 711	C++
 	OpenXR Demo.exe!RefCounted::unreference() Line 89	C++
 	OpenXR Demo.exe!Ref<OpenXRAPIExtension>::unref() Line 207	C++
 	OpenXR Demo.exe!Ref<OpenXRAPIExtension>::~Ref<OpenXRAPIExtension>() Line 223	C++
 	OpenXR Demo.exe!`OpenXRExtensionWrapper::_gdextension_get_openxr_api'::`2'::`dynamic atexit destructor for 'openxr_api_extension''()	C++
 	OpenXR Demo.exe!_execute_onexit_table::__l2::<lambda>() Line 206	C++
 	OpenXR Demo.exe!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) &,void <lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, _execute_onexit_table::__l2::int <lambda>(void) & action, __acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 204	C++
 	[Inline Frame] OpenXR Demo.exe!__acrt_lock_and_call(const __acrt_lock_id) Line 983	C++
 	OpenXR Demo.exe!_execute_onexit_table(_onexit_table_t * table) Line 160	C++
 	OpenXR Demo.exe!common_exit::__l2::<lambda>() Line 230	C++
 	OpenXR Demo.exe!__crt_seh_guarded_call<void>::operator()<void <lambda>(void),void <lambda>(void) &,void <lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, common_exit::__l2::void <lambda>(void) & action, __acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 224	C++
 	[Inline Frame] OpenXR Demo.exe!__acrt_lock_and_call(const __acrt_lock_id) Line 983	C++
 	OpenXR Demo.exe!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 199	C++
 	OpenXR Demo.exe!__scrt_common_main_seh() Line 295	C++
 	OpenXR Demo.exe!ShimMainCRTStartup(...) Line 74	C
 	kernel32.dll!00007ffd8787e8d7()	Unknown
 	ntdll.dll!RtlUserThreadStart(long(*)(void *) StartAddress, void * Argument) Line 1184	C
instance_binding_crash instance_binding_crash_locals

@brycehutchings brycehutchings requested a review from a team as a code owner September 24, 2025 19:39
@m4gr3d m4gr3d added this to the 4.6 milestone Sep 24, 2025
@m4gr3d m4gr3d added the cherrypick:4.5 Considered for cherry-picking into a future 4.5.x release label Sep 24, 2025
Copy link
Contributor

@dsnopek dsnopek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I think this change is fine. If we wanted, we could probably have OpenXRAPI (or some other singleton) manage the OpenXRAPIExtension instance, and then we could still have just one of them. But having an extra instance per extension wrapper probably isn't a very big deal.

Copy link
Contributor

@BastiaanOlij BastiaanOlij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me too as a way to handle this. I guess we could have multiple instances of the extension wrapper class but they all point to the same singleton.

Davids suggestion for making the wrapper instance lifecycle be handled by the OpenXRAPI class itself is a good one too, but for now this seems good enough to me.

@Repiteo
Copy link
Contributor

Repiteo commented Sep 25, 2025

Could you squash your commits? See our pull request guidelines for more information

@brycehutchings brycehutchings force-pushed the openxr_late_destruction_crash_fix branch from 77e3ed8 to cd198f7 Compare September 25, 2025 17:13
@brycehutchings
Copy link
Contributor Author

Could you squash your commits? See our pull request guidelines for more information

Sorry about that, I've squashed it

@Repiteo Repiteo merged commit e49e73e into godotengine:master Sep 25, 2025
20 checks passed
@Repiteo
Copy link
Contributor

Repiteo commented Sep 25, 2025

Thanks!

@Repiteo
Copy link
Contributor

Repiteo commented Sep 30, 2025

Cherry-picked to 4.5

@Repiteo Repiteo removed the cherrypick:4.5 Considered for cherry-picking into a future 4.5.x release label Sep 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

X Tutup