From 547220fee47478666298bba51d75f6e65cb5de9b Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Tue, 26 Jul 2022 12:01:16 -0700 Subject: [PATCH] Avoid sharing mutable attributed string across threads in RCTBaseTextInputShadowView Summary: The `NSMutableAttributedString` was initialized with the same backing store as the cached attributed string on the shadow queue (background thread), but then passed to the main thread and ultimately the JS thread. This explicitly copies the mutable attributed string into an immutable one on the shadow thread before passed off to other threads, which hopefully will address the `convertIdToFollyDynamic` crash that always includes `RCTBaseTextInputShadowView` touching an attributed string on the shadow queue in the trace. Changelog: [iOS][Fixed] - Possible fix for convertIdToFollyDynamic crash in RCTBaseTextInputView and RCTEventDispatcher Reviewed By: sammy-SC Differential Revision: D38133150 fbshipit-source-id: f371da5d17a32c3341287cd3e9730b31a98495f9 --- .../Text/TextInput/RCTBaseTextInputShadowView.m | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m index 19d202cb349443..bc480aa04999ca 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m @@ -144,8 +144,7 @@ - (void)uiManagerWillPerformMounting RCTTextAttributes *textAttributes = [self.textAttributes copy]; - NSMutableAttributedString *attributedText = - [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTextWithBaseTextAttributes:nil]]; + NSMutableAttributedString *attributedText = [[self attributedTextWithBaseTextAttributes:nil] mutableCopy]; // Removing all references to Shadow Views and tags to avoid unnecessary retaining // and problems with comparing the strings. @@ -162,13 +161,13 @@ - (void)uiManagerWillPerformMounting [attributedText insertAttributedString:propertyAttributedText atIndex:0]; } - BOOL isAttributedTextChanged = NO; + NSAttributedString *newAttributedText; if (![_previousAttributedText isEqualToAttributedString:attributedText]) { // We have to follow `set prop` pattern: // If the value has not changed, we must not notify the view about the change, // otherwise we may break local (temporary) state of the text input. - isAttributedTextChanged = YES; - _previousAttributedText = [attributedText copy]; + newAttributedText = [attributedText copy]; + _previousAttributedText = newAttributedText; } NSNumber *tag = self.reactTag; @@ -183,10 +182,10 @@ - (void)uiManagerWillPerformMounting baseTextInputView.reactBorderInsets = borderInsets; baseTextInputView.reactPaddingInsets = paddingInsets; - if (isAttributedTextChanged) { + if (newAttributedText) { // Don't set `attributedText` if length equal to zero, otherwise it would shrink when attributes contain like `lineHeight`. - if (attributedText.length != 0) { - baseTextInputView.attributedText = attributedText; + if (newAttributedText.length != 0) { + baseTextInputView.attributedText = newAttributedText; } else { baseTextInputView.attributedText = nil; }