Swift IPC receivers get a throwing MESSAGE_CHECK
Component: WebKit IPC / UIProcess | e7b60ae
WebKit's multi-process sandboxing model depends on IPC message validation at the boundary between the sandboxed WebContent process and the privileged UI, GPU, and Network processes. The C++ MESSAGE_CHECK macro family logs, optionally crashes, and always exits early when a message field fails an invariant it should not be able to violate, so a compromised renderer cannot smuggle unvalidated data deeper into privileged logic. As WebKit ports IPC receivers like WebBackForwardList to Swift, there is no direct equivalent — Swift has no macros with early-return control flow — so the prior code hand-rolled the pattern as a boolean check followed by a manual return at each call site.
This commit adds Platform/IPC/MessageCheck.swift, a Swift-idiomatic replacement built on throwing functions: messageCheck, dispatchMessage, and markMessageInvalid. WebBackForwardList.swift's UIProcess IPC handlers are converted to try messageCheck { }, and the actual poisoning of the connection — markCurrentlyDispatchedMessageAsInvalid — is deferred to the catch block inside dispatchMessage, where the IPC::Connection is reachable. Connection::takeErrorString and setErrorString are widened from ASCIILiteral to WTF::String to carry Swift-originated error strings, which is why the GPU and Network process takeInvalidMessageStringForTesting call sites change — a mechanical follow-on, not a conversion of those processes to the new Swift pattern.
Significance
The old Swift pattern required the developer to remember an explicit early return after a failed check, whereas the new throw/try version makes that early exit compiler-enforced. That removes a class of "forgot to return" bugs in Swift IPC receivers, and the commit is explicitly the first of several building toward autogenerated message-check shims.
Audit directions
Narrow: diff the old manual-return checks against their converted throw-based equivalents, since a check dropped or reordered during conversion silently reopens the exact class of bug this mechanism exists to close — the match tell is a converted handler with fewer try messageCheck calls than the pre-image had if messageCheck(...) { return } blocks. Also verify that dispatchMessage's onInvalidMessage completion handler always supplies a reply for every message type that expects one, because a missed reply on a failed check hangs a synchronous IPC call. Wider: the one hand-written catch site outside dispatchMessage (backForwardGoToItemShared) needs confirming that it routes to markCurrentlyDispatchedMessageAsInvalid on the right connection — the general shape to hunt is any bespoke catch for InvalidMessage that bypasses the shared dispatch wrapper, since those are the sites where the connection-poisoning step can be forgotten. Widest, as more receivers port to Swift: every language-boundary reimplementation of a security macro deserves the question "does the new form fail closed in every path the old form did?", which applies equally to Rust ?-based ports of C error-code checks and to any macro-to-exception conversion.