4

In my Google Play developer console, I see a lot of crashes in NewStringUTF() like so:

  #00  pc 00000000001b9f22  /system/lib/libart.so (art::IndirectReferenceTable::Add(art::IRTSegmentState, art::ObjPtr<art::mirror::Object>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+630)
  #01  pc 00000000002ad461  /system/lib/libart.so (_jthrowable* art::JNIEnvExt::AddLocalReference<_jthrowable*>(art::ObjPtr<art::mirror::Object>)+32)
  #02  pc 0000000000298e49  /system/lib/libart.so (art::JNI::NewStringUTF(_JNIEnv*, char const*)+416)
  #03  pc 000000000024baf0  /data/app/com.steenriver.littlecrane-1vpoZWmGtL5mN2uxtEBltA==/lib/arm/liblittlecrane.so (androidsupport_reportFailedLaunch(char const*)+64)
  ...

So the actually crash is in IndirectReferenceTable::Add() call.

Why would the NewStringUTF() call fail? I pass it a normal ASCII string, and my 'env' pointer is not null.

My code:

bool androidsupport_reportFailedLaunch( const char* msg )
{
        if ( !androidsupport_engine.app ) return false;

        JNIEnv* env = androidsupport_engine.app->appThreadEnv;
        if ( !env ) return false;

        jstring jniText = env->NewStringUTF( msg );
        EXCEPTION_RETURN( env );

        ...

The msg parameter is not nil, and points to a const char* that is in static memory, as the function is called like so:

androidsupport_reportFailedLaunch( "Incompatible device." );

The JNIEnv* is cached, but it was attached to the native thread like so:

    int error = (*android_app->activity->vm)->AttachCurrentThread(android_app->activity->vm, &android_app->appThreadEnv, NULL);
    if (error) android_app->appThreadEnv = NULL;

according to an Android example by nvidia.

Bram
  • 7,440
  • 3
  • 52
  • 94
  • Maybe you've filled up the local reference table? Every call to `NewStringUTF` creates a new local reference. Do you ever delete those? Or does this thread return back to Java? – Michael Jul 23 '19 at 06:01
  • Possible duplicate of [Keeping a global reference to the JNIEnv environment](https://stackoverflow.com/questions/12420463/keeping-a-global-reference-to-the-jnienv-environment) – Andrew Henle Jul 23 '19 at 12:32
  • You **can not** cache the `JNIEnv *` value. – Andrew Henle Jul 23 '19 at 12:33
  • @AndrewHenle I do AttachCurrentThread() when I cache that JNIEnv, and it is only used by my NativeActivity thread. – Bram Jul 23 '19 at 16:43

1 Answers1

0

NewStringUTF() accepts modified UTF-8. Feel free to use NewString() to construct a regular Java String object as long as the input argument contains only ASCII characters. As soon as it includes non-ASCII characters, manual conversion may be required.

Alexander Solovets
  • 2,447
  • 15
  • 22
  • I only feed it ASCII strings. Also, I doubt that if it contained any other characters, it would flat-out crash. – Bram Jul 23 '19 at 04:50
  • @Bram It *does* 'flat-out crash'. – user207421 Jul 23 '19 at 06:52
  • NewString is for UTF-16. Nothing in Java/JNI/JVM is related to ASCII (except foreign character set encoding/decoding [StandardCharsets.US_ASCII](https://docs.oracle.com/javase/9/docs/api/java/nio/charset/StandardCharsets.html#US_ASCII)). – Tom Blodget Jul 23 '19 at 22:33
  • My point was that ASCII string is a valid UTF-8 string, but I forgot about `NewString()` accepting UTF-16, and not UTF-8. – Alexander Solovets Jul 24 '19 at 07:07