X Tutup
Skip to content

Fix potential DAP crash at startup#114196

Merged
akien-mga merged 1 commit intogodotengine:masterfrom
migueldeicaza:debugger-crash-fix
Dec 21, 2025
Merged

Fix potential DAP crash at startup#114196
akien-mga merged 1 commit intogodotengine:masterfrom
migueldeicaza:debugger-crash-fix

Conversation

@migueldeicaza
Copy link
Contributor

This also appeared on our crash telemetry, I have not been able to reproduce, but I suspect it is a timing issue when the client has gone away before the server connects.

@migueldeicaza migueldeicaza requested a review from a team as a code owner December 19, 2025 13:28
@AThousandShips AThousandShips changed the title Fixes debugger crash at startup. Fixe debugger crash at startup Dec 19, 2025
@AThousandShips AThousandShips added this to the 4.6 milestone Dec 19, 2025
@AThousandShips
Copy link
Member

Being able to reproduce the bug and confirming this fixes things would be really important here, the check being added wont be an issue if it isn't needed but we should confirm it actually fixes something

@migueldeicaza
Copy link
Contributor Author

This is the stack trace, but regardless of it, the code is clearly broken:

          Crashed: Godot Main Thread [instance #1]
0  Xogot                          0x7c69234 StreamPeerTCP::set_no_delay(bool) + 179 (ref_counted.h:179)
1  Xogot                          0x39bc040 DebugAdapterProtocol::on_client_connected() + 154 (debug_adapter_protocol.cpp:154)
2  Xogot                          0x39bc040 DebugAdapterProtocol::on_client_connected() + 154 (debug_adapter_protocol.cpp:154)
3  Xogot                          0x39d4e08 DebugAdapterProtocol::poll() + 270 (list.h:270)
4  Xogot                          0x39ed66c DebugAdapterServer::_notification(int) + 63 (debug_adapter_server.cpp:63)
5  Xogot                          0x81e22b8 Object::notification(int, bool) + 917 (object.cpp:917)
6  Xogot                          0x50920c4 SceneTree::_process_group(SceneTree::ProcessGroup*, bool) + 1065 (scene_tree.cpp:1065)
7  Xogot                          0x508fb4c SceneTree::_process(bool) + 1138 (scene_tree.cpp:1138)
8  Xogot                          0x50905f8 SceneTree::process(double) + 586 (scene_tree.cpp:586)
9  Xogot                          0x132175c Main::iteration() + 4590 (main.cpp:4590)
10 Xogot                          0x12c0cc8 MethodBindTR<bool>::ptrcall(Object*, void const**, void*) const + 107 (method_ptrcall.h:107)
11 Xogot                          0x8181cbc gdextension_object_method_bind_ptrcall(void const*, void*, void const* const*, void*) + 1423 (gdextension_interface.cpp:1423)
12 SwiftGodot                     0x30c0a4 __swift_memcpy48_4 + 2215400
13 Xogot                          0x28f8e8 closure #1 in GodotApp.iterate() + 855 (GodotAppView.swift:855)
14 Xogot                          0x6bfb4 GodotInstance.async(callback:) + 4339646388
15 SwiftGodot                     0x3d80c __swift_memcpy49_8 + 21492
16 Xogot                          0x8184eb4 CallableCustomExtension::call(Variant const**, int, Variant&, Callable::CallError&) const + 174 (gdextension_interface.cpp:174)
17 Xogot                          0x81b59cc std::__1::__function::__func<GodotInstance::execute(Callable, bool)::$_0, std::__1::allocator<GodotInstance::execute(Callable, bool)::$_0>, void ()>::operator()() + 890 (variant.h:890)
18 Xogot                          0x81b30c0 TaskExecutor::invokeCallback(void*) + 395 (function.h:395)
19 Xogot                          0x81b4090 GodotInstance::execute(Callable, bool) + 4475207824 (function.h:4475207824)
20 Xogot                          0x81b5538 MethodBindT<Callable, bool>::ptrcall(Object*, void const**, void*) const + 336 (binder_common.h:336)
21 Xogot                          0x8181cbc gdextension_object_method_bind_ptrcall(void const*, void*, void const* const*, void*) + 1423 (gdextension_interface.cpp:1423)
22 SwiftGodot                     0x30c30c __swift_memcpy48_4 + 2216016
23 Xogot                          0x28f7c0 GodotApp.iterate() + 426 (SwiftGodotKit.swift:426)
24 Xogot                          0x28fb10 @objc GodotApp.iterate() + 4341889808 (<compiler-generated>:4341889808)
25 QuartzCore                     0xeb9cc CA::Display::DisplayLinkItem::dispatch_(CA::SignPost::Interval<(CA::SignPost::CAEventCode)835322056>&) + 48
26 QuartzCore                     0xeb3a0 CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 884
27 QuartzCore                     0xeaf38 CA::Display::DisplayLink::dispatch_deferred_display_links(unsigned int) + 352
28 UIKitCore                      0x9c710 _UIUpdateSequenceRun + 84
29 UIKitCore                      0x9f040 schedulerStepScheduledMainSection + 172
30 UIKitCore                      0x9cc5c runloopSourceCallback + 92
31 CoreFoundation                 0x73f4c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
32 CoreFoundation                 0x73ee0 __CFRunLoopDoSource0 + 176
33 CoreFoundation                 0x76b40 __CFRunLoopDoSources0 + 244
34 CoreFoundation                 0x75d3c __CFRunLoopRun + 840
35 CoreFoundation                 0xc8284 CFRunLoopRunSpecific + 588
36 GraphicsServices               0x14c0 GSEventRunModal + 164
37 UIKitCore                      0x3ee674 -[UIApplication _run] + 816
38 UIKitCore                      0x14e88 UIApplicationMain + 340
39 SwiftUI                        0x291ef8 closure #1 in KitRendererCommon(_:) + 168
40 SwiftUI                        0x291e28 runApp<A>(_:) + 100
41 SwiftUI                        0x291d0c static App.main() + 180
42 Xogot                          0x2684b4 main + 4341728436 (XogotApp.swift:4341728436)
43 ???                            0x1c6be9de8 (Missing)

@migueldeicaza
Copy link
Contributor Author

In any case, I already applied this change to our trees, I am just sharing in an attempt to improve the stability of Godot for all users. We are fortunate enough to have telemetry data that tracks crashes in the wild in difficult conditions which Godot is not getting, a small way of contributing - but I do not have the cycles to put together much more than this - I leave it up to the Godot maintainers to decide whether they want these changes.

@AThousandShips
Copy link
Member

AThousandShips commented Dec 19, 2025

That crash log should be sufficient, thank you

You're not obligated to put in any more work than you are willing, but I'm pointing out the bug fixing and triage process, to ensure work that goes into the engine is doing something useful, especially to ensure it actually fixes some issue someone has rather than the issue actually being elsewhere, it's important not to play "whack a bug" with the codebase but to be able to make informed decisions on what to merge (it's especially important to know if something actually fixes anything or if it just masks a bug elsewhere)

