Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,333
    • Issues 4,333
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 370
    • Merge Requests 370
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #16899

Closed
Open
Opened Jul 02, 2019 by GuangGuang@Guang1234567

Crash at `foreign export ccall function` that return `Ptr CString` for C on Arm64 (android)

Hello dev:

I export a haskell function for c like below:

foreign export ccall "namesMatching" _namesMatchingC :: CString -> IO (Ptr CString)

_namesMatchingC filePath = do
    filePath' <- peekCString filePath
    pathNames <- namesMatching filePath'
    pathNames' <- forM pathNames mapFilePath
    withArray pathNames' $ \cstrArr -> return cstrArr
  where
    mapFilePath = (`withCString` (\cstr -> do return cstr))

This function return IO (Ptr CString) that interface with char** in c++.

My android jni cpp code that calling namesMatching exported from haskell:

#include <jni.h>

#include <unistd.h>
#include <sstream>
#include <string>

#include "ghcversion.h"
#include "HsFFI.h"
#include "Rts.h"

#include "my_log.h"
#include "Lib_stub.h"
#include "FileSystem_stub.h"

extern "C" {

// ........

JNIEXPORT jobjectArray
JNICALL
Java_com_zw3rk_helloworld_MainActivity_namesMatchingJNI(
        JNIEnv *env,
        jobject thiz,
        jstring path) {

    LOG_ASSERT(NULL != env, "JNIEnv cannot be NULL.");
    LOG_ASSERT(NULL != thiz, "jobject cannot be NULL.");
    LOG_ASSERT(NULL != path, "jstring cannot be NULL.");

    const char *c_value = env->GetStringUTFChars(path, NULL);
    const char **result = static_cast<const char **>(namesMatching(
            const_cast<char *>(c_value)));
    jsize len = 0;
    for (; result[len] != NULL; len++);

    env->ReleaseStringUTFChars(path, c_value);
    jobjectArray strs = env->NewObjectArray(len, env->FindClass("java/lang/String"), env->NewStringUTF(""));
    for (int i = 0; i < len; i++) {
        jstring str = env->NewStringUTF(result[i]);  // <-----------  crash here
        env->SetObjectArrayElement(strs, i, str);
    }
    // freeCStringArray frees the newArray pointer created in haskell module
    // freeCStringArray(len, result);
    return strs;
}

}

My android kotlin code that calling Java_com_zw3rk_helloworld_MainActivity_namesMatchingJNI:


private fun doSthAfterAllPermissionGranted() {
        // Example of a call to a native method
        val tv = findViewById(R.id.sample_text) as TextView

        Handler(Looper.getMainLooper()).postDelayed(
                {
                    tv.text = stringFromJNI()
                    Log.e("test1", "--------- begin --------namesMatchingJNI")
                    Log.w("test2", "${namesMatchingJNI("/sdcard/*.txt").joinToString()}}")
                    Log.e("test3", "---------- end --------namesMatchingJNI")

                    doSthAfterAllPermissionGranted()
                }
                , 2000)
    }

   external fun namesMatchingJNI(path: String): Array<String>

EveryThing is ok, but sometimes crash at jstring str = env->NewStringUTF(result[i]);

result[i] is obtained from haskell.

The Crash dump is here:

********** Crash dump: **********
Build fingerprint: 'HONOR/COR-AL00/HWCOR:8.1.0/HUAWEICOR-AL00/151(C00GT):user/release-keys'
pid: 19991, tid: 19991, name: w3rk.helloworld  >>> com.zw3rk.helloworld <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x9
Stack frame #00 pc 000000000001cea0  /system/lib64/libc.so (strlen+16)
Stack frame #01 pc 00000000003bfbe0  /system/lib64/libart.so (art::mirror::String::AllocFromModifiedUtf8(art::Thread*, char const*)+28)
Stack frame #02 pc 000000000037be84  /system/lib64/libart.so (art::JNI::NewStringUTF(_JNIEnv*, char const*)+572)
Stack frame #03 pc 0000000000b55b90  /data/app/com.zw3rk.helloworld-VAuV-C-ri9T0r3qoc_cgzQ==/lib/arm64/libnative-lib.so (_JNIEnv::NewStringUTF(char const*)+48)
Stack frame #04 pc 0000000000b562d8  /data/app/com.zw3rk.helloworld-VAuV-C-ri9T0r3qoc_cgzQ==/lib/arm64/libnative-lib.so (Java_com_zw3rk_helloworld_MainActivity_namesMatchingJNI+652)
Stack frame #05 pc 0000000000012558  /data/app/com.zw3rk.helloworld-VAuV-C-ri9T0r3qoc_cgzQ==/oat/arm64/base.odex (offset 0x12000)

I think the AllocFromModifiedUtf8 in error log means that cstring return from haskell has been changed? Or Sth Else cause it?

Edited Jul 02, 2019 by Ben Gamari
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
Reference: ghc/ghc#16899