Skip to content

Fix crash on Cmd-G in the HTML output window - #44

Merged
dayglojesus merged 1 commit into
mainfrom
fix/html-output-find-crash
Aug 24, 2026
Merged

Fix crash on Cmd-G in the HTML output window#44
dayglojesus merged 1 commit into
mainfrom
fix/html-output-find-crash

Conversation

@dayglojesus

@dayglojesus dayglojesus commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Cmd-G / Cmd-Shift-G in the HTML output window killed TextMate:

Exception:  EXC_BAD_ACCESS (SIGSEGV)
Subtype:    KERN_INVALID_ADDRESS at 0x0000000000000010
Triggered:  Thread 0, com.apple.main-thread

0  WebKit  CallableWrapper<-[WKWebView findString:withConfiguration:completionHandler:]::$_28, void, bool>::call(bool) + 56
1  WebKit  ...makeAsyncReplyCompletionHandler<Messages::WebPage::FindString, WebPageProxy::findString(...)>...
2  WebKit  AuxiliaryProcessProxy::sendMessage(...)
3  WebKit  IPC::Connection::dispatchMessage(...)
...
21 TextMate  main + 756

No TextMate frames below main — the fault lands on the async IPC reply from the WebContent process, long after the call site returned, which is why the stack alone doesn't name the culprit.

Cause

-findNext: and -findPrevious: passed completionHandler:nil:

[self findString:entry.string withConfiguration:config completionHandler:nil];

SDK WKWebView.h:510 declares configuration as nullable and the handler not, inside NS_ASSUME_NONNULL_BEGIN/END (lines 34/768), so the handler is implicitly nonnull. WebKit invokes it without a null check, and 0x10 is the invoke slot of a nil Block_layout (isa 8 + flags 4 + reserved 4). Passing nil is a caller-side contract violation; there is nothing to fix in WebKit.

The OakNotEmptyString guard above each call is what made this delayed rather than immediate — a non-empty string takes the async path. An empty one would fault synchronously, because the !string.length early return invokes the handler just as unguarded.

-performFindOperation: already passed a real block, so the find dialog was never affected. Only the two keyboard shortcuts.

Both v2.1.4-undead (the build that crashed) and v2.1.5-undead contain these two lines.

The compiler was already saying so

Building the unfixed code emits, at exactly the two call sites:

WebView Additions.mm:80:76: warning: null passed to a callee that requires a non-null argument [-Wnonnull]
WebView Additions.mm:93:76: warning: null passed to a callee that requires a non-null argument [-Wnonnull]

Verification

A minimal WKWebView harness, rather than inspection:

completion handler result
nil exit 139 (SIGSEGV)
^(WKFindResult*){ } exit 0

Under lldb the nil case gives EXC_BAD_ACCESS (code=1, address=0x10) in CallableWrapper<-[WKWebView findString:withConfiguration:completionHandler:]::$_24, void, bool>::call(bool) + 56, above makeAsyncReplyCompletionHandler, AuxiliaryProcessProxy::sendMessage and IPC::Connection::dispatchMessage — matching the reported crash frame for frame. The lambda ordinal differs ($_24 vs $_28) only because the test ran on macOS 26.5 against a 26.3 dump.

Clean build of the tree; full CTest run unchanged.

Why an empty block

It restores what these two actions did under WebKit1, where -searchFor:direction:caseSensitive:wrap: returned a BOOL that findNext: also discarded. Reporting the result the way performFindOperation: does — so a failed Cmd-G beeps instead of doing nothing visible — is a real improvement but a separate question, deliberately kept out of a crash fix.

Follow-ups, not in this PR

  • Make -Wnonnull fatal. It found this bug for free, and after this change exactly one site in the tree stands in the way. That is more durable protection than a test, which would need GUI infrastructure this repo doesn't have.
  • Frameworks/text/src/types.h:119 is that site, and it's a latent bug rather than noise: range_t(0) has no matching pos_t constructor, so it resolves to range_t(std::string const&) and constructs std::string from a null pointer, which is undefined behaviour. Currently unreachable — selection_t(std::string const&)'s do-while always pushes one range, so empty() is never true there. It should almost certainly be range_t().

Cmd-G and Cmd-Shift-G in the HTML output window killed TextMate with
EXC_BAD_ACCESS at address 0x10, on the main thread, with no TextMate frames
below main: the fault lands on the async IPC reply from the WebContent
process, long after the call site returned.

-findNext: and -findPrevious: passed completionHandler:nil to
-[WKWebView findString:withConfiguration:completionHandler:]. That parameter
is implicitly nonnull — WKWebView.h:510 declares `configuration` as nullable
and the handler not, inside NS_ASSUME_NONNULL_BEGIN/END — and WebKit invokes
it without a null check, so 0x10 is the invoke slot of a nil Block_layout.
Passing nil is a caller-side contract violation; there is nothing to fix in
WebKit.

The OakNotEmptyString guard above each call is what made the crash delayed
rather than immediate. A non-empty string takes the async path; an empty one
would fault synchronously, because the !string.length early return invokes the
handler just as unguarded.

-performFindOperation: already passed a real block, so the find dialog was
never affected. Only the two keyboard shortcuts.

An empty block restores the behaviour these two actions had under WebKit1,
where -searchFor:direction:caseSensitive:wrap: returned a BOOL that findNext:
also discarded. Reporting the result the way performFindOperation: does — so
that a failed Cmd-G beeps — is a separate question, deliberately left out of a
crash fix.

Verified with a minimal WKWebView harness rather than by inspection: calling
findString: with a nil handler exits 139 on SIGSEGV, and with an empty block
exits 0. Under lldb the nil case faults in
CallableWrapper<-[WKWebView findString:withConfiguration:completionHandler:]
::$_24, void, bool>::call(bool) + 56, above makeAsyncReplyCompletionHandler,
AuxiliaryProcessProxy::sendMessage and IPC::Connection::dispatchMessage —
matching the reported crash frame for frame.

Claude-Session: https://claude.ai/code/session_01Gi3HR9ioH4wfrn4BWvJUDA
@dayglojesus
dayglojesus merged commit eb8a527 into main Aug 24, 2026
2 checks passed
@dayglojesus
dayglojesus deleted the fix/html-output-find-crash branch August 24, 2026 03:40
This was referenced Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant