A C ++ JNI call to NewStringUTF crashes an Android application when using many different emoji types and languages ​​(outside of ascii, but still valid modified utf-8)

I am trying to solve the Cocos2d-x Keyboard input problem on Android 5.x when I create a CCImage from text with many emoji found on the keyboard (some work, but most do not). On Android 4.x, on some devices only distorted text / extra characters are displayed. The source of the failure is the JNI call NewStringUTF (). It just doesn't support all 2, 3, and 4 bytes of utf-8 characters in Android 5 / Lollipop.

This crash occurs on cocos2d-x v2.2.6 (and confirmed on 3.x) using NDK 10e with Toolchain 4.8 (not sure if any of them have too much difference, we used 9d before switching to Android Studio, and I am sure that we had this problem, but there was much less use of candy.)

If you never hit any of the unmodified utf-8 characters (i.e. stick with ascii), you will probably never see the problem.

Log Cat:
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]     string: '👊👊'
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]     in call to NewStringUTF
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]     from void org.cocos2dx.lib.Cocos2dxHelper.nativeSetEditTextDialogResult(byte[])
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65] "GLThread 45716" prio=5 tid=14 Runnable
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   | group="main" sCount=0 dsCount=0 obj=0x12c0c6c0 self=0xf442bc00
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   | sysTid=10959 nice=0 cgrp=default sched=0/0 handle=0xf450c380
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   | state=R schedstat=( 0 0 0 ) utm=1164 stm=188 core=2 HZ=100
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   | stack=0xeed4e000-0xeed50000 stackSize=1036KB
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   | held mutexes= "mutator lock"(shared held)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #00 pc 00004e64  /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #01 pc 00003665  /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #02 pc 00271461  /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+84)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #03 pc 002534d7  /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+158)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #04 pc 000b7f5b  /system/lib/libart.so (art::JniAbort(char const*, char const*)+610)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #05 pc 000b8681  /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #06 pc 000bac4f  /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+922)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #07 pc 000c474d  /system/lib/libart.so (art::CheckJNI::NewStringUTF(_JNIEnv*, char const*)+44)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #08 pc 002a6324  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (_JNIEnv::NewStringUTF(char const*)+40)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #09 pc 0076eb6c  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::BitmapDC::getBitmapFromJavaShadowStroke(char const*, int, int, cocos2d::CCImage::ETextAlign, char const*, float, float, float, float, bool, float, float, float, float, bool, float, float, float, float)+312)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #10 pc 0076f12c  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCImage::initWithStringShadowStroke(char const*, int, int, cocos2d::CCImage::ETextAlign, char const*, int, float, float, float, bool, float, float, float, float, bool, float, float, float, float)+216)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #11 pc 007aeb14  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCTexture2D::initWithString(char const*, cocos2d::_ccFontDefinition*)+1188)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #12 pc 0072cd6c  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCLabelTTF::updateTexture()+120)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #13 pc 0072c804  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::CCLabelTTF::setString(char const*)+260)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #14 pc 00523140  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (cocos2d::extension::CCEditBoxImplAndroid::setText(char const*)+344)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #15 pc 00523474  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (???)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #16 pc 0076fb2c  /data/app/com.appsomniacs.da2.debug-1/lib/arm/libcocos2dcpp.so (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult+208)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   native: #17 pc 001dfeb1  /data/dalvik-cache/arm/data@app@com.appsomniacs.da2.debug-1@base.apk@classes.dex (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult___3B+100)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   at org.cocos2dx.lib.Cocos2dxHelper.nativeSetEditTextDialogResult(Native method)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   at org.cocos2dx.lib.Cocos2dxHelper.access$000(Cocos2dxHelper.java:41)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   at org.cocos2dx.lib.Cocos2dxHelper$1.run(Cocos2dxHelper.java:267)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1501)
    12-11 01:02:17.460 10451-10959/com.appsomniacs.da2.debug A/art: sart/runtime/check_jni.cc:65]   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1278)

Stack trace (from another test, but same crash)

    Build fingerprint: 'samsung/zerofltetmo/zerofltetmo:5.1.1/LMY47X/G920TUVU3DOJ7:user/release-keys'
            Revision: '11'
            ABI: 'arm'
            pid: 18460, tid: 18534, name: GLThread 28670  >>> com.appsomniacs.da2 <<<
            signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
                r0 00000000  r1 00004866  r2 00000006  r3 00000000
                r4 f33a4db8  r5 00000006  r6 00000000  r7 0000010c
                r8 88476100  r9 f442c800  sl 00000000  fp 12f61070
                ip 00004866  sp f33a4960  lr f6f01cf9  pc f6f25c30  cpsr 600b0010

            backtrace:
                #00 pc 0003bc30  /system/lib/libc.so (tgkill+12)
                #01 pc 00017cf5  /system/lib/libc.so (pthread_kill+52)
                #02 pc 00018907  /system/lib/libc.so (raise+10)
                #03 pc 000151a5  /system/lib/libc.so (__libc_android_abort+36)
                #04 pc 00012fec  /system/lib/libc.so (abort+4)
                #05 pc 0075a275  /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (__gnu_cxx::__verbose_terminate_handler()+220)
                #06 pc 0072a10b  /data/app/com.appsomniacs.da2-

2/lib/arm/libcocos2dcpp.so (__cxxabiv1::__terminate(void (*)())+2)
            #07 pc 0072a13b  /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (std::terminate()+10)
            #08 pc 0072a4ab  /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (__cxa_pure_virtual+14)
            #09 pc 0041ecc5  /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so
            #10 pc 005977ab  /data/app/com.appsomniacs.da2-2/lib/arm/libcocos2dcpp.so (Java_org_cocos2dx_lib_Cocos2dxHelper_nativeSetEditTextDialogResult+110)
            #11 pc 001dfe39  /data/dalvik-cache/arm/data@app@com.appsomniacs.da2-2@base.apk@classes.dex
+1
source share
1 answer

, std::string jbyte, java- java jstring, ++ jni. , 170k , , emoji , ... . , , Android 5.x, , . Android 4.x , .

++ - :

jstring JniHelper::getjString(const char *input) {
    JniMethodInfo minfo; // JniHelper

    bool hasMethod = JniHelper::getStaticMethodInfo (minfo, APPTAG_JNI_PACKAGE_NAME, "convertCStringToJniSafeString", "([B)Ljava/lang/String;");
    if (!hasMethod)
    {
        return minfo.env->NewStringUTF(""); // TODO Tune your response to fit your needs...
    }
    else
    {
        string nativeString = std::string(input); // has a bit of a code smell, there is probably a better way.
        // cite: http://stackoverflow.com/questions/27303316/c-stdstring-to-jstring-with-a-fixed-length
        jbyteArray array = minfo.env->NewByteArray(nativeString.length());
        minfo.env->SetByteArrayRegion(array,0,nativeString.length(),(jbyte*)nativeString.c_str());

        // cite: http://discuss.cocos2d-x.org/t/jni-return-string/9982/3
        jstring str = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, array);
        minfo.env->DeleteLocalRef(array);
        return str;
    }
}

java java :

public static String convertCStringToJniSafeString(byte[] input) {
    try {
        String nativeString = new String(input, "UTF-8"); // please debate what the safest charset should be?
        return nativeString;
    } catch (UnsupportedEncodingException e) {
        // TODO Simplistic Error handling, tune to your needs.
        Log.e(APPTAG, "Couldn't convert the jbyteArray to jstring");
        return ""; //JSTRING_CONVERT_FAIL
    }
}

jstring ( UTF8) , - , , .

, - ... , ...

+4

Source: https://habr.com/ru/post/1618434/


All Articles