Skip to content
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

Possible memory leak in gdextension.cpp when method names are duplicated #101870

Open
0x53A opened this issue Jan 21, 2025 · 2 comments
Open

Possible memory leak in gdextension.cpp when method names are duplicated #101870

0x53A opened this issue Jan 21, 2025 · 2 comments

Comments

@0x53A
Copy link
Contributor

0x53A commented Jan 21, 2025

Tested versions

nightly

System information

linux

Issue description

While working on something unrelated, I got a memcheck failure in CI: https://github.com/godot-rust/gdext/actions/runs/12881698201/job/35912681146#step:3:1706

=================================================================
==3088==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 232 byte(s) in 1 object(s) allocated from:
    #0 0x55ba3602b62e in malloc (/home/runner/work/_temp/godot_bin/godot.linuxbsd.editor.dev.x86_64.llvm.san+0x21c9c62e) (BuildId: 874db2a84ccfa9b3)
    #1 0x55ba55e654e6 in Memory::alloc_static(unsigned long, bool) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:106:14
    #2 0x55ba55e65362 in operator new(unsigned long, char const*) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:39:9
    #3 0x55ba58953974 in GDExtension::_register_extension_class_method(void*, void const*, GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:509:12
    #4 0x7f5c738209e0 in godot_core::registry::method::ClassMethodInfo::register_nonvirtual_class_method::h6f44d6b7c80457d4 /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:157:13
    #5 0x7f5c7381fff8 in godot_core::registry::method::ClassMethodInfo::register_extension_class_method::hfb75fa1a2544ea5f /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:147:13
    #6 0x7f5c730ae1e2 in itest::register_tests::func_test::_::__init::__inner_init::_$u7b$$u7b$closure$u7d$$u7d$::h9ae97532f88693d3 /home/runner/work/gdext/gdext/itest/rust/src/register_tests/func_test.rs:79:1
    #7 0x7f5c72dbfffd in core::ops::function::FnOnce::call_once::h0a8edd5c08646abf /rustc/f3d1d47fd84dfcf7f513be1dbad356e74c8f3b2b/library/core/src/ops/function.rs:250:5
    #8 0x7f5c72c230a2 in godot_core::registry::callbacks::register_user_methods_constants::ha0604185de96699d /home/runner/work/gdext/gdext/godot-core/src/registry/callbacks.rs:392:5
    #9 0x7f5c7381756d in godot_core::registry::class::auto_register_classes::h71cfbbdffdad7470 /home/runner/work/gdext/gdext/godot-core/src/registry/class.rs:228:9
    #10 0x7f5c7386886c in godot_core::init::gdext_on_level_init::h1d4172dd01e950e9 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:161:5
    #11 0x7f5c72fd3a5a in godot_core::init::ffi_initialize_layer::_$u7b$$u7b$closure$u7d$$u7d$::hdf873678b0f13b97 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:107:9
    #12 0x7f5c71290641 in godot_core::private::handle_panic_with_print::h4b774d0a828afef5 /home/runner/work/gdext/gdext/godot-core/src/private.rs:377:17
    #13 0x7f5c70cf8878 in godot_core::private::handle_panic::h129b9f0e49e1359a /home/runner/work/gdext/gdext/godot-core/src/private.rs:275:5
    #14 0x55ba5895bbdd in GDExtension::initialize_library(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:745:2
    #15 0x55ba589f5fb1 in GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension_manager.cpp:228:12
    #16 0x55ba364c1f2b in Main::setup2(bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:3381:40
    #17 0x55ba364aed45 in Main::setup(char const*, int, char**, bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:2676:14
    #18 0x55ba36068f93 in main /home/runner/work/godot4-nightly/godot4-nightly/platform/linuxbsd/godot_linuxbsd.cpp:74:14
    #19 0x7f5c7be29d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

