AddressSanitizer reports heap-use-after-free in object_instance_id_when_freed integration test · Issue #89 · godot-rust/gdext (original) (raw)

I built a custom Godot 4 binary using:

$ scons optimize=debug debug_symbols=yes use_ubsan=yes use_asan=yes use_lsan=yes use_msan=yes

ASAN triggers an abort in the integration test on the is_instance_valid call here:

https://github.com/godot-rust/gdextension/blob/c37d0ce51cbc40292914015bce24bde1ab1a791a/itest/rust/src/object_test.rs#L156-L157

Full trace:

   -- object_instance_id_when_freed
=================================================================
==231428==ERROR: AddressSanitizer: heap-use-after-free on address 0x61a000031e90 at pc 0x55bbd4aa611d bp 0x7ffe8e2ab610 sp 0x7ffe8e2ab600
READ of size 8 at 0x61a000031e90 thread T0
    #0 0x55bbd4aa611c in gdextension_object_get_instance_id core/extension/gdextension_interface.cpp:935
    #1 0x7f4e3fac3e48 in godot_core::obj::gd::Gd$LT$T$GT$::instance_id_or_none::h6bf6c0272958a527 godot-core/src/obj/gd.rs:245
    #2 0x7f4e3fac3a3d in godot_core::obj::gd::Gd$LT$T$GT$::is_instance_valid::h141dab810e85fcaa godot-core/src/obj/gd.rs:273
    #3 0x7f4e3fabb7ec in itest::object_test::object_instance_id_when_freed::_$u7b$$u7b$closure$u7d$$u7d$::hfe59ff15c9d5bed3 itest/rust/src/object_test.rs:157
    #4 0x7f4e3fae0cbb in std::panicking::try::do_call::h104e89f3d9fa7b31 /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:483
    #5 0x7f4e3faef7fa in __rust_try (/home/thomas/gdextension/itest/godot/../../target/debug/libitest.so+0xef7fa)
    #6 0x7f4e3fad6c95 in std::panicking::try::h0ac213656080ecc2 /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:447
    #7 0x7f4e3fad2728 in std::panic::catch_unwind::h91a171faba7069ab /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panic.rs:137
    #8 0x7f4e3fa44410 in itest::object_test::object_instance_id_when_freed::h57b9df4b7dbd655c itest/rust/src/object_test.rs:151
    #9 0x7f4e3fa424f5 in itest::object_test::run::h1094db215a0ea691 itest/rust/src/object_test.rs:33
    #10 0x7f4e3faaf1a3 in itest::run_tests::hb5d66f5c57c15ab5 itest/rust/src/lib.rs:37
    #11 0x7f4e3faaf2ca in itest::IntegrationTests::run::h02b98bbdbf1e9732 itest/rust/src/lib.rs:65
    #12 0x7f4e3faaf01d in _$LT$itest..IntegrationTests$u20$as$u20$godot_core..obj..traits..cap..ImplementsGodotApi$GT$::__register_methods::function::_$u7b$$u7b$closure$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::h96e4d73b028b49ff godot-core/src/macros.rs:110
    #13 0x7f4e3fb0aca7 in core::ops::function::FnOnce::call_once::hd8e3e1fcd5d67a4a /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/core/src/ops/function.rs:251
    #14 0x7f4e3fa26807 in _$LT$$LP$R$C$$RP$$u20$as$u20$godot_core..builtin..meta..signature..SignatureTuple$GT$::ptrcall::hefc81992d74e99c4 godot-core/src/builtin/meta/signature.rs:161
    #15 0x7f4e3faaeff0 in _$LT$itest..IntegrationTests$u20$as$u20$godot_core..obj..traits..cap..ImplementsGodotApi$GT$::__register_methods::function::_$u7b$$u7b$closure$u7d$$u7d$::he26c1c1d176e0cb9 godot-core/src/macros.rs:104
    #16 0x7f4e3fae5c08 in std::panicking::try::do_call::h9c147f7996c369c6 /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:483
    #17 0x7f4e3faef7fa in __rust_try (/home/thomas/gdextension/itest/godot/../../target/debug/libitest.so+0xef7fa)
    #18 0x7f4e3fadcf0f in std::panicking::try::h944674e78df8af86 /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panicking.rs:447
    #19 0x7f4e3fad20b7 in std::panic::catch_unwind::h64f12795b33108fb /rustc/69f9c33d71c871fc16ac445211281c6e7a340943/library/std/src/panic.rs:137
    #20 0x7f4e3faafd3f in _$LT$itest..IntegrationTests$u20$as$u20$godot_core..obj..traits..cap..ImplementsGodotApi$GT$::__register_methods::function::h84eb79f17ccba806 godot-core/src/macros.rs:103
    #21 0x55bbd4a88a2a in GDExtensionMethodBind::ptrcall(Object*, void const**, void*) const core/extension/gdextension.cpp:197
    #22 0x55bbbbdf1271 in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_vm.cpp:1864
    #23 0x55bbbb757afb in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:1842
    #24 0x55bbc77a8be1 in bool Node::_gdvirtual__ready_call<false>() scene/main/node.h:242
    #25 0x55bbc77a8be1 in Node::_notification(int) scene/main/node.cpp:155
    #26 0x55bbba4fcabb in Node::_notificationv(int, bool) scene/main/node.h:46
    #27 0x55bbd4b734b5 in Object::notification(int, bool) core/object/object.cpp:790
    #28 0x55bbc77501c7 in Node::_propagate_ready() scene/main/node.cpp:188
    #29 0x55bbc774fb49 in Node::_propagate_ready() scene/main/node.cpp:180
    #30 0x55bbc7758ffc in Node::_set_tree(SceneTree*) scene/main/node.cpp:2596
    #31 0x55bbc7886d10 in SceneTree::initialize() scene/main/scene_tree.cpp:410
    #32 0x55bbb9c03b30 in OS_LinuxBSD::run() platform/linuxbsd/os_linuxbsd.cpp:866
    #33 0x55bbb9bf9fb3 in main platform/linuxbsd/godot_linuxbsd.cpp:73
    #34 0x7f4e4dc3c28f  (/usr/lib/libc.so.6+0x2328f)
    #35 0x7f4e4dc3c349 in __libc_start_main (/usr/lib/libc.so.6+0x23349)
    #36 0x55bbb9bf99c4 in _start (/home/thomas/godot/bin/godot.linuxbsd.editor.x86_64.san+0x33f5c9c4)

0x61a000031e90 is located 16 bytes inside of 1264-byte region [0x61a000031e80,0x61a000032370)
freed by thread T0 here:
    #0 0x7f4e4e6be672 in __interceptor_free /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x55bbd2d6ef3c in Memory::free_static(void*, bool) core/os/memory.cpp:168

previously allocated by thread T0 here:
    #0 0x7f4e4e6bfa89 in __interceptor_malloc /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x55bbd2d6e67a in Memory::alloc_static(unsigned long, bool) core/os/memory.cpp:75
    #2 0x617000067827  (<unknown module>)

SUMMARY: AddressSanitizer: heap-use-after-free core/extension/gdextension_interface.cpp:935 in gdextension_object_get_instance_id
Shadow bytes around the buggy address:
  0x0c347fffe380: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe390: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe3a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
  0x0c347fffe3b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c347fffe3c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c347fffe3d0: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe3e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe3f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe400: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe410: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c347fffe420: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==231428==ABORTING
[Finished running. Exit status: 1]

Not sure if this is an issue with Godot or with gdextension, but recording it here for now.