godotengine / godot

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

Saving procedural MeshInstance3D backed by ArrayMesh as resource or scene causes access violation #91385

Closed csm-kb closed 2 months ago

csm-kb commented 6 months ago

Tested versions

Reproduced

Not repro'd

System information

Godot v4.2.2.stable.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 4080 (NVIDIA; 31.0.15.5222) - 11th Gen Intel(R) Core(TM) i7-11700K @ 3.60GHz (16 Threads)

Issue description

Hey team! Working in a Mono-enabled version of Godot here for performance. Attached MRP uses C#, I'm steadily working to convert the core to GDScript for easier access; but the access violation below originates from within the native ResourceSaver::save call somewhere from what I could trace, so it should be agnostic.

This appears in latest 4.2.2-stable, but surprisingly doesn't appear in 4.3-dev5 (i.e. what I'm attempting just works there). Curious to know where the delta is!


Context

For a side project, I generate lots of procedural mesh chunks (with LOD info) in a grid. My latest move was to serialize the generated mesh data, so that I don't have to regenerate from map data every time.

I devised two ways to do this:

  1. Directly save the ArrayMesh resources pulled from MeshInstance3Ds to a PackedMap custom resource (list or dict), so it can be reproduced by a packed map loader in a future dynamic scene.
  2. Create a new Node3D, duplicate + add_child + set owner on all of the generated MeshInstance3Ds from the map generator node, and then pack it into a scene with metadata (PackedMap).

The Bug

Having tried both ways (and settled on the latter), I ran into a brick wall:

Godot Editor stopped with exit code: 3221225477 (-> hex 0xC0000005)


- Method 2 (shown in the MRP) would also spin for a bit, with a corresponding memory increase, and produce the above error.

I have not yet worked with a scratch-built local copy of Godot (but particularly 4.2.2-stable) so I could natively debug it and diagnose further, but figured I would push this here.

Even if this is a no-factor for 4.3 (as it appears resolved in dev5), I want to determine where the source fix was to learn from it!

### Steps to reproduce

1. Open MRP with a console-enabled version of Godot (e.g. console exe, via VSCode)
2. `test_mapgen` scene should take a second to open by default -- if not, open it
3. Click on the `Map` node, and trigger the `Save Map To Disk` flag
4. Wait for the crash...
5. Observe the above access violation

### Minimal reproduction project (MRP)

