godot icon indicating copy to clipboard operation
godot copied to clipboard

NaN/inf not handled in Curve3D `sample_baked`, crashes

Open Firepal opened this issue 1 year ago • 5 comments

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)

unhandled_nan.zip

Firepal avatar Oct 20 '24 22:10 Firepal

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 --
================================================================

Architector4 avatar Oct 20 '24 23:10 Architector4

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 --
================================================================

Architector4 avatar Oct 20 '24 23:10 Architector4

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 --
================================================================

Architector4 avatar Oct 20 '24 23:10 Architector4

Seems like a Curve3D bug:

https://github.com/godotengine/godot/blob/44fa552343722bb048e2d7c6d3661174a95a8a3c/scene/resources/curve.cpp#L1743-L1768

dalexeev avatar Oct 21 '24 05:10 dalexeev

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

Firepal avatar Oct 21 '24 08:10 Firepal