Keep RenderWidgetHostViewCocoa alive during nested loops started by TextInputClientMac
Moderate
Commit Hash:
22a00be2e3f7992797da13725942103b0a78efc7
Commit Time: 2026-03-19 00:08:33
Impact Level: Moderate
Generated By: webview2-upstream-sentry
Upstream Review:
View Upstream Review 🔗
📋 Summary
This commit fixes a crash where TextInputClientMac's synchronous IPC calls (SyncGetCharacterIndexAtPoint and SyncGetFirstRectForRange) could enter nested RunLoops that cause RenderWidgetHostViewCocoa to be prematurely deallocated. Key changes include:
1. Added NS_VALID_UNTIL_END_OF_SCOPE protection for self in RenderWidgetHostViewCocoa's characterIndexForPoint: method before calling SyncGetCharacterIndexAtPoint, ensuring self is not released during the nested RunLoop.
2. Added the same protection in firstRectForCharacterRange:actualRange: before calling SyncGetFirstRectForRange.
3. In RenderWidgetHostViewMac::SyncGetFirstRectForRange, cached the GetDeviceScaleFactor() return value before entering the potentially nested GetFirstRectForRange call, avoiding failure when the ScreenInfos list is cleared during the nested RunLoop.
1. Added NS_VALID_UNTIL_END_OF_SCOPE protection for self in RenderWidgetHostViewCocoa's characterIndexForPoint: method before calling SyncGetCharacterIndexAtPoint, ensuring self is not released during the nested RunLoop.
2. Added the same protection in firstRectForCharacterRange:actualRange: before calling SyncGetFirstRectForRange.
3. In RenderWidgetHostViewMac::SyncGetFirstRectForRange, cached the GetDeviceScaleFactor() return value before entering the potentially nested GetFirstRectForRange call, avoiding failure when the ScreenInfos list is cleared during the nested RunLoop.
🎯 Impact Analysis
This change has a moderate impact on WebView2Mac and warrants attention. Key analysis:
1. **Directly affects WebView2Mac's IME interaction path**: The modified characterIndexForPoint: and firstRectForCharacterRange:actualRange: are core NSTextInputClient protocol methods called by macOS's input method framework to obtain cursor positions and character indices. WebView2Mac's embedded WebView uses the same RenderWidgetHostViewCocoa for IME interactions, and these methods are frequently called during CJK input method scenarios.
2. **Fixes a potential use-after-free crash**: SyncGetCharacterIndexAtPoint and SyncGetFirstRectForRange are synchronous mojo calls that may enter nested RunLoops while waiting for renderer process responses. During this period, external events (such as window closing or navigation) could cause RenderWidgetHostViewCocoa to be deallocated. NS_VALID_UNTIL_END_OF_SCOPE ensures self is kept alive by holding a strong reference until the method returns. WebView2Mac has the same risk, especially when the host app rapidly switches or closes WebViews.
3. **Edge repo already has partial similar pattern**: Edge's RenderWidgetHostViewCocoa already has the NS_VALID_UNTIL_END_OF_SCOPE keepSelfAlive pattern in its keyDown handling path (around line 1365), but characterIndexForPoint: and firstRectForCharacterRange: methods do not yet have this protection, carrying the same crash risk as upstream.
4. **Browser-side device_scale_factor caching**: The fix to cache GetDeviceScaleFactor() in RenderWidgetHostViewMac is also relevant to WebView2Mac. WebView2Mac's browser process uses RenderWidgetHostViewMac to manage render views, and if ScreenInfos is cleared during the nested RunLoop in GetFirstRectForRange, scale calculations would similarly fail.
1. **Directly affects WebView2Mac's IME interaction path**: The modified characterIndexForPoint: and firstRectForCharacterRange:actualRange: are core NSTextInputClient protocol methods called by macOS's input method framework to obtain cursor positions and character indices. WebView2Mac's embedded WebView uses the same RenderWidgetHostViewCocoa for IME interactions, and these methods are frequently called during CJK input method scenarios.
2. **Fixes a potential use-after-free crash**: SyncGetCharacterIndexAtPoint and SyncGetFirstRectForRange are synchronous mojo calls that may enter nested RunLoops while waiting for renderer process responses. During this period, external events (such as window closing or navigation) could cause RenderWidgetHostViewCocoa to be deallocated. NS_VALID_UNTIL_END_OF_SCOPE ensures self is kept alive by holding a strong reference until the method returns. WebView2Mac has the same risk, especially when the host app rapidly switches or closes WebViews.
3. **Edge repo already has partial similar pattern**: Edge's RenderWidgetHostViewCocoa already has the NS_VALID_UNTIL_END_OF_SCOPE keepSelfAlive pattern in its keyDown handling path (around line 1365), but characterIndexForPoint: and firstRectForCharacterRange: methods do not yet have this protection, carrying the same crash risk as upstream.
4. **Browser-side device_scale_factor caching**: The fix to cache GetDeviceScaleFactor() in RenderWidgetHostViewMac is also relevant to WebView2Mac. WebView2Mac's browser process uses RenderWidgetHostViewMac to manage render views, and if ScreenInfos is cleared during the nested RunLoop in GetFirstRectForRange, scale calculations would similarly fail.
Impacted Classes:
content::RenderWidgetHostViewCocoa
content::RenderWidgetHostViewMac
content::TextInputClientMac