https://bugs.kde.org/show_bug.cgi?id=527056
--- Comment #3 from Con Hennessy <[email protected]> --- This is what claude's deeper explanation is (and for my simple world it makes sense). " Here's the mechanics behind the crash, walking through the backtrace: What InterceptNavigationThrottle is for components/navigation_interception is a piece of Chromium's content layer specifically built for embedders (Android WebView, and QtWebEngine) that want veto power over navigations before they commit. QtWebEngine attaches one of these throttles to every main-frame navigation. When the throttle's WillStartRequest() runs, it synchronously calls into QWebEnginePage::acceptNavigationRequest() — that's the only reason your C++ override of acceptNavigationRequest() exists; it's a Qt-level callback invoked from inside Chromium's navigation pipeline, not from some safe, decoupled place. Where the reentrancy happens Look at the ownership chain from the bottom of your trace upward: - NavigationControllerImpl::LoadURLWithParams (#22) starts a new navigation. - Navigator::Navigate (#20) asks the FrameTreeNode for the slot to put it in. - FrameTreeNode::TakeNavigationRequest → ResetNavigationRequestButKeepState (#18-19): this is Chromium's rule that a FrameTreeNode can only have one NavigationRequest in flight at a time. Starting a new one means the old one for that frame is destroyed right here, synchronously. - That destruction cascades: NavigationRequest::~NavigationRequest (#16) → NavigationThrottleRegistryImpl::~NavigationThrottleRegistryImpl (#12) → the throttle vector is torn down → InterceptNavigationThrottle::~InterceptNavigationThrottle (#2-4) → logging::CheckFailure() (#1) → abort. The question is: whose old NavigationRequest is being destroyed? It's the one for the link-click navigation that's still executing. Frame #26, WebEngineFrame::openUrl, is the thing that called load() to start the "new" navigation at #23-25. And WebEngineFrame::openUrl was reached via a plain, direct (non-queued) Qt signal chain — Frame::signalOpenUrlRequest (#30) → FrameManager::openUrl (#27) — that chain originates one level further up (above where your paste cuts off) from ArticleViewerWebEnginePage::acceptNavigationRequest(), i.e. from inside the InterceptNavigationThrottle callback for the very navigation that's about to get destroyed. So the sequence on a single call stack, never returning to the event loop in between, is: 1. Chromium starts navigating to the clicked link's URL. 2. InterceptNavigationThrottle::WillStartRequest() calls acceptNavigationRequest(). 3. Your override emits urlClicked — a direct Qt connection, so the slot runs immediately, same stack. 4. That slot chain (slotLinkClicked → openSafeUrl → signalOpenUrlRequest → FrameManager::openUrl → WebEngineFrame::openUrl → loadUrl) calls QWebEnginePage::load() on the same page/FrameTreeNode, asking Chromium to start a second navigation right now. 5. Chromium's TakeNavigationRequest() enforces "one NavigationRequest per frame" by deleting the current one — but "the current one" is the NavigationRequest whose throttle is still on the call stack, three frames below, waiting for step 2's call to return. 6. InterceptNavigationThrottle's destructor has a CHECK guarding against exactly this — being torn down while it's still mid-callback / hasn't been resumed or cancelled through its own proper lifecycle — and it fires, which under Chromium's DCHECK/CHECK machinery calls ImmediateCrash(). In short: step 2 never got to return false and let Chromium cancel the nav told Chromium to replace it with a new one. You're deleting an object (the throttle/NavigationRequest) out from under a stack frame that belongs to that same object. That's a reentrancy bug, not a logic bug in the URL handling — the decision (open this link in the current tab) was correct, only the timing was wrong. Why Qt::QueuedConnection fixes it By queuing the urlClicked → slotLinkClicked connection, step 3 no longer runs the rest of the chain synchronously. Instead, acceptNavigationRequest() returns false immediately, Chromium's InterceptNavigationThrottle::WillStartRequest() returns control cleanly, the throttle and its NavigationRequest finish being cancelled/destroyed through their normal lifecycle (no CHECK violation, since nothing else is trying to replace it s back to the Qt event loop, and only then does the queued slotLinkClickedrun and call load() — at which point there's no competing in-flight NavigationRequest on that FrameTreeNode to destroy reentrantly. -- You are receiving this mail because: You are watching all bug changes.