Direct leak of 232 byte(s) in 1 object(s) allocated from:
    #0 0x55ba3602b62e in malloc (/home/runner/work/_temp/godot_bin/godot.linuxbsd.editor.dev.x86_64.llvm.san+0x21c9c62e) (BuildId: 874db2a84ccfa9b3)
    #1 0x55ba55e654e6 in Memory::alloc_static(unsigned long, bool) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:106:14
    #2 0x55ba55e65362 in operator new(unsigned long, char const*) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:39:9
    #3 0x55ba58953974 in GDExtension::_register_extension_class_method(void*, void const*, GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:509:12
    #4 0x7f5c738209e0 in godot_core::registry::method::ClassMethodInfo::register_nonvirtual_class_method::h6f44d6b7c80457d4 /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:157:13
    #5 0x7f5c7381fff8 in godot_core::registry::method::ClassMethodInfo::register_extension_class_method::hfb75fa1a2544ea5f /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:147:13
    #6 0x7f5c730ae00f in itest::register_tests::func_test::_::__init::__inner_init::_$u7b$$u7b$closure$u7d$$u7d$::h9ae97532f88693d3 /home/runner/work/gdext/gdext/itest/rust/src/register_tests/func_test.rs:79:1
    #7 0x7f5c72dbfffd in core::ops::function::FnOnce::call_once::h0a8edd5c08646abf /rustc/f3d1d47fd84dfcf7f513be1dbad356e74c8f3b2b/library/core/src/ops/function.rs:250:5
    #8 0x7f5c72c230a2 in godot_core::registry::callbacks::register_user_methods_constants::ha0604185de96699d /home/runner/work/gdext/gdext/godot-core/src/registry/callbacks.rs:392:5
    #9 0x7f5c7381756d in godot_core::registry::class::auto_register_classes::h71cfbbdffdad7470 /home/runner/work/gdext/gdext/godot-core/src/registry/class.rs:228:9
    #10 0x7f5c7386886c in godot_core::init::gdext_on_level_init::h1d4172dd01e950e9 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:161:5
    #11 0x7f5c72fd3a5a in godot_core::init::ffi_initialize_layer::_$u7b$$u7b$closure$u7d$$u7d$::hdf873678b0f13b97 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:107:9
    #12 0x7f5c71290641 in godot_core::private::handle_panic_with_print::h4b774d0a828afef5 /home/runner/work/gdext/gdext/godot-core/src/private.rs:377:17
    #13 0x7f5c70cf8878 in godot_core::private::handle_panic::h129b9f0e49e1359a /home/runner/work/gdext/gdext/godot-core/src/private.rs:275:5
    #14 0x55ba5895bbdd in GDExtension::initialize_library(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:745:2
    #15 0x55ba589f5fb1 in GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension_manager.cpp:228:12
    #16 0x55ba364c1f2b in Main::setup2(bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:3381:40
    #17 0x55ba364aed45 in Main::setup(char const*, int, char**, bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:2676:14
    #18 0x55ba36068f93 in main /home/runner/work/godot4-nightly/godot4-nightly/platform/linuxbsd/godot_linuxbsd.cpp:74:14
    #19 0x7f5c7be29d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

