react-native: (Android) crash on TextInput onKeyPress when inputting an emoji via auto-complete

On 0.53.0 and later, including 0.54.2, if I input an emoji into a TextInput via auto-complete, the app crashes.

I’ve tracked down the root cause; I’ll put more details in a follow-up comment.

Environment

Environment:
  OS: macOS High Sierra 10.13.3
  Node: 9.7.1
  Yarn: 1.5.1
  npm: 5.6.0
  Watchman: 4.9.0
  Xcode: Xcode 9.2 Build version 9C40b
  Android Studio: Not Found

Packages: (wanted => installed)
  react: 16.2.0 => 16.2.0
  react-native: 0.53.3 => 0.53.3

Expected Behavior

No crash!

Actual Behavior

Crash stack:

Error calling RCTEventEmitter.receiveEvent

Failed to create Value from JSON: 
run
    NativeRunnable.java
handleCallback
    Handler.java:790
dispatchMessage
    Handler.java:99
dispatchMessage
    MessageQueueThreadHandler.java:31
loop
    Looper.java:164
run
    MessageQueueThreadImpl.java:194
run
    Thread.java:764

Steps to Reproduce

Fortunately, this repros with the example project from https://github.com/facebook/react-native/issues/18262 .

screenshot_1521183883

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 9
  • Comments: 33 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Are there any updates on this issue? Thanks

Update: Still present in 0.55.3

So the "Failed to create value from JSON: " exception is thrown from: https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.cpp#L74 (i.e., it’s trying to parse JSON from an empty string)

Debugging this code, this is called from: https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.cpp#L98

The conversion to JSON produces the string:

[258,"topKeyPress",{"key":"�"}]

(I’m not 100% sure if the �, which is supposed to be the potato emoji, is messed up because of the JSON conversion messing up or my debugging output.)

It is the String(ctx, json.c_str()) conversion that is failing and returning an empty string. This leads to the line https://github.com/facebook/react-native/blob/0ee502d1254b828efb119cc06bcd213c3d843269/ReactCommon/jschelpers/Value.h#L32

so it looks like JSC_JSStringCreateWithUTF8CString is having problems with the emoji character.

@joshyhargreaves correction - it does appear to be auto-complete related here too - the original reproduction I was given was when typing something like @mention hiya😀, and seemingly hiya😀 or just 😀 wasn’t enough to trigger it. I’ve noticed that a hiya😀 will trigger the bug and it’s to do with autocomplete turning that into a Hiya😀 (or @mention Hiya😀 for the previous example). Not really sure why it’s trying to auto-complete to the capitalised version of the word without it being the start of a sentence but it looks like there’s a company called Hiya so maybe that’s ended up in Google’s dictionary. With typing hiya😀 the output is actually Hiya😀 due to text input sentence auto-capitalisation so the auto-complete isn’t triggered in that case, hence no crash.

This was definitely winning weird unexplained bug of the month before I found this issue report, so thanks @akalin-keybase 👍

@kevinkevw, stupid question, but are you building react native from source for Android?

@nickofthyme yes you are correct.

I haven’t had any time to fix the route cause of the issues, the logic behind this is the route cause of the issue: https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditTextInputConnectionWrapper.java#L102. When the cursor moves forward, the character behind the cursor is taken, as it deemed to be the character that has been pressed. I believe that TextInput#getText returns an Editable. I will have to investigate as I am unfamiliar with unicode support in Java, but on first impressions I do know that the unicode spec does support the combination of different unicode/emoji symbols to encode other emojis.

@joshyhargreaves @akalin-keybase I think we’ve hit this issue here although not with autocomplete, seems just using the emoji keyboard does the trick and causes a crash with the Failed to create Value from JSON error.

Can only replicate if the app is running on-device, and only so far with the stock android keyboard. Swiftkey and Samsung keyboard seem to be immune, as does any keyboard if the app is running in the Chrome devtools debugger.

@akalin-keybase @hramos I opened a PR to disable the onKeyPress logic, any thoughts and comments on that would be great 💯.

I’m also going to have a look into the onKeyPress logic, it looks like the logic itself doesn’t work particularly well with unicode characters as it assumes key’s pressed can only have a width of 1. The potato emoji, as per the character string is encoded in java as ‘\uD83E\uDD54’ which results in two characters in the text input, and the key emitted will be the second of those two (\uDD54). There may be something wrong with the value conversion itself, but it’s never been an issue for the onChangeText callback.