Debugging Rare Freeze in Godot: Engine Detaches from Process

Godot Version

Godot 4.2.2 - Steam Release

Question I have encountered a recurring issue in my project where the game freezes unexpectedly and sporadically. This freeze does not trigger the debugger, making it difficult to pinpoint the cause, as Godot seems to detach from the running game process. Notably, I cannot pause or interact with the process during these instances, which has really made it difficult to find a cause.

The only clue I have comes from a consistent engine error logged each time:

E 0:07:38:0349   remove: Condition "p_elem->_root != this" is true.
<C++ Source> ./core/templates/self_list.h:80 @ remove()

Despite the rarity of this issue, it has persisted throughout the development process. I have used print statements in various areas I suspected might be related to the freeze, aiming to capture any abnormal behavior right before the freeze occurs. However, this method has yet to yield a breakthrough.

Main Questions

  1. Are there specific methods or tools within Godot that might help identify and resolve such freezes?
  2. Can I access any logs that might provide insights into what happens just before everything stops responding?
  3. Any general advice on tackling unresponsive behaviors in Godot would be highly valuable, especially given my limited experience with the engine.

This is only my second project using Godot, and any guidance or suggestions would be greatly appreciated.

You have any for loop or while in your code?

This freeze does not trigger the debugger, making it difficult to pinpoint the cause, as Godot seems to detach from the running game process.

What debugger are you using? For example, with gdb you can do set follow-fork-mode child .

I was just using the built in Godot Debugger, is that something I can configure through that? I honestly don’t know if that uses gdb, or something else.

Sorry, I was assuming you were using a debugger for Godot itself (C++), not a gdscript debugger.

Have you seen this thread? "Condition 'p_elem->_root!=this' is true." errors when adding nodes from a thread · Issue #8691 · godotengine/godot · GitHub

Maybe related to thread unsafe code.

There are a handful, but none that either aren’t iterating through a fixed sized list, or would be running at the time of the crash. Unless better terrain might be causing something to go wrong.

Hmm, I haven’t intentionally been working on different threads, but would it be best practice to set all my add_child() calls to call_deferred? I could see some of my temporary particle spawning lining up with the issue.

The way I solve issues like this is by putting a breakpoint on whatever source file is generating the p_elem->_root != this error. You’ll need to:

  1. Compile Godot in debug mode
  2. Attach a debugger (some IDEs have debugger integration and do this automatically)
  3. Inspect the resulting stackframes/variables.
  4. Identify the offending object by traversing up the call stack.
1 Like

Gotcha this seems like a plan, I’ll try doing this with CLion, was kinda toying with this idea, but it felt too much like nuclear option. But honestly working from a local build of Godot, would probably be better for just identifying more of these issues. I’ll just work from that for a few days until the bug happens again. Thanks for the help!

CLion will automatically breakpoint when the process e.g segfaults (so possibly you dont need to set a breakpoint to catch the game freezing).

1 Like

Hi, it has been a while, however, I was finally able to recreate the issue, and think something might be off with the Godot physics server.

So what caused the crash most recently was within body_apply_impulse() function within the physics server. Within this, it calls _update_shapes() within the current physics instance.

For reference:

void GodotPhysicsServer2D::_update_shapes() {
	while (pending_shape_update_list.first()) {
		pending_shape_update_list.first()->self()->_shape_changed();
		pending_shape_update_list.remove(pending_shape_update_list.first());
	}
}

So this seems to be looping through each pending shape and calling _shape_changed(). However what I have figured out is that for whatever reason, pending_shape_update_list.first() (and _last for that matter) is null in this call. And so when it gets into the remove function this condition evaluates:

void remove(SelfList<T> *p_elem) {

     ERR_FAIL_COND(p_elem->_root != this);
     // vvv Rest of method below vvv
}

So that throws the error and apparently, it’s stuck doing so forever, if the logs are any indication:

So honestly, I’m a bit unsure of how to continue past here. The impulse being applied is nothing crazy just an impulse of (916, 386) on position (0,0). My program is already applying more impulse 95% of this physics body normal usage (this is a rope that the player swings on, this right here is the impulse applied to the rope when the player first grabs on.) And honestly I’m not even convinced this is super connected to that.

Godot has thrown the same error many times in scenes that have 0 calls of applying forces or impulses. I’m not sure where to go from here. I thought about digging through the _update_shape() method but that ended up being a deep and branching rabbit hole.

Part of me wants to experiment with a null check that ensures remove isn’t called if the method is null, but I don’t know if that would even work, or if there would be wide-reaching implications that I don’t want to mess with.

And honestly, at this point, this bug happens so rarely that I’m honestly scared to make any wild guess at a solution. Since my last post the bug has become significantly rare within my game, I decided to make tonight my “force the bug to happen” night and it took 4 hours of throwing myself at walls and corners or anything that I have come to associate with the crash.

Any tips for moving forward would be greatly appreciated.

Edit/Addendum: Just to add any information, I thought I might be able to attempt recreating the issue by setting the “grab rope” impulse to be the same as it was when the freeze happened. This has provided no help in reliably recreating the freeze, So I can believe I can confidently rule out that the impulse applied was the cause of the crash.