Summary
CefClient.onGotFocus() unconditionally called browser.setFocus(true). CEF's OnSetFocus() callback guards itself against reentrant SetFocus() calls (is_in_onsetfocus_ in CefBrowserContentsDelegate::OnSetFocus()), but OnGotFocus/OnWebContentsFocused has no equivalent guard -- so an already-focused browser recurses onGotFocus() <-> native setFocus(true) synchronously (no async task-post anywhere in the cycle) until the calling thread's stack overflows.
Exact chain:
onGotFocus(browser)
-> browser.setFocus(true)
-> native SetFocus() -> OnSetFocus(FOCUS_SOURCE_SYSTEM)
-> JCEF's onSetFocus handler returns false (no user handler registered)
-> platform_delegate_->SetFocus(true)
-> synchronously re-fires OnWebContentsFocused -> FocusHandler::OnGotFocus (native) -> Java onGotFocus(browser) again
-> recurse
Real-world symptom
Manifests as a bare, repeated Exception in thread "AWT-EventQueue-0" with no visible exception class or stack trace (the default handler's own printStackTrace() re-triggers the same overflow while the stack is still exhausted) -- seen across multiple unrelated investigations this session as an apparently-inexplicable exception storm, and confirmed (via hs_err_pid*.log PID matching) to be the actual cause of #27's "several Exception in thread AWT-EventQueue-0 with no visible stack trace" preceding that issue's mojo DCHECK crash.
Reproduction
Confirmed via live jstack polling of an isolated CefMessageRouterTest run: a clean, 769-frame-deep, two-function cycle (N_SetFocus <-> CefClient.onGotFocus), entirely on the EDT/UI thread.
Not a recent regression -- git log --follow shows onGotFocus()'s body was never functionally touched since it was originally written (only whole-file reformats). Verified via a real build at cf73c06 (the commit that introduced CefNativeAdapter's lock mechanism, mined from a sibling fork) that this reproduces there too, and at that commit crashes the process outright (SIGSEGV, libc.so.6+0x91651) 3/3 runs, worse than current HEAD (survives with the storm, no crash, in isolation).
Fix
java/org/cef/CefClient.java's onGotFocus() now guards with the class's own pre-existing focusedBrowser_ tracking (already set in onGotFocus(), cleared in onTakeFocus(), just never used to prevent the redundant call): only calls browser.setFocus(true) on an actual focus transition (focusedBrowser_ != browser). The one real setFocus(true) call per genuine focus gain still happens; focusHandler_.onGotFocus() (the user-visible notification) still fires on every call, unaffected.
Fixed in commit c1e570a (branch coverage/phase1-value-objects-phase2-handlers). Verified: isolated repro clean (was crashing/storming every run, now 7/8 clean, the one remaining timeout is an unrelated bare-startup hang with zero focus-related output); full-suite Exception in thread count 0/3 (was present in every prior run).
Impact
Was silently corrupting/crashing test runs and (per the CEF focus-notification pattern being entirely stock/default) any real embedding application that lets a JCEF browser receive OS-level focus at all, whenever CEF's OnWebContentsFocused fires for an already-focused browser.
Summary
CefClient.onGotFocus()unconditionally calledbrowser.setFocus(true). CEF'sOnSetFocus()callback guards itself against reentrantSetFocus()calls (is_in_onsetfocus_inCefBrowserContentsDelegate::OnSetFocus()), butOnGotFocus/OnWebContentsFocusedhas no equivalent guard -- so an already-focused browser recursesonGotFocus()<-> nativesetFocus(true)synchronously (no async task-post anywhere in the cycle) until the calling thread's stack overflows.Exact chain:
Real-world symptom
Manifests as a bare, repeated
Exception in thread "AWT-EventQueue-0"with no visible exception class or stack trace (the default handler's ownprintStackTrace()re-triggers the same overflow while the stack is still exhausted) -- seen across multiple unrelated investigations this session as an apparently-inexplicable exception storm, and confirmed (viahs_err_pid*.logPID matching) to be the actual cause of #27's "severalException in thread AWT-EventQueue-0with no visible stack trace" preceding that issue's mojo DCHECK crash.Reproduction
Confirmed via live
jstackpolling of an isolatedCefMessageRouterTestrun: a clean, 769-frame-deep, two-function cycle (N_SetFocus <-> CefClient.onGotFocus), entirely on the EDT/UI thread.Not a recent regression --
git log --followshowsonGotFocus()'s body was never functionally touched since it was originally written (only whole-file reformats). Verified via a real build atcf73c06(the commit that introducedCefNativeAdapter's lock mechanism, mined from a sibling fork) that this reproduces there too, and at that commit crashes the process outright (SIGSEGV,libc.so.6+0x91651) 3/3 runs, worse than current HEAD (survives with the storm, no crash, in isolation).Fix
java/org/cef/CefClient.java'sonGotFocus()now guards with the class's own pre-existingfocusedBrowser_tracking (already set inonGotFocus(), cleared inonTakeFocus(), just never used to prevent the redundant call): only callsbrowser.setFocus(true)on an actual focus transition (focusedBrowser_ != browser). The one realsetFocus(true)call per genuine focus gain still happens;focusHandler_.onGotFocus()(the user-visible notification) still fires on every call, unaffected.Fixed in commit c1e570a (branch
coverage/phase1-value-objects-phase2-handlers). Verified: isolated repro clean (was crashing/storming every run, now 7/8 clean, the one remaining timeout is an unrelated bare-startup hang with zero focus-related output); full-suiteException in threadcount 0/3 (was present in every prior run).Impact
Was silently corrupting/crashing test runs and (per the CEF focus-notification pattern being entirely stock/default) any real embedding application that lets a JCEF browser receive OS-level focus at all, whenever CEF's
OnWebContentsFocusedfires for an already-focused browser.