Swift IPC handlers return replies and may be async
Component: WebKit IPC | 9fdd260
Source/WebKit/Scripts/webkit/messages.py
Configurations/CommonBase.xcconfig
WebKit은 .messages.in 파일을 입력으로 받아 messages.py로 IPC receiver glue 코드를 생성합니다. Swift receiver의 경우에는 C++에서 호출 가능한 wrapper가 인자를 decode하고, handler를 호출한 뒤 reply를 전송합니다. 다만 @MainActor 멤버는 생성되는 C++ header로 export되지 않습니다. 그래서 wrapper는 nonisolated 상태로 두고, actor 진입은 wrapper가 직접 처리해야 합니다. 한편 Swift 쪽과 C++ 쪽에서 처리되는 메시지 사이의 dispatch 순서도 중요한데, 이 때문에 handler는 첫 suspension 지점까지 inline으로 실행되어야 합니다. Task.immediate는 이를 보장하지만 Task.init은 보장하지 않습니다.
이번 reland에서는 생성되는 Swift handler가 reply를 직접 반환하고, async로 선언될 수도 있도록 변경되었습니다. 동기 wrapper는 MainActor.assumeIsolated로 @MainActor에 진입한 뒤, Task.immediate로 handler를 시작합니다. OS 26 이전 시스템에서는 back-deploy된 startOnMainActor SPI가 대신 사용됩니다. UIProcess의 WebBackForwardList handler들도 이 경로로 옮겨졌고, -Werror RegionIsolation도 함께 활성화되었습니다. 또한 Windows Swift compiler 버그를 우회하기 위해, 인자를 메시지마다 생성되는 Invocation 클래스에 담아 전달하도록 구현되었습니다.
Significance
Swift IPC reply를 누락하거나 두 번 전송하는 실수는 이제 구조적으로 발생할 수 없습니다. 다만 handler가 suspend될 수 있게 되면서, UIProcess IPC의 순서 및 reentrancy에 대한 가정이 달라집니다. WebContent가 제어하는 입력을 받는 실제 UIProcess handler들이 이미 이 경로에서 실행되고 있습니다.
Audit directions
- Suspension을 거치며 stale해지는 상태. 이관된
WebBackForwardListhandler(backForwardGoToItem,backForwardUpdateItem,backForwardItemAtIndexForWebContent등)를 살펴볼 필요가 있습니다. 특히 item, index, page에 대한 가정이await를 거치는 사이 깨질 가능성이 있는지가 점검 대상입니다. 또한 handler가 대기 중인 동안 다른 IPC가 끼어들 수 있는지도 확인해야 합니다. - 구버전 OS에서의 실행 순서. OS 26 이전 fallback은 custom
.swiftinterface를 통해 mangled된 privatestartOnMainActor를 호출합니다. 이 함수가 inline 실행과 priority/actor 상속 측면에서Task.immediate와 동일하게 동작하는지 확인이 필요합니다. 차이가 있다면 OS 버전에 따라 달라지는 ordering 버그로 이어질 가능성이 있습니다. - Suspension 구간의 lifetime.
Invocation클래스는target,connection, decode된 parameter,completionHandler를 retain합니다. Handler 실행 도중 connection이 닫히거나 receiver가 해제되는 경우에도, 이 값들이 유효하게 유지되는지 점검해야 합니다. - 끝내 전송되지 않는 deferred reply. Leak되거나 resume되지 않는 continuation은 동기 sender를 hang 상태로 만들 가능성이 있습니다(
IPCTesterReceiver.pendingDeferredReply참고). Teardown과 cancellation 처리를 확인해야 합니다. 이와 함께 continuation이 교체될 때 이전 continuation이 어떻게 처리되는지도 살펴볼 필요가 있습니다. - Suspension 이후의 invalid message. Async
run()의catch에는markMessageInvalid와completeWithDefaultReply가 함께 호출됩니다. Suspension 이후 throw가 발생한 경우에도, 살아 있는 connection에 default reply가 정확히 한 번만 전송되는지 확인해야 합니다. - Escape hatch. 생성된
WeakRef의@unchecked Sendable와sendingannotation에는 "Safety:" 주석이 근거로 붙어 있습니다. 이 주장이 실제로 성립하는지 검증이 필요합니다. 구체적으로는target이 init에서만 기록되는지, main-thread assertion이 유지되는지, C++이 dispatch로 전달한 값을 재사용하지 않는지가 확인 대상입니다.