gtrevi
gtrevi

Reputation: 127

Android: getting a c++ std::string up to JNIEXPORT gets unexpectedly cleared out

On an Android application, I'm trying to get a string from native code up to Java, but exactly at the JNIEXPORT level, the std::string gets wiped out of its contents. Here's the code for all the three layers:

C++ code (original x-patform class):

std::string GTAInterface::GetConfigurationJSON()
{
    std::string m_cfgJSON = "a bare test";
    return m_cfgJSON;
}

C++ wrapper code (since JNI on Android can only call static C++ functions... no words on this):

const char *gtaGateway::GetConfigurationJSON(int sysId)
{
    string ret = ((GTAInterface*)gtaSystemArray[sysId])->GetConfigurationJSON();
    return ret.c_str(); // here the "ret" string is still retaining the retrieved value
}

An finally, the JNIEXPORT class:

JNIEXPORT jstring JNICALL
Java_com_gta_sdk_gtaGateway_GetConfigurationJSON(JNIEnv *env, jobject obj, jint sys)
{
    std::string cfgJson = gtaGateway::GetConfigurationJSON(sys);

    return env->NewStringUTF(cfgJson.c_str()); // here the debugger shows that "cfgJson" is "" (empty)??!!
}

So, the code correctly gets executed throughout all the call chain, but for some reason I can't figure out why the "cfgJson" string @ the JNIEXPORT level gets cleared out! Could someone please help out, since I have no other clue of what I could be doing wrong...

Many thanks!

Upvotes: 0

Views: 462

Answers (2)

gtrevi
gtrevi

Reputation: 127

So, just caught the issue (thanks Andrew for inspiring): a through "heap chase" with a monitor and a load test got me to the corruption point (elsewhere in the application)... goods and bads of unmanaged :)

Therefore, just in case someone else needs it, the approach exposed in the question is perfectly working, as well as my initial attempt in passing std::string-s all the way up through the call chain 'till the jstring.

Upvotes: 0

Andrew Henle
Andrew Henle

Reputation: 1

Your underlying string object is destroyed.

This code

const char *gtaGateway::GetConfigurationJSON(int sysId)
{
    string ret = ((GTAInterface*)gtaSystemArray[sysId])->GetConfigurationJSON();
    return ret.c_str(); // here the "ret" string is still retaining the retrieved value
}

returns a pointer to a C-style string, but per the c_str() method documentation

The pointer returned may be invalidated by further calls to other member functions that modify the object.

When your gtaGateway::GetConfigurationJSON() method returns, the destructor for the string object is called. That likely "modifies the object", I'd think.

I haven't tested it, but I suspect this code will work:

const string gtaGateway::GetConfigurationJSON(int sysId)
{
    string ret = ((GTAInterface*)gtaSystemArray[sysId])->GetConfigurationJSON();
    return ret;
}

Note the return is now a string object and not a C-string pointer into an object about to be destroyed.

Upvotes: 1

Related Questions