Skip to content

Crash on exit when using OpenXRExtensionWrapperExtension #88613

@Malcolmnixon

Description

@Malcolmnixon

Tested versions

  • Reproducible in 4.3-dev [fb10e67]

System information

Windows 11, gl_compatibility, NVidia RTX 3070 TI

Issue description

When terminating a Godot application which uses any OpenXRExtensionWrapperExtension objects, the application terminates in a call of memdelete(extension_wrapper) with a pointer that isn't a valid block of heap memory.

The problem is caused by the inheritance structure of OpenXRExtensionWrapperExtension:

class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {

The problem occurs when OpenXRExtensionWrapperExtension::register_extension_wrapper() registers this class with OpenXRAPI::register_extension_wrapper() AS AN OpenXRExtensionWrapper:

void OpenXRExtensionWrapperExtension::register_extension_wrapper() {
OpenXRAPI::register_extension_wrapper(this);
}

The OpenXRAPI extension wrappers saves OpenXRExtensionWrapper instances in a Vector<OpenXRExtensionWrapper *> and later deletes them using memdelete.

The problem is that the memory layout of OpenXRExtensionWrapperExtension is as follows (sizes specific to Windows/X64):

  • Object base: 408 bytes
  • OpenXRExtensionWrapper base: 8 bytes
  • OpenXRCompositionLayerProvider base: 8 bytes
  • OpenXRExtensionWrapperExtension members: 688 bytes
  • Total size = 1112 bytes

When the OpenXRExtensionWrapperExtension::register_extension_wrapper() registers itself, it has to cast its this pointer to an OpenXRExtensionWrapper* which involves adding 408 to the pointer value to jump over the Object. When memdelete() is called on this pointer, it fails because the pointer isn't a block of allocated memory.

This pattern is fully supported in C++ using the normal new/delete, as the compiler will generate a "virtual deleting destructor" in the objects VTABLE, so a delete by any class type will correctly call the real destructor, then adjust the pointer to the start of the object and delete the memory.

Godot's use of memdelete() appears to bypass this machinery preventing safe deletion of multiple-inheritance classes.

Steps to reproduce

Run Godot with the godot_openxr_vendors extension (or any extension providing OpenXR extensions) and then terminate the application.

Minimal reproduction project (MRP)

N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions