-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
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
Deferred call of GDScript lambda from thread leads to double free or corruption when hot reloading #84046
Comments
I can confirm the bug. It doesn't happen all the time, but when it does it reports For me, the crash only happen when running the project from the editor, i.e. with the debugging server enabled. That makes it a bit difficult to debug with gdb, but I managed to get a stacktrace by enabling "Keep Debug Server Open" in the editor, and then running the project with gdb on the command line using
CC @godotengine/gdscript |
Given that's lambda related, I had a suspicion that #81628 may have caused this. I tried a local revert and that solves the crash, so it's indeed a regression from #81628. CC @rune-scape |
This isn't related to emitting signals though, and only to using This crashes the same way: extends Node
func _ready():
WorkerThreadPool.add_task(T_test_func)
func T_test_func():
(func(): print("hi")).call_deferred() # This crashes the game. Same with: extends Node
func _ready():
WorkerThreadPool.add_task(T_test_func)
func T_test_func():
var lambda = func(): print("hi")
lambda.call_deferred() # This crashes the game. |
Does emiting a signal involve lamdas in any other way? Otherwise it's possible that there are two issues here. The first with calling a deferred lambda, the second with emiting a signal from a thread. As far as I see with the given example, connected functions are not called when a signal is emitted from a thread. I would have assumed they are called in the context of the thread. |
That's a separate issue from the crash, and not a regression in 4.2, as it behaves the same in 4.1. Your line:
raises an error in 4.1 and 4.2 which explains that you can't emit signals from threads:
AFAIK it's not thread safe, and as part of the work done in 4.1 on scene tree multithreading, it had to be restricted. But it's indeed not related to the crash I described above which comes from deferring a lambda call in a thread. |
Thanks for the clarification, I must have missed that error message. I actually prefer the limitation of needing to defer emiting signals from a thread. That way the callee knows that it will always be running in the main thread. Is there a type-safe way to defer emiting a signal from a thread without using a lambda? Lacking emit_deferred I thought the lambda method was the canonical way of doing so, but given that the unit tests didn't catch this indicates to me that it is not? |
In theory the type safe way to do this should be So I don't think there's a type safe / string-less way to emit this currently, you'd have to do Or indeed the lambda solution makes sense, if it didn't crash. |
Weird. I cannot reproduce this issue on the latest master build (v4.2.beta.custom_build [3e7f638]). I'm I doing something wrong? Capture.video.du.2023-11-07.15-20-37.webm |
Just discussed with @allenwp, he says that the issue seems to be intermittent with beta 5. Sometimes, it works, other times, it crashes or it errors out (trying to write into invalid memory). We are investigating. He is on Windows 10. |
Here's an example of the crash with v4.2.beta5.official [4c96e96] Sometimes I get no error dialog, but the app just closes: And other times, it works fine without any issue: To get these different results, I just hit F5 to start the game, then try again and again. Edit: Here's a call stack:
And some Autos/Locals from the VS debugger:
Edit 2:
Edit 3: This one was captured by running the code from a
|
Because the error is intermittent, I've been using this code to test fixes for this issue, which allows for a few thousand tests to be quickly done: extends Node
signal test_signal
static var state: int = 0
func _process(_delta: float) -> void:
if state == 0:
test_signal.connect(test_done)
WorkerThreadPool.add_task(T_test_func)
elif state == 1:
test_signal.disconnect(test_done)
state = 0
func T_test_func():
print("Test processing called.")
#test_done.call_deferred() # This works.
#test_signal.emit() # This doesn't crash but test_done is not called.
(func(): test_signal.emit()).call_deferred() # This crashes the game.
func test_done():
print("Test done.")
state = 1 |
Godot version
v4.2.beta3.official [e8d57af]
System information
Godot v4.2.beta3 - Windows 10.0.19045 - Vulkan (Mobile) - dedicated NVIDIA RTX A2000 Laptop GPU (NVIDIA; 31.0.15.2737) - 11th Gen Intel(R) Core(TM) i7-11850H @ 2.50GHz (16 Threads)
Issue description
In Godot 4.1 I regularly use
call_deferred
to send data from a WorkerThreadPool thread back to the main thread. Usually this involves a direct function call, but occasionally I emit a deferred signal by wrapping the emit call into a lambda:In Godot 4.2, this crashes the game.
Simply emitting the signal (without deferring it) does not immediately crash the game, but does not call the connected signals either.
Steps to reproduce
Simply create a node with the following script and attempt to run it.
Minimal reproduction project
Reproduction is trivial without a dedicated project.
The text was updated successfully, but these errors were encountered: