Reputation: 127
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
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
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