Application crash when calling native code

Hey, I’m trying to get a shared object library to work, but with no avail.

Here is the C++ code:

extern "C" const char* GetHelp(){
    return "username_password";
}

Here is the C#:

    private void Awake()
    {
        GetUser();
    }

    [DllImport("Utility")]
    private static extern string GetHelp();

    private void GetUser()
    {
        string tmp = GetHelp();
        username = tmp.Split('_')[0];
        password = tmp.Split('_')[1];
        Debug.Log(username);
        Debug.Log(password);
    }

Here is the logcat:
05-31 14:30:46.035 26388-26450/com.racsi.filesecurity A/libc: invalid address or address of corrupt block 0x9f2ccd7c passed to dlfree
05-31 14:30:46.035 26388-26450/com.racsi.filesecurity A/libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdeadbaad in tid 26450 (UnityMain)
05-31 14:30:46.105 378-378/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
05-31 14:30:46.105 378-378/? A/DEBUG: Build fingerprint: ‘samsung/j5nltexx/j5nlte:6.0.1/MMB29M/J500FNXXU1BQA3:user/release-keys’
05-31 14:30:46.105 378-378/? A/DEBUG: Revision: ‘5’
05-31 14:30:46.105 378-378/? A/DEBUG: ABI: ‘arm’
05-31 14:30:46.105 378-378/? A/DEBUG: pid: 26388, tid: 26450, name: UnityMain >>> com.racsi.filesecurity <<<
05-31 14:30:46.105 378-378/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdeadbaad
05-31 14:30:46.165 378-378/? A/DEBUG: Abort message: ‘invalid address or address of corrupt block 0x9f2ccd7c passed to dlfree’
05-31 14:30:46.165 378-378/? A/DEBUG: r0 00000000 r1 00000000 r2 00000000 r3 00000002
05-31 14:30:46.165 378-378/? A/DEBUG: r4 9f2ccd7c r5 deadbaad r6 b6cdbeb8 r7 98207000
05-31 14:30:46.165 378-378/? A/DEBUG: r8 9f2ccd84 r9 9c335660 sl a0ebc510 fp ae41ecac
05-31 14:30:46.165 378-378/? A/DEBUG: ip b6cd65dc sp ae41ec88 lr b6ca8847 pc b6ca8846 cpsr 60010030
05-31 14:30:46.175 378-378/? A/DEBUG: backtrace:
05-31 14:30:46.175 378-378/? A/DEBUG: #00 pc 00030846 /system/lib/libc.so (dlfree+1285)
05-31 14:30:46.175 378-378/? A/DEBUG: #01 pc 002a0944 /mnt/asec/com.racsi.filesecurity-2/lib/arm/libmono.so (g_free+44)
05-31 14:30:46.175 378-378/? A/DEBUG: #02 pc 001ba068 /mnt/asec/com.racsi.filesecurity-2/lib/arm/libmono.so
05-31 14:30:46.175 378-378/? A/DEBUG: #03 pc 0000df94
05-31 14:30:47.905 26792-26792/? E/Zygote: v2
05-31 14:30:47.905 26792-26792/? E/Zygote: accessInfo : 0
05-31 14:30:48.195 1538-2503/? E/NativeCrashListener: Exception dealing with report
android.system.ErrnoException: read failed: EAGAIN (Try again)
at libcore.io.Posix.readBytes(Native Method)
at libcore.io.Posix.read(Posix.java:169)
at libcore.io.BlockGuardOs.read(BlockGuardOs.java:230)
at android.system.Os.read(Os.java:367)
at com.android.server.am.NativeCrashListener.consumeNativeCrashData(NativeCrashListener.java:240)
at com.android.server.am.NativeCrashListener.run(NativeCrashListener.java:138)
05-31 14:30:48.665 378-378/? A/DEBUG: Tombstone written to: /data/tombstones/tombstone_01
05-31 14:30:48.665 378-378/? E/DEBUG: AM write failed: Broken pipe

Any help will be appreciated, thank you.

Your problem here is that you can’t just assign a string from native land to managed land like that. It needs to be marshalled.

Here’s some code to get you going.
C code:

extern "C" const char *GetHelp(){
    return "username_password";
}

Here is the C#:

    private void Awake()
    {
        GetUser();
    }

    [DllImport("Utility")]
    private static extern IntPtr GetHelp();

    private void GetUser()
    {
        //
        // Call native lib to get a reference (pointer) to the data
        //
        IntPtr ptrData = GetHelp();

        //
        // We need to marshal the data from the pointer to a string.
        //
        string tmp = Marshal.PtrToStringAnsi (ptrData);

        username = tmp.Split('_')[0];
        password = tmp.Split('_')[1];
        Debug.Log(username);
        Debug.Log(password);
    }

So note there are 3 distinct changes I’ve made here.

  • change the import declaration to IntPtr instead of string
  • change the variable being assigned from GetHelp() to IntPtr
  • Marshal the data from the pointer to a managed ANSI string.

As a general rule, anything that is pointer data (char *'s, arrays, structs, etc) will need to be marshalled.

Here is some additional reading: Interop with Native Libraries | Mono

Let us know if it works!

2 Likes

As an addendum, here’s a handy chart showing what types to use when marshaling between native and managed code:

If Unicode support is needed, then I suggest UTF-8 encoding since you can still use const char* on the native side when receiving strings.

3 Likes

It finally works, thank you very much for your help! :slight_smile:

1 Like