[MeshCrashMiniRepo.zip](https://github.com/godotengine/godot/files/15172411/MeshCrashMiniRepo.zip)
raulsntos commented 5 months ago

I'm able to reproduce in 4.2.2.stable.mono.custom_build.15073afe3, but as mentioned it seems to be fixed in master. Here's the stacktrace anyway:

* thread #1, name = 'godot.linuxbsd.', stop reason = signal SIGSEGV: address not mapped to object (fault address: 0x7fbd8f801000)
  * frame #0: 0x000055555faf7fa8 godot.linuxbsd.editor.dev.x86_64.llvm.mono`FileAccessCompressed::store_8(this=0x000055557c981070, p_dest='\0') at file_access_compressed.cpp:349:25
    frame #1: 0x000055555faee45b godot.linuxbsd.editor.dev.x86_64.llvm.mono`FileAccess::store_buffer(this=0x000055557c981070, p_src="\xe8\U00000003", p_length=1488024) at file_access.cpp:711:3
    frame #2: 0x000055555fb6cb72 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinaryInstance::write_variant(f=Ref<FileAccess> @ 0x00007fffffffa3a8, p_property=0x00005555e0805f68, resource_map=0x00007fffffffbdf0, external_resources=0x00007fffffffc2e0, string_map=0x00007fffffffc2a0, p_hint=0x00007fffffffa378) at resource_format_binary.cpp:1841:7
    frame #3: 0x000055555fb6c9e5 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinaryInstance::write_variant(f=Ref<FileAccess> @ 0x00007fffffffacf0, p_property=0x00005555e0806258, resource_map=0x00007fffffffbdf0, external_resources=0x00007fffffffc2e0, string_map=0x00007fffffffc2a0, p_hint=0x00007fffffffacc0) at resource_format_binary.cpp:1831:5
    frame #4: 0x000055555fb6c78d godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinaryInstance::write_variant(f=Ref<FileAccess> @ 0x00007fffffffb5a8, p_property=0x00005555e08062f0, resource_map=0x00007fffffffbdf0, external_resources=0x00007fffffffc2e0, string_map=0x00007fffffffc2a0, p_hint=0x00007fffffffb578) at resource_format_binary.cpp:1822:5
    frame #5: 0x000055555fb6c9e5 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinaryInstance::write_variant(f=Ref<FileAccess> @ 0x00007fffffffbcd0, p_property=0x00005555e0806338, resource_map=0x00007fffffffbdf0, external_resources=0x00007fffffffc2e0, string_map=0x00007fffffffc2a0, p_hint=0x00005555e0806350) at resource_format_binary.cpp:1831:5
    frame #6: 0x000055555fb71800 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinaryInstance::save(this=0x00007fffffffc240, p_path=0x00007fffffffc318, p_resource=0x00007fffffffc558, p_flags=32) at resource_format_binary.cpp:2288:4
    frame #7: 0x000055555fb733e7 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceFormatSaverBinary::save(this=0x0000555560a8f050, p_resource=0x00007fffffffc558, p_path=0x00007fffffffc448, p_flags=32) at resource_format_binary.cpp:2427:15
    frame #8: 0x000055555fb81719 godot.linuxbsd.editor.dev.x86_64.llvm.mono`ResourceSaver::save(p_resource=0x00007fffffffc558, p_path=0x00007fffffffc828, p_flags=32) at resource_saver.cpp:128:19
    frame #9: 0x000055555f8e69e7 godot.linuxbsd.editor.dev.x86_64.llvm.mono`core_bind::ResourceSaver::save(this=0x0000555560cdeb40, p_resource=0x00007fffffffc558, p_path=0x00007fffffffc828, p_flags=(value = 32)) at core_bind.cpp:154:9
    frame #10: 0x000055555f977701 godot.linuxbsd.editor.dev.x86_64.llvm.mono`void call_with_ptr_args_ret_helper<__UnexistingClass, Error, Ref<Resource> const&, String const&, BitField<core_bind::ResourceSaver::SaverFlags>, 0ul, 1ul, 2ul>(p_instance=0x0000555560cdeb40, p_method=(godot.linuxbsd.editor.dev.x86_64.llvm.mono`core_bind::ResourceSaver::save(Ref<Resource> const&, String const&, BitField<core_bind::ResourceSaver::SaverFlags>) at core_bind.cpp:152), p_args=0x00007fffffffc7b0, r_ret=0x00007fffffffc830, (null)=IndexSequence<0UL, 1UL, 2UL> @ 0x00007fffffffc588) at binder_common.h:334:22
    frame #11: 0x000055555f977615 godot.linuxbsd.editor.dev.x86_64.llvm.mono`void call_with_ptr_args_ret<__UnexistingClass, Error, Ref<Resource> const&, String const&, BitField<core_bind::ResourceSaver::SaverFlags>>(p_instance=0x0000555560cdeb40, p_method=(godot.linuxbsd.editor.dev.x86_64.llvm.mono`core_bind::ResourceSaver::save(Ref<Resource> const&, String const&, BitField<core_bind::ResourceSaver::SaverFlags>) at core_bind.cpp:152), p_args=0x00007fffffffc7b0, r_ret=0x00007fffffffc830) at binder_common.h:582:2
    frame #12: 0x000055555f976b95 godot.linuxbsd.editor.dev.x86_64.llvm.mono`MethodBindTR<Error, Ref<Resource> const&, String const&, BitField<core_bind::ResourceSaver::SaverFlags>>::ptrcall(this=0x0000555560cdef70, p_object=0x0000555560cdeb40, p_args=0x00007fffffffc7b0, r_ret=0x00007fffffffc830) const at method_bind.h:513:3
    frame #13: 0x000055555b342bae godot.linuxbsd.editor.dev.x86_64.llvm.mono`godotsharp_method_bind_ptrcall(p_method_bind=0x0000555560cdef70, p_instance=0x0000555560cdeb40, p_args=0x00007fffffffc7b0, p_ret=0x00007fffffffc830) at runtime_interop.cpp:557:17
    frame #14: 0x00007fff4965d8db
    frame #15: 0x00007fff4965d7e1
    frame #16: 0x00007fff4bf3568b
    frame #17: 0x00007fff4bf350fe
    frame #18: 0x00007fff4c3eb357
    frame #19: 0x00007fff4c3e8ae3
    frame #20: 0x00007fff4964b9bc
    frame #21: 0x000055555b322956 godot.linuxbsd.editor.dev.x86_64.llvm.mono`CSharpInstance::callp(this=0x000055557497ba50, p_method=0x00007fffcc04d320, p_args=0x0000000000000000, p_argcount=0, r_error=0x00007fffffffd198) at csharp_script.cpp:1768:2
    frame #22: 0x00005555600f5157 godot.linuxbsd.editor.dev.x86_64.llvm.mono`Object::callp(this=0x0000555579cb05e0, p_method=0x00007fffcc04d320, p_args=0x0000000000000000, p_argcount=0, r_error=0x00007fffffffd198) at object.cpp:753:26
    frame #23: 0x000055555fcfc3a4 godot.linuxbsd.editor.dev.x86_64.llvm.mono`Callable::callp(this=0x00007fffcc04d320, p_arguments=0x0000000000000000, p_argcount=0, r_return_value=0x00007fffffffd180, r_call_error=0x00007fffffffd198) const at callable.cpp:69:25
    frame #24: 0x00005555600ef910 godot.linuxbsd.editor.dev.x86_64.llvm.mono`CallQueue::_call_function(this=0x0000555560dd75c0, p_callable=0x00007fffcc04d320, p_args=0x00007fffcc04d338, p_argcount=0, p_show_error=true) at message_queue.cpp:221:13
    frame #25: 0x00005555600f01ba godot.linuxbsd.editor.dev.x86_64.llvm.mono`CallQueue::flush(this=0x0000555560dd75c0) at message_queue.cpp:326:6
    frame #26: 0x000055555d47c2b9 godot.linuxbsd.editor.dev.x86_64.llvm.mono`SceneTree::physics_process(this=0x0000555563578b00, p_time=0.016666666666666666) at scene_tree.cpp:471:33
    frame #27: 0x000055555a864f27 godot.linuxbsd.editor.dev.x86_64.llvm.mono`Main::iteration() at main.cpp:3640:45
    frame #28: 0x000055555a7b5c31 godot.linuxbsd.editor.dev.x86_64.llvm.mono`OS_LinuxBSD::run(this=0x00007fffffffd568) at os_linuxbsd.cpp:958:7
    frame #29: 0x000055555a7a98ec godot.linuxbsd.editor.dev.x86_64.llvm.mono`main(argc=4, argv=0x00007fffffffdb28) at godot_linuxbsd.cpp:74:6
    frame #30: 0x00007ffff7c29d90 libc.so.6`__libc_start_call_main(main=(godot.linuxbsd.editor.dev.x86_64.llvm.mono`main at godot_linuxbsd.cpp:44), argc=4, argv=0x00007fffffffdb28) at libc_start_call_main.h:58:16
    frame #31: 0x00007ffff7c29e40 libc.so.6`__libc_start_main_impl(main=<unavailable>, argc=4, argv=<unavailable>, init=<unavailable>, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffdb18) at libc-start.c:392:3
    frame #32: 0x000055555a7a9625 godot.linuxbsd.editor.dev.x86_64.llvm.mono`_start + 37

I don't know what fixed it but it doesn't look related to .NET. To find the change that fixed it you'll have to do a git bisect.

csm-kb commented 5 months ago

@raulsntos Awesome, cheers for yielding that!

akien-mga commented 2 months ago

Closing as fixed in 4.3. If someone who can reproduce the issue wants to bisect to find what fixed it in master, we could evaluate whether it can be cherry-picked for 4.2.x. But the 4.3 release is imminent.