Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Causing infinite recursion with call_deferred ends the debugging process without throwing an error #88953

Closed
5ro4 opened this issue Feb 28, 2024 · 6 comments · Fixed by #88961

Comments

@5ro4
Copy link

5ro4 commented Feb 28, 2024

Tested versions

v4.2.1.stable.official [b09f793]

System information

Godot v4.2.1.stable - Windows 10.0.19045 - GLES3 (Compatibility) - NVIDIA GeForce RTX 3080 (NVIDIA; 31.0.15.4633) - AMD Ryzen 9 5900X 12-Core Processor (24 Threads)

Issue description

When causing an infinite recursion with a call_deferred, such as this:

func _ready() -> void:
_ready.call_deferred()

The running project window closes without explanation. The output just prints "--- Debugging process stopped ---"

Steps to reproduce

Create a node with a script with this code:

func _ready() -> void:
_ready.call_deferred()

Minimal reproduction project (MRP)

_DebugStopped.zip

@AThousandShips
Copy link
Member

AThousandShips commented Feb 28, 2024

This doesn't cause infinite recursion technically, it doesn't call itself it queues itself being called again and again

Does this happen with other methods? Calling _ready directly isn't necessarily safe regardless

And the code in question is perfectly legal and while inefficient and a bit odd in some cases a perfectly valid way to have something repeat every frame, though it might have some issues

So I suspect this might be related to _ready and not the call here, as call_deferred is not recursion, it queues up a call next frame

@AThousandShips
Copy link
Member

AThousandShips commented Feb 28, 2024

Can confirm this, and it happens because the message queue runs out of space:

Failed method: Node2D::_test. Message queue out of memory. Message queue out of memory. Try increasing 'memory/limits/message_queue/max_size_mb' in project settings.

The reason is simple, the call queue is filled up and functionally becomes infinite recursion, when it should instead defer those calls to later, will look at fixing this as it is breaking things even when it shouldn't, the deferred call shouldn't happen immediately I'd say in this case

Doing this avoids this issue, but shouldn't be needed:

func _foo() -> void:
    await get_tree().process_frame
    _foo.call_deferred()

There are also some potential memory safety issues here due to the pages being mutated, will look at a fix

@AThousandShips
Copy link
Member

AThousandShips commented Feb 28, 2024

Unfortunately the engine seems to depend on deferred calls being called immediately if we are managing the call queue, so this isn't safe even though I'd say it should be

I don't think there's currently any simple way to handle this, given these aspects, so it should be treated the same way as any recursive call even though it isn't technically one, a warning might be added to some of the documentation

Edit: This is already mentioned in Object.call_deferred, will elaborate in Callable and add some details to Object too.

@5ro4
Copy link
Author

5ro4 commented Feb 28, 2024

My actual problem with this is that no error or explanation is provided; the game just stops. I accidentally had this kind of recursive call in one script among hundreds and it took a while to figure out why the game just closed itself a second after starting.

@AThousandShips
Copy link
Member

AThousandShips commented Feb 28, 2024

There is an error, in the console, at least in 4.3, if the engine crashes you won't get any message elsewhere anyway so that's not specific to this

Note that with a normal infinite recursion there's no error at all, it just crashes silently

@5ro4
Copy link
Author

5ro4 commented Feb 28, 2024

I don't know about 4.3, but in 4.2, calling _ready() instead of _ready.call_deferred() throws this error: "Stack overflow. Check for infinite recursion in your script." But when using call_deferred it just crashes silently without any error in the console, just the message "Debugging process stopped".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants