godotengine / godotengine/godot

Calling call_deferred() from std::thread can spam thread-check errors when MessageQueue is full

Open
#119,397 0 comments 0 reactions 0 assignees View on GitHub
bug topic:core
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

4.6.2.stable

### System information

Android - 4.6.2.stable

### Issue description

There appears to be a secondary failure in the `call_deferred()` / `MessageQueue` out-of-memory error path.

When `call_deferred()` is called from a native `std::thread`, and the internal `CallQueue` / `MessageQueue` is full, Godot tries to print the following error:

```cpp
fprintf(stderr, "Failed method: %s. Message queue out of memory. %s\n", String(p_callable).utf8().get_data(), error_text.utf8().get_data());
```

In `Callable::operator String()` it will try to call `get_script()`.

```cpp
Callable::operator String() const {
if (is_custom()) {
return custom->get_as_text();
} else {
if (is_null()) {
return "null::null";
}

Object *base = get_object();
if (base) {
String class_name = base->get_class();
Ref script = base->get_script();
if (script.is_valid()) {
if (!script->get_global_name().is_empty()) {
class_name += "(" + script->get_global_name() + ")";
} else if (script->get_path().is_resource_file()) {
class_name += "(" + script->get_path().get_file() + ")";
}
}
return class_name + "::" + String(method);
} else {
return "null::" + String(method);
}
}
}
```

For node, it will cause error in log in debug build.

```c++
Variant Node::get_script() const {
ERR_THREAD_GUARD_V(Variant());
return Object::get_script();
}
```

### Steps to reproduce

Block main thread and continue call `call_deferred()` in std thread.

### Minimal reproduction project (MRP)

The code is already showing the problem.

Contributor guide

Open the contributing guide

Research direction

Start with the MessageQueue/CallQueue full error path and Callable::operator String(), then inspect Node::get_script() and its thread guard. Reproduce the issue by blocking the main thread while calling call_deferred() from a std::thread; done means the full-queue error path no longer spams thread-check errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend, game-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.