godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.55k stars 20.07k forks source link

Executing `MultiMesh._get_transform_2d_array` function crashes Godot with GLES3 #92038

Open qarmin opened 3 months ago

qarmin commented 3 months ago

Tested versions

4.3 c27f24da81a6b5a3282a16a10a8e3749cde4ef7c

System information

Ubuntu 22.04 CI

Issue description

When executing (this code was automatically minimized, so it is possible, that an even more "minimal" project can be created)

extends Node
func _process(delta):
    var temp_variable878 = MultiMesh.new()
    temp_variable878.property_get_revert(StringName("."))
    temp_variable878.set_instance_count(18)
    temp_variable878._get_transform_2d_array()
    temp_variable878.get_method_argument_count(StringName("."))
    temp_variable878.set_buffer(PackedFloat32Array([81.8810119628906, -37.9453048706055, 7.53989219665527, 6.33658170700073, 48.5376014709473, -56.5251426696777, 36.5014190673828, -39.4767036437988, -62.3482704162598, 99.3360900878906, 12.1148347854614, -52.8599128723145, 1.81378126144409, -41.4583511352539, 0, 99.078498840332, 85.0770950317383, -69.0927352905273, -88.7104034423828, -4.80872392654419, -19.7792835235596, 57.4738006591797, 57.2557907104492, -88.3957595825195, 98.5607528686523]))
    temp_variable878._get_transform_2d_array()

Godot crashes:

Godot Engine v4.3.beta.custom_build - https://godotengine.org
MESA: error: ZINK: failed to choose pdev
glx: failed to create drisw screen
failed to load driver: zink
######################## Ending test ########################
ERROR: Condition "p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)" is true.
   at: multimesh_set_buffer (drivers/gles3/storage/mesh_storage.cpp:1945)
=================================================================
==22835==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60e001451c40 at pc 0x562aa24888f2 bp 0x7ffde9d890b0 sp 0x7ffde9d890a0
READ of size 4 at 0x60e001451c40 thread T0
    #0 0x562aa24888f1 in GLES3::MeshStorage::multimesh_instance_get_transform_2d(RID, int) const drivers/gles3/storage/mesh_storage.cpp:1826
    #1 0x562ab2a4882d in RenderingServerDefault::multimesh_instance_get_transform_2d(RID, int) const servers/rendering/rendering_server_default.h:340
    #2 0x562aaed9be56 in MultiMesh::get_instance_transform_2d(int) const scene/resources/multimesh.cpp:253
    #3 0x562aaed9687c in MultiMesh::_get_transform_2d_array() const scene/resources/multimesh.cpp:127
    #4 0x562a9b3d01cb in void call_with_variant_args_retc_helper<__UnexistingClass, Vector<Vector2>>(__UnexistingClass*, Vector<Vector2> (__UnexistingClass::*)() const, Variant const**, Variant&, Callable::CallError&, IndexSequence<>) core/variant/binder_common.h:807
    #5 0x562a9b3b8d9f in void call_with_variant_args_retc_dv<__UnexistingClass, Vector<Vector2>>(__UnexistingClass*, Vector<Vector2> (__UnexistingClass::*)() const, Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) core/variant/binder_common.h:568
    #6 0x562a9b38c428 in MethodBindTRC<Vector<Vector2>>::call(Object*, Variant const**, int, Callable::CallError&) const core/object/method_bind.h:620
    #7 0x562ab78638e9 in Object::callp(StringName const&, Variant const**, int, Callable::CallError&) core/object/object.cpp:841
    #8 0x562ab6b5fffc in Variant::callp(StringName const&, Variant const**, int, Variant&, Callable::CallError&) core/variant/variant_call.cpp:1211
    #9 0x562a9c380583 in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_vm.cpp:1767
    #10 0x562a9bc01a8d in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:2006
    #11 0x562aa9e83a4a in bool Node::_gdvirtual__process_call<false>(double) scene/main/node.h:351
    #12 0x562aa9db1199 in Node::_notification(int) scene/main/node.cpp:55
    #13 0x562a9b25fedf in Node::_notificationv(int, bool) scene/main/node.h:50
    #14 0x562ab7865472 in Object::notification(int, bool) core/object/object.cpp:903
    #15 0x562aa9fbe4a4 in SceneTree::_process_group(SceneTree::ProcessGroup*, bool) scene/main/scene_tree.cpp:962
    #16 0x562aa9fc1740 in SceneTree::_process(bool) scene/main/scene_tree.cpp:1039
    #17 0x562aa9fb06cb in SceneTree::process(double) scene/main/scene_tree.cpp:526
    #18 0x562a9a8a3dca in Main::iteration() main/main.cpp:4052
    #19 0x562a9a599bb1 in OS_LinuxBSD::run() platform/linuxbsd/os_linuxbsd.cpp:962
    #20 0x562a9a5789ff in main platform/linuxbsd/godot_linuxbsd.cpp:85
    #21 0x7ff16c229d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
    #22 0x7ff16c229e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #23 0x562a9a578474 in _start (/home/runner/work/Qarminer/Qarminer/godot.linuxbsd.editor.dev.x86_64.san+0x403b8474)