Indirect leak of 20 byte(s) in 1 object(s) allocated from:
    #0 0x55ba3602b62e in malloc (/home/runner/work/_temp/godot_bin/godot.linuxbsd.editor.dev.x86_64.llvm.san+0x21c9c62e) (BuildId: 874db2a84ccfa9b3)
    #1 0x55ba55e654e6 in Memory::alloc_static(unsigned long, bool) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:106:14
    #2 0x55ba3957bf2d in Variant::Type* memnew_arr_template<Variant::Type>(unsigned long) /home/runner/work/godot4-nightly/godot4-nightly/./core/os/memory.h:180:28
    #3 0x55ba58b24fc5 in MethodBind::_generate_argument_types(int) /home/runner/work/godot4-nightly/godot4-nightly/core/object/method_bind.cpp:104:24
    #4 0x55ba5898964e in GDExtensionMethodBind::update(GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:223:3
    #5 0x55ba5896bf65 in GDExtensionMethodBind::GDExtensionMethodBind(GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:237:3
    #6 0x55ba589539b7 in GDExtension::_register_extension_class_method(void*, void const*, GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:509:12
    #7 0x7f5c738209e0 in godot_core::registry::method::ClassMethodInfo::register_nonvirtual_class_method::h6f44d6b7c80457d4 /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:157:13
    #8 0x7f5c7381fff8 in godot_core::registry::method::ClassMethodInfo::register_extension_class_method::hfb75fa1a2544ea5f /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:147:13
    #9 0x7f5c730ae1e2 in itest::register_tests::func_test::_::__init::__inner_init::_$u7b$$u7b$closure$u7d$$u7d$::h9ae97532f88693d3 /home/runner/work/gdext/gdext/itest/rust/src/register_tests/func_test.rs:79:1
    #10 0x7f5c72dbfffd in core::ops::function::FnOnce::call_once::h0a8edd5c08646abf /rustc/f3d1d47fd84dfcf7f513be1dbad356e74c8f3b2b/library/core/src/ops/function.rs:250:5
    #11 0x7f5c72c230a2 in godot_core::registry::callbacks::register_user_methods_constants::ha0604185de96699d /home/runner/work/gdext/gdext/godot-core/src/registry/callbacks.rs:392:5
    #12 0x7f5c7381756d in godot_core::registry::class::auto_register_classes::h71cfbbdffdad7470 /home/runner/work/gdext/gdext/godot-core/src/registry/class.rs:228:9
    #13 0x7f5c7386886c in godot_core::init::gdext_on_level_init::h1d4172dd01e950e9 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:161:5
    #14 0x7f5c72fd3a5a in godot_core::init::ffi_initialize_layer::_$u7b$$u7b$closure$u7d$$u7d$::hdf873678b0f13b97 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:107:9
    #15 0x7f5c71290641 in godot_core::private::handle_panic_with_print::h4b774d0a828afef5 /home/runner/work/gdext/gdext/godot-core/src/private.rs:377:17
    #16 0x7f5c70cf8878 in godot_core::private::handle_panic::h129b9f0e49e1359a /home/runner/work/gdext/gdext/godot-core/src/private.rs:275:5
    #17 0x55ba5895bbdd in GDExtension::initialize_library(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:745:2
    #18 0x55ba589f5fb1 in GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension_manager.cpp:228:12
    #19 0x55ba364c1f2b in Main::setup2(bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:3381:40
    #20 0x55ba364aed45 in Main::setup(char const*, int, char**, bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:2676:14
    #21 0x55ba36068f93 in main /home/runner/work/godot4-nightly/godot4-nightly/platform/linuxbsd/godot_linuxbsd.cpp:74:14
    #22 0x7f5c7be29d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

