godot icon indicating copy to clipboard operation
godot copied to clipboard

Crash when iterating over custom GDScript iterator captured within lambda

Open mihe opened this issue 3 months ago • 1 comments

Tested versions

Reproducible in: 4.3.dev [780e1a504]

System information

Windows 11 (10.0.22631)

Issue description

I'm not sure of the correlation here, but it seems that if you in a GDScript script create an instance of a custom iterator, capture that iterator within a lambda to iterate over it, and then invoke that lambda, like so:

extends Node

class RangeIterator:
    var _count: int
    var _current: int

    func _init(count: int) -> void:
        _count = count
        _current = 0

    func should_continue() -> bool:
        return _current < _count

    func _iter_init(arg: Variant) -> bool:
        _current = 0
        return should_continue()

    func _iter_next(arg: Variant) -> bool:
        _current += 1
        return should_continue()

    func _iter_get(arg: Variant) -> Variant:
        return _current

func _init() -> void:
    var iterator := RangeIterator.new(4)

    var iterate := func() -> void:
        for value in iterator:
            pass

    iterate.call()

... you will crash the application here due to instruction_args being nullptr, with the following backtrace:

GDScriptFunction::call(GDScriptInstance * p_instance, const Variant * * p_args, int p_argcount, Callable::CallError & r_err, GDScriptFunction::CallState * p_state) (modules/gdscript/gdscript_vm.cpp:2997)
GDScriptLambdaCallable::call(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) (modules/gdscript/gdscript_lambda_callable.cpp:118)
Callable::callp(const Variant * * p_arguments, int p_argcount, Variant & r_return_value, Callable::CallError & r_call_error) (core/variant/callable.cpp:58)
_VariantCall::func_Callable_call(Variant * v, const Variant * * p_args, int p_argcount, Variant & r_ret, Callable::CallError & r_error) (core/variant/variant_call.cpp:1025)
`_register_variant_builtin_methods'::`2'::Method_Callable_call::call(Variant * base, const Variant * * p_args, int p_argcount, Variant & r_ret, const Vector<Variant> & p_defvals, Callable::CallError & r_error) (core/variant/variant_call.cpp:2064)
Variant::callp(const StringName & p_method, const Variant * * p_args, int p_argcount, Variant & r_ret, Callable::CallError & r_error) (core/variant/variant_call.cpp:1226)
GDScriptFunction::call(GDScriptInstance * p_instance, const Variant * * p_args, int p_argcount, Callable::CallError & r_err, GDScriptFunction::CallState * p_state) (modules/gdscript/gdscript_vm.cpp:1746)
GDScript::_create_instance(const Variant * * p_args, int p_argcount, Object * p_owner, bool p_is_ref_counted, Callable::CallError & r_error) (modules/gdscript/gdscript.cpp:182)
GDScript::instance_create(Object * p_this) (modules/gdscript/gdscript.cpp:414)
Object::set_script(const Variant & p_script) (core/object/object.cpp:969)
Node::set_script(const Variant & p_script) (scene/main/node.cpp:3867)
Object::set(const StringName & p_name, const Variant & p_value, bool * r_valid) (core/object/object.cpp:265)
SceneState::instantiate(SceneState::GenEditState p_edit_state) (scene/resources/packed_scene.cpp:343)
PackedScene::instantiate(PackedScene::GenEditState p_edit_state) (scene/resources/packed_scene.cpp:2077)
Main::start() (main/main.cpp:3812)
widechar_main(int argc, wchar_t * * argv) (platform/windows/godot_windows.cpp:179)
_main() (platform/windows/godot_windows.cpp:206)
main(int argc, char * * argv) (platform/windows/godot_windows.cpp:220)
WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) (platform/windows/godot_windows.cpp:234)

Steps to reproduce

  1. Run the main scene of the MRP
  2. Observe the crash

Minimal reproduction project (MRP)

captured-iterators.zip

mihe avatar Apr 25 '24 13:04 mihe

Possibly related to #74686.

mihe avatar Apr 25 '24 13:04 mihe