0x60e001451c40 is located 0 bytes to the right of 160-byte region [0x60e001451ba0,0x60e001451c40)
allocated by thread T0 here:
    #0 0x7ff16ceb4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0x562ab5ccd559 in Memory::alloc_static(unsigned long, bool) core/os/memory.cpp:75
    #2 0x562a9b353587 in Error CowData<float>::resize<false>(long) core/templates/cowdata.h:340
    #3 0x562a9b3400fe in Vector<float>::resize(long) core/templates/vector.h:95
    #4 0x562ab720600e in VariantConstructorFromArray<Vector<float> >::validated_construct(Variant*, Variant const**) core/variant/variant_construct.h:560
    #5 0x562a9c37a1fb in GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) modules/gdscript/gdscript_vm.cpp:1622
    #6 0x562a9bc01a8d in GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) modules/gdscript/gdscript.cpp:2006
    #7 0x562aa9e83a4a in bool Node::_gdvirtual__process_call<false>(double) scene/main/node.h:351
    #8 0x562aa9db1199 in Node::_notification(int) scene/main/node.cpp:55
    #9 0x562a9b25fedf in Node::_notificationv(int, bool) scene/main/node.h:50
    #10 0x562ab7865472 in Object::notification(int, bool) core/object/object.cpp:903
    #11 0x562aa9fbe4a4 in SceneTree::_process_group(SceneTree::ProcessGroup*, bool) scene/main/scene_tree.cpp:962
    #12 0x562aa9fc1740 in SceneTree::_process(bool) scene/main/scene_tree.cpp:1039
    #13 0x562aa9fb06cb in SceneTree::process(double) scene/main/scene_tree.cpp:526
    #14 0x562a9a8a3dca in Main::iteration() main/main.cpp:4052
    #15 0x562a9a599bb1 in OS_LinuxBSD::run() platform/linuxbsd/os_linuxbsd.cpp:962
    #16 0x562a9a5789ff in main platform/linuxbsd/godot_linuxbsd.cpp:85
    #17 0x7ff16c229d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
SUMMARY: AddressSanitizer: heap-buffer-overflow drivers/gles3/storage/mesh_storage.cpp:1826 in GLES3::MeshStorage::multimesh_instance_get_transform_2d(RID, int) const
Shadow bytes around the buggy address:
  0x0c1c80282330: fd fd fd fd fa fa fa fa fa fa fa fa fd fd fd fd
  0x0c1c80282340: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c80282350: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c1c80282360: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa
  0x0c1c80282370: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c1c80282380: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
  0x0c1c80282390: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c802823a0: fd fd fd fd fa fa fa fa fa fa fa fa fd fd fd fd
  0x0c1c802823b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c1c802823c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1c802823d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Shadow gap:              cc
==22835==ABORTING

This example was found by Godot fuzzer - Qarminer, so it is quite unlikelly that this code could be used in real project, but still this should be handled gracefully.

Memory leaks or asan backtraces are visible when using Godot build with sanitizers support - https://github.com/qarmin/GodotBuilds/actions (linux -> linux-editor-sanitizers)

Steps to reproduce

Above

Minimal reproduction project (MRP)

Above

clayjohn commented 3 months ago

I can't reproduce with bd2300d77a6008167043f23fd91bcc562cde0a19. For me the ERROR: Condition "p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)" is true. error prints endlessly, but there is no crash.

akien-mga commented 3 months ago

Did you compile with asan?

@qarmin Could you include your build command in such reports? Asan crashes can only be reproduced with an asan build and that's not clear from the current format of your reports.

clayjohn commented 3 months ago

I didn't realize that this was only a crash in asan builds. I just built a normal debug build