Indirect leak of 20 byte(s) in 1 object(s) allocated from:
    #0 0x55ba3602b62e in malloc (/home/runner/work/_temp/godot_bin/godot.linuxbsd.editor.dev.x86_64.llvm.san+0x21c9c62e) (BuildId: 874db2a84ccfa9b3)
    #1 0x55ba55e654e6 in Memory::alloc_static(unsigned long, bool) /home/runner/work/godot4-nightly/godot4-nightly/core/os/memory.cpp:106:14
    #2 0x55ba3957bf2d in Variant::Type* memnew_arr_template<Variant::Type>(unsigned long) /home/runner/work/godot4-nightly/godot4-nightly/./core/os/memory.h:180:28
    #3 0x55ba58b24fc5 in MethodBind::_generate_argument_types(int) /home/runner/work/godot4-nightly/godot4-nightly/core/object/method_bind.cpp:104:24
    #4 0x55ba5898964e in GDExtensionMethodBind::update(GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:223:3
    #5 0x55ba5896bf65 in GDExtensionMethodBind::GDExtensionMethodBind(GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:237:3
    #6 0x55ba589539b7 in GDExtension::_register_extension_class_method(void*, void const*, GDExtensionClassMethodInfo const*) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:509:12
    #7 0x7f5c738209e0 in godot_core::registry::method::ClassMethodInfo::register_nonvirtual_class_method::h6f44d6b7c80457d4 /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:157:13
    #8 0x7f5c7381fff8 in godot_core::registry::method::ClassMethodInfo::register_extension_class_method::hfb75fa1a2544ea5f /home/runner/work/gdext/gdext/godot-core/src/registry/method.rs:147:13
    #9 0x7f5c730ae00f in itest::register_tests::func_test::_::__init::__inner_init::_$u7b$$u7b$closure$u7d$$u7d$::h9ae97532f88693d3 /home/runner/work/gdext/gdext/itest/rust/src/register_tests/func_test.rs:79:1
    #10 0x7f5c72dbfffd in core::ops::function::FnOnce::call_once::h0a8edd5c08646abf /rustc/f3d1d47fd84dfcf7f513be1dbad356e74c8f3b2b/library/core/src/ops/function.rs:250:5
    #11 0x7f5c72c230a2 in godot_core::registry::callbacks::register_user_methods_constants::ha0604185de96699d /home/runner/work/gdext/gdext/godot-core/src/registry/callbacks.rs:392:5
    #12 0x7f5c738[1756](https://github.com/godot-rust/gdext/actions/runs/12881698201/job/35912681146#step:3:1772)d in godot_core::registry::class::auto_register_classes::h71cfbbdffdad7470 /home/runner/work/gdext/gdext/godot-core/src/registry/class.rs:228:9
    #13 0x7f5c7386886c in godot_core::init::gdext_on_level_init::h1d4172dd01e950e9 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:161:5
    #14 0x7f5c72fd3a5a in godot_core::init::ffi_initialize_layer::_$u7b$$u7b$closure$u7d$$u7d$::hdf873678b0f13b97 /home/runner/work/gdext/gdext/godot-core/src/init/mod.rs:107:9
    #15 0x7f5c71290641 in godot_core::private::handle_panic_with_print::h4b774d0a828afef5 /home/runner/work/gdext/gdext/godot-core/src/private.rs:377:17
    #16 0x7f5c70cf8878 in godot_core::private::handle_panic::h129b9f0e49e1359a /home/runner/work/gdext/gdext/godot-core/src/private.rs:275:5
    #17 0x55ba5895bbdd in GDExtension::initialize_library(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension.cpp:745:2
    #18 0x55ba589f5fb1 in GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel) /home/runner/work/godot4-nightly/godot4-nightly/core/extension/gdextension_manager.cpp:228:12
    #19 0x55ba364c1f2b in Main::setup2(bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:3381:40
    #20 0x55ba364aed45 in Main::setup(char const*, int, char**, bool) /home/runner/work/godot4-nightly/godot4-nightly/main/main.cpp:2676:14
    #21 0x55ba36068f93 in main /home/runner/work/godot4-nightly/godot4-nightly/platform/linuxbsd/godot_linuxbsd.cpp:74:14
    #22 0x7f5c7be29d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)

SUMMARY: AddressSanitizer: 504 byte(s) leaked in 4 allocation(s).

Looking into that error, method is allocated in L509 and passed into ClassDB::bind_method_custom.

if (method == nullptr) {
method = memnew(GDExtensionMethodBind(p_method_info));
method->set_instance_class(class_name);
extension->methods[method_name] = method;
} else {
method->is_reloading = false;
}
#else
GDExtensionMethodBind *method = memnew(GDExtensionMethodBind(p_method_info));
method->set_instance_class(class_name);
#endif
ClassDB::bind_method_custom(class_name, method);

If, for some reason, a method with the same name was already registered, it returns an error:

godot/core/object/class_db.cpp

Lines 1879 to 1882 in 1b7b009

if (type->method_map.has(p_method->get_name())) {
// overloading not supported
ERR_FAIL_MSG(vformat("Method already bound '%s::%s'.", p_class, p_method->get_name()));
}

The fix might be as simple as freeing p_method before returning.

Steps to reproduce

none

Minimal reproduction project (MRP)

none

@AThousandShips
Copy link
Member

nightly

There are no nightly builds, please specify version you're using

@0x53A
Copy link
Contributor Author

0x53A commented Jan 21, 2025

The commit used was 1b7b00967

(https://github.com/godot-rust/gdext/actions/runs/12881698201/job/35912681146#step:3:261)

Since I only noticed this in CI, I do not have a direct project for reproduction. I just looked at the code to create my theory for the cause.

And tbh, it’s an extremely minor issue: IF the user incorrectly calls the extension API (duplicated method names), THEN a tiny amount of memory is leaked ONE time at startup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants