godot
godot copied to clipboard
NaN/inf not handled in Curve3D `sample_baked`, crashes
Tested versions
Reproducible in: v4.2+v4.3 stable
System information
Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Mobile) - dedicated NVIDIA GeForce GTX 1070 (NVIDIA; 32.0.15.6070) - Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz (16 Threads)
Issue description
In my project I perform the operation sqrt(1-x) where x can be more than 1.0 due to a strangely imprecise dot-product between two normalized Vector2s. When x=1.0000001 or more, the operation produces NaN as negative square-roots aren't real numbers.
Adding NaN to a property related to a node's Transform (e.g. rotation.y) safely produces !v.is_finite() messages without crashing in a fresh project. But in my project, for reasons that escape me, that NaN manages to go all the way into render culling logic, producing the following errors in the console then crashing the running game instance:
ERROR: Condition "!v.is_finite()" is true.
at: instance_set_transform (servers/rendering/renderer_scene_cull.cpp:935)
ERROR: FATAL: Index p_index = 3750 is out of bounds (size() = 3750).
at: get (./core/templates/cowdata.h:205)
Replacing the operation with sqrt(1-min(1,x)) does not produce a NaN and thus entirely mitigates this, but I'd rather Godot not take a NaN for granted...
Steps to reproduce
Download and run the MRP's default scene. It will automatically crash after about 3 seconds, when the NaN is produced.
Minimal reproduction project (MRP)
Can replicate on Arch Linux's build of Godot in their repositories. Example project unsuccessfully tries to load godot-polyliner addon, but according to off-github communication between us the issue author just forgot to remove it and it goes unused.
System info: Godot v4.3.stable unknown - Arch Linux #1 SMP PREEMPT_DYNAMIC Fri, 18 Oct 2024 23:15:24 +0000 - Tty - Vulkan (Mobile) - dedicated AMD Radeon RX 7600S (RADV NAVI33) - AMD Ryzen 7 7735HS with Radeon Graphics (16 Threads)
Stack trace is without debuginfo, but nonetheless:
ERROR: Condition "!v.is_finite()" is true.
at: instance_set_transform (servers/rendering/renderer_scene_cull.cpp:935)
ERROR: FATAL: Index p_index = 3750 is out of bounds (size() = 3750).
at: get (./core/templates/cowdata.h:205)
================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.3.stable.arch_linux
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /usr/lib/libc.so.6(+0x41a80) [0x700188a43a80] (??:0)
[2] /usr/bin/godot(+0x3cb002a) [0x5f1a75a9102a] (??:?)
[3] /usr/bin/godot(+0x3cbbd2d) [0x5f1a75a9cd2d] (??:?)
[4] /usr/bin/godot(+0x3ccaa18) [0x5f1a75aaba18] (??:?)
[5] /usr/bin/godot(+0x127acd8) [0x5f1a7305bcd8] (??:?)
[6] /usr/bin/godot(+0x10e0f87) [0x5f1a72ec1f87] (??:?)
[7] /usr/bin/godot(+0x314dea6) [0x5f1a74f2eea6] (??:?)
[8] /usr/bin/godot(+0xfaa9f5) [0x5f1a72d8b9f5] (??:?)
[9] /usr/bin/godot(+0x54d9ac0) [0x5f1a772baac0] (??:?)
[10] /usr/bin/godot(+0x317320d) [0x5f1a74f5420d] (??:?)
[11] /usr/bin/godot(+0x31da63f) [0x5f1a74fbb63f] (??:?)
[12] /usr/bin/godot(+0x31e3615) [0x5f1a74fc4615] (??:?)
[13] /usr/bin/godot(+0xf7d0ed) [0x5f1a72d5e0ed] (??:?)
[14] /usr/bin/godot(+0xe1392d) [0x5f1a72bf492d] (??:?)
[15] /usr/lib/libc.so.6(+0x261ce) [0x700188a281ce] (??:0)
[16] /usr/lib/libc.so.6(__libc_start_main+0x8a) [0x700188a2828a] (??:0)
[17] /usr/bin/godot(+0xe36b85) [0x5f1a72c17b85] (??:?)
-- END OF BACKTRACE --
================================================================
Just built godot from the tag 4.3-stable with dev_build=yes on above hardware/OS, issue persists. Here's the full stacktrace:
ERROR: Condition "!v.is_finite()" is true.
at: instance_set_transform (servers/rendering/renderer_scene_cull.cpp:935)
ERROR: FATAL: Index p_index = 3750 is out of bounds (size() = 3750).
at: get (./core/templates/cowdata.h:205)
================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.3.stable.custom_build (77dcf97d82cbfe4e4615475fa52ca03da645dbd8)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /usr/lib/libc.so.6(+0x41a80) [0x766413753a80] (??:0)
[2] CowData<float>::get(long) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/templates/cowdata.h:205 (discriminator 3))
[3] Vector<float>::operator[](long) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/templates/vector.h:97)
[4] Curve3D::_find_interval(float) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/resources/curve.cpp:1768 (discriminator 1))
[5] Curve3D::sample_baked(float, bool) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/resources/curve.cpp:1898)
[6] void call_with_variant_args_retc_helper<__UnexistingClass, Vector3, float, bool, 0ul, 1ul>(__UnexistingClass*, Vector3 (__UnexistingClass::*)(float, bool) const, Variant const**, Variant&, Callable::CallError&, IndexSequence<0ul, 1ul>) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/variant/binder_common.h:807 (discriminator 2))
[7] void call_with_variant_args_retc_dv<__UnexistingClass, Vector3, float, bool>(__UnexistingClass*, Vector3 (__UnexistingClass::*)(float, bool) const, Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/variant/binder_common.h:569)
[8] MethodBindTRC<Vector3, float, bool>::call(Object*, Variant const**, int, Callable::CallError&) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/object/method_bind.h:620 (discriminator 1))
[9] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/modules/gdscript/gdscript_vm.cpp:1874 (discriminator 1))
[10] GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/modules/gdscript/gdscript.cpp:2032 (discriminator 1))
[11] bool Node::_gdvirtual__process_call<false>(double) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/node.h:351 (discriminator 2))
[12] Node::_notification(int) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/node.cpp:56)
[13] Node::_notificationv(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./scene/main/node.h:50 (discriminator 14))
[14] Node3D::_notificationv(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./scene/3d/node_3d.h:52 (discriminator 3))
[15] Object::notification(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/core/object/object.cpp:873)
[16] SceneTree::_process_group(SceneTree::ProcessGroup*, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:962)
[17] SceneTree::_process(bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:1034 (discriminator 2))
[18] SceneTree::process(double) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:528)
[19] Main::iteration() (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/main/main.cpp:4111 (discriminator 3))
[20] OS_LinuxBSD::run() (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/platform/linuxbsd/os_linuxbsd.cpp:962 (discriminator 1))
[21] /media/ext_hdd/nobackup/architector4/Downloads/godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x18c) [0x5b3de137e805] (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[22] /usr/lib/libc.so.6(+0x261ce) [0x7664137381ce] (??:0)
[23] /usr/lib/libc.so.6(__libc_start_main+0x8a) [0x76641373828a] (??:0)
[24] /media/ext_hdd/nobackup/architector4/Downloads/godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5b3de137e5a5] (??:?)
-- END OF BACKTRACE --
================================================================
Just built godot from latest commit in master branch, https://github.com/godotengine/godot/tree/44fa552343722bb048e2d7c6d3661174a95a8a3c, and issue persists:
ERROR: Condition "!v.is_finite()" is true.
at: instance_set_transform (servers/rendering/renderer_scene_cull.cpp:961)
ERROR: FATAL: Index p_index = 3750 is out of bounds (size() = 3750).
at: get (./core/templates/cowdata.h:205)
================================================================
handle_crash: Program crashed with signal 4
Engine version: Godot Engine v4.4.dev.custom_build (44fa552343722bb048e2d7c6d3661174a95a8a3c)
Dumping the backtrace. Please include this when reporting the bug to the project developer.
[1] /usr/lib/libc.so.6(+0x41a80) [0x724608817a80] (??:0)
[2] CowData<float>::get(long) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/templates/cowdata.h:205 (discriminator 3))
[3] Vector<float>::operator[](long) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/templates/vector.h:97)
[4] Curve3D::_find_interval(float) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/resources/curve.cpp:1768 (discriminator 1))
[5] Curve3D::sample_baked(float, bool) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/resources/curve.cpp:1898)
[6] void call_with_variant_args_retc_helper<__UnexistingClass, Vector3, float, bool, 0ul, 1ul>(__UnexistingClass*, Vector3 (__UnexistingClass::*)(float, bool) const, Variant const**, Variant&, Callable::CallError&, IndexSequence<0ul, 1ul>) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/variant/binder_common.h:807 (discriminator 2))
[7] void call_with_variant_args_retc_dv<__UnexistingClass, Vector3, float, bool>(__UnexistingClass*, Vector3 (__UnexistingClass::*)(float, bool) const, Variant const**, int, Variant&, Callable::CallError&, Vector<Variant> const&) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/variant/binder_common.h:569)
[8] MethodBindTRC<Vector3, float, bool>::call(Object*, Variant const**, int, Callable::CallError&) const (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./core/object/method_bind.h:620 (discriminator 1))
[9] GDScriptFunction::call(GDScriptInstance*, Variant const**, int, Callable::CallError&, GDScriptFunction::CallState*) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/modules/gdscript/gdscript_vm.cpp:2015 (discriminator 1))
[10] GDScriptInstance::callp(StringName const&, Variant const**, int, Callable::CallError&) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/modules/gdscript/gdscript.cpp:2046 (discriminator 1))
[11] Node::_gdvirtual__process_call(double) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/node.h:380 (discriminator 2))
[12] Node::_notification(int) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/node.cpp:56)
[13] Node::_notificationv(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./scene/main/node.h:50 (discriminator 14))
[14] Node3D::_notificationv(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/./scene/3d/node_3d.h:52 (discriminator 3))
[15] Object::notification(int, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/core/object/object.cpp:878)
[16] SceneTree::_process_group(SceneTree::ProcessGroup*, bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:1028)
[17] SceneTree::_process(bool) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:1100 (discriminator 2))
[18] SceneTree::process(double) (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/scene/main/scene_tree.cpp:590)
[19] Main::iteration() (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/main/main.cpp:4398 (discriminator 3))
[20] OS_LinuxBSD::run() (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/platform/linuxbsd/os_linuxbsd.cpp:962 (discriminator 1))
[21] /media/ext_hdd/nobackup/architector4/Downloads/godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(main+0x18c) [0x5930fceeb845] (/media/ext_hdd/nobackup/architector4/Downloads/godot/godot/platform/linuxbsd/godot_linuxbsd.cpp:85)
[22] /usr/lib/libc.so.6(+0x261ce) [0x7246087fc1ce] (??:0)
[23] /usr/lib/libc.so.6(__libc_start_main+0x8a) [0x7246087fc28a] (??:0)
[24] /media/ext_hdd/nobackup/architector4/Downloads/godot/godot/bin/godot.linuxbsd.editor.dev.x86_64(_start+0x25) [0x5930fceeb5e5] (??:?)
-- END OF BACKTRACE --
================================================================
Seems like a Curve3D bug:
https://github.com/godotengine/godot/blob/44fa552343722bb048e2d7c6d3661174a95a8a3c/scene/resources/curve.cpp#L1743-L1768
Hmm. In main.gd:
func _process(delta):
var p = kart.position - (kart.transform.basis.z * kart.velocity*4.0)
last_value = curve_offset.get_closest_offset(p)
var lookahead = 15.0*kart.velocity
var extra_dir = (curve_offset.sample_baked(last_value+lookahead) - curve_offset.sample_baked(last_value+lookahead+1)).normalized()
p adds the forward vector of the kart to its position, but the code will eventually add NaN to the rotation, making the basis NaN (supposedly), making p filled with NaN. get_closest_offset(p) probably makes last_value NaN, and that's passed to the sample_baked() calls.
Does Curve3D.sample_baked() check for finiteness?
Apparently not:
https://github.com/godotengine/godot/blob/44fa552343722bb048e2d7c6d3661174a95a8a3c/scene/resources/curve.cpp#L1883-L1900