@migueldeicaza migueldeicaza changed the title Fixe debugger crash at startup Fixes debugger crash at startup Dec 19, 2025
@AThousandShips AThousandShips changed the title Fixes debugger crash at startup Fix debugger crash at startup Dec 19, 2025
@akien-mga akien-mga requested a review from rsubtil December 19, 2025 14:59
@akien-mga akien-mga changed the title Fix debugger crash at startup Fix potential DAP crash at startup Dec 19, 2025
Crash seen in the wild on Xogot with telemetry.
@akien-mga
Copy link
Member

akien-mga commented Dec 19, 2025

Amended the commit message to follow our guidelines.

Copy link
Member

@akien-mga akien-mga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems consistent with how e.g. EditorFileSystem validates its connection, so that seems fine. There are more places in the codebase where take_connection() calls aren't always validated (notably in thirdparty/enet/enet_godot.cpp) but they're outside the scope of this PR.

Copy link
Member

@AThousandShips AThousandShips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stack trace confirms the Ref being null being the cause of the issue and it is performed elsewhere so indicates that the null state of the ref is not unexpected so would seem to be the correct fix, if later analysis indicates something else is wrong and should be fixed elsewhere this won't prevent that and we still have something indicating that state

Thanks!

@rsubtil
Copy link
Member

rsubtil commented Dec 19, 2025

I agree, if take_connection can fail even if is_connection_available is true, then an error check should be added:

Ref<T> _take_connection() {
Ref<T> conn;
if (!is_connection_available()) {
return conn;
}
Ref<NetSocket> ns;
NetSocket::Address addr;
ns = _sock->accept(addr);
if (ns.is_null()) {
return conn;
}
conn.instantiate();
conn->accept_socket(ns, addr);
return conn;

Still, I agree with @AThousandShips that it would be better to get to the root of this problem if possible. I'm curious if you have a scenario with multiple connections to the DAP server. This code was copied back then from LSP at the time, but I can't think of any scenario where multiple connections is useful in DAP, and I'm pretty sure the implementation is not tackling it correctly either, so I'm curious if this the case here.

If you want to, and since you can't reproduce this bug locally, we can instead have a chat on Rocket.chat if you feel this should be analyzed further.

@AThousandShips
Copy link
Member

I'd suggest asking the person who reported this to @migueldeicaza to open an issue here on GitHub to look into this if they can, but getting the details would help narrowing it down, but it shouldn't crash in this case but agreed it might be an issue elsewhere that could benefit other areas if fixed

@migueldeicaza
Copy link
Contributor Author

Many of our crashes are only experienced by users in the wild, and we get anonymized crashes from Apple/Google which only contain the crash information, and then we stare at the stack traces and try to prevent another user from hitting the same issue.

If I had to estimate, we probably get some 100 crashes like this for every case where a user reaches out to us to complain. For a mix of reasons, people do not bother, people do not think it will get fixed, people do not know what happened, people fault something else, people do not know how to reach out, people are not familiar with processes.

50 is probably generous, it could be 100.

On our end, we monitor those crashes constantly and while some users might have had a bad experience, it helps future users not run into the same issue.

I personally think that Godot should distribute an instrumented version of the engine to improve the stability of the engine.

@AThousandShips
Copy link
Member

I personally think that Godot should distribute an instrumented version of the engine to improve the stability of the engine.

If by instrumented you mean with debug symbols you have godotengine/godot-proposals#1342

If instead meaning gathering data on crashes etc. that's very complicated and messy with data collection laws etc.

@migueldeicaza
Copy link
Contributor Author

I mean the latter, when you detect a crash, you upload the data to a site that aggregates it.

You could make it an opt-in feature, you ask at startup "Do you want to assist developers in improving Godot?" and then if they say yes, you activate the crash reporter, otherwise you do not.

We are using Crashlytics from Google, and we also get data from Apple. But there is a fabulous new stack that I am tempted to use from Bitdrift - which also solves other problems.

@AThousandShips
Copy link
Member

AThousandShips commented Dec 19, 2025

I'd suggest opening a proposal, but there's a lot of practical aspects, including how much larger the target audience for Godot is compared with individual projects using Godot, making our handling of the data problematic from a practical perspective (beyond just the legal aspects, and the reasonable aversion of a lot of people to different software collecting data), related concepts and proposals have been discussed in the past and as I recall there was a relatively large push back to the collection of data (then we have the potential issues of forks of the engine pushing telemetry to our data servers causing issues etc.), and we might not get a lot of data for the same reasons of aversion (I wouldn't enable the feature myself for example)

@syntaxerror247
Copy link
Member

I mean the latter, when you detect a crash, you upload the data to a site that aggregates it.

Well we already have a system like this in place ;)
We have the Editor on the Play Store and this means we do receive ANR and crash reports. While many of these issues are specific to certain Android devices, but addressing them benefits everyone.

@akien-mga akien-mga merged commit 1125e34 into godotengine:master Dec 21, 2025
20 checks passed
@akien-mga
Copy link
Member

Thanks!

@migueldeicaza
Copy link
Contributor Author

@syntaxerror247 godot should publish that data, it would help prioritize bugs that are affecting the engine stability.

@syntaxerror247
Copy link
Member

@syntaxerror247 godot should publish that data, it would help prioritize bugs that are affecting the engine stability.

Yeah, having more eyes on those crashes may help, the android team once thought about creating github issues for some frequent crashes but never got to this, but IMO that doesn't really make sense since reports won't have reproduction steps (which are very important) and most crashes are only on low-powered devices. There's already some issues opened with crash details from play console but those are still unresolved as we don't really know the root cause. That said, the team is keeping an eye on them and is creating PRs where possible.

@migueldeicaza
Copy link
Contributor Author

I find myself on the same spot, initially not knowing what triggers the crash or the steps, but sorting this out is not too hard.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

X Tutup