-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
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
Crash without feedback when attempting to remove a freed child. #77053
Comments
It's not exactly straightforward to detect and warn about this issue though I suspect |
It doesn't happen with $path because it has separate lookup and doesn't expect the reference to be valid There's an overhead to consider when enforcing checks to if the reference is valid, the difference between just using a pointer expected to be valid, or doing a lookup for an id and checking, which more importantly also does thread safety which means a bottleneck and a slowdown |
If you need to be sure an instance is valid use |
i proposing a solution following the logic of the issue, In the following script, we add a check before removing the child to see if it's still in the scene tree using is_inside_tree(). If the node is not in the tree, we print a message and do not attempt to remove it. This way, you can avoid crashes even if you try to remove a freed node. var node2 func _ready():
func remove_node_after_delay(node):
please verify it then provide me with a feedback to check if its a viable solution or not. |
See also #61906, which should improve the existing situation for any kind of engine crash. |
@KhalilBenGaied this is not valid 4.0 code, and won't solve the issue on non-debug builds, see above for the way to detect freed objects
This won't detect if the node has been freed, and should crash on non-debug builds |
The way to deal with this safely comes in as I can see it three ways:
The issue here, as is the appropriate way to approach things especially in non-debug builds, is that we assume that references are valid when passed to functions, as there is an overhead to checking this, and just assuming the user is knowing what they are doing and not passing invalid references (there is a lot of checks that the references aren't null, but if they aren't null they are assumed to be valid). This is the normal way of doing things (c++ does it for one) as you'd otherwise do these checks all the time and it'd cost you a lot of performance when in most cases you don't need it Now we could add checking for variant validity when passing references as arguments in GDScript, it's quite easy to do, but I think it'd add quite a bit of performance loss, as each passed |
But to summarise, other than making crashing more informative, this isn't a bug, this is an issue of insufficient user checking and variable management |
I'm having a similar issue where remove_child(), queue_free() or even .visible = false, inside a thread on a valid object is crashing intermittently without any debug/verbose/logs. It crashes about 1 in every few times. Sometimes taking upwards of 10 calls which is no fun. Since we can't seem to debug threaded operations, I can't figure out what's causing it. Scenario: I create and add a simple child scene (busyBackground) (has a label and simple AnimationPlayer) before starting the thread and at the end of the thread, I try to remove the busyBackground and it crashes (sometimes). I tried to get a reduced repro but I'm not able to repro outside of my main project. I added is_instance_valid() check to make sure the child I'm removing is valid and it is. I tried moving the instantiation of the busyBackground into the thread and no change. I tried emitting a global signal to call the ClearBusyBackground() and it's not working at all. The signal seems to be ignored from the thread. Not clear to me how that should work. I tried changing from a global signal to a local signal and I'm back to crashing (so local signals work from threads while global signals don't?).
|
You are adding and removing nodes from a thread, try using deferred calls instead |
@AThousandShips I gave that a try. Didn't seem to change anything. I added call_deferred to a bunch of things in and around that problem space and nothing changed. Continued to crash. |
@AThousandShips Actually, I have to take that back. One of my looping runs completed so digging into it some more. |
So, this is fun. Removing either of these lines prevents the crash.
Moving the str().replace to it's own line and not using it prevents the crash
Still crash with the replace removed.
It appears to crash when we attempt to use/assign the output array to the lineEdit field. Adding a call_deferred here fixes the problem. I had tried looping through the output and building up groomedOutput manually but it still crashed.
I have the workaround I need so I'll be moving on. Thanks @AThousandShips for the suggestion. |
Godot version
v4.0.2.stable.official [7a0977c]
System information
Manjaro Linux KDE
Plasma Version: 5.27.4 KDE
Frameworks Version: 5.105.0
Qt Version: 5.15.9
Kernel Version: 5.15.109-1-MANJARO (64-bit)
Issue description
If a variable pointing to a previously freed object is used as the argument of .remove_child the game crashes without any feedback. Obviously it is an error to remove a freed node, but there should be feedback so that the user can fix their mistake.
Interestingly the game does not crash if the node is refered to using its $ path. That is, in the following snippet (included in the minimal reproduction project):
the first remove_child causes no problems, but the second one makes the game crash even before "Removing second child" is printed.
Steps to reproduce
Minimal reproduction project
Waits are introduced between each action so that the bug is easier to observe, and so that it is clear that the actions do not have to happen in the same frame.
Godot.zip
The text was updated successfully, but these errors were encountered: