1

I have the following CPP code. What I want to do is when an error occurs in my native side, I will notify Java about the error. I used How can I catch SIGSEGV (segmentation fault) and get a stack trace under JNI on Android? as reference.

static JavaVM* g_JVM = NULL;
static jobject  g_thejavaobject  = NULL;

void InitializeNativeSide(JNIEnv *env, jclass, jobject object)
{
    env->GetJavaVM(&g_JVM);
    g_thejavaobject = env->NewGlobalRef(object);
}

// this executes in another thread running in parallel with UI thread
void StartExecuting(JNIEnv *_env, jclass) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = SignalErrorHandler;
    sa.sa_flags   = SA_SIGINFO;
    sigaction(SIGSEGV, &sa, NULL);

    // native starts executing here. after a while, a SEGFAULT is encountered
    // triggering SignalErrorHandler()
    ...
}

void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
{
    JNIEnv *env;
    g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);

    jclass myClass = env->FindClass("com/company/MyClass");
    jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
    env->CallVoidMethod(g_thejavaobject, myMethod);

    env->DeleteLocalRef(myClass);
}

Everything works fine but the call to myClass.nativeCrashed() does not work. What am I doing wrong?

user1506104
  • 6,554
  • 4
  • 71
  • 89
  • Do you really think it's safe to make Java calls in a signal handler? That is not going to work. The **only** function calls that can be safely made from a signal handler are async-signal-safe one listed at http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04 – Andrew Henle Aug 14 '18 at 13:30

1 Answers1

2

You can't do this:

void SignalErrorHandler(int signal, siginfo_t *si, void *arg)
{
    JNIEnv *env;
    g_JVM->GetEnv((void**)&env, JNI_VERSION_1_6);

    jclass myClass = env->FindClass("com/company/MyClass");
    jmethodID myMethod = env->GetMethodID(myClass, "nativeCrashed", "()V" );
    env->CallVoidMethod(g_thejavaobject, myMethod);

    env->DeleteLocalRef(myClass);
}

That will not work for at least two fundamental reasons.

First, only async-signal-safe functions may be called from within a signal handler. The POSIX-specified list can be found at http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03.

No Java JNI call is async-signal-safe.

Second, the Java JVM uses SIGSEGV internally - getting a SIGSEGV is not necessarily fatal:

Signals Used in Oracle Solaris, Linux, and macOS

...

SIGSEGV, SIGBUS, SIGFPE, SIGPIPE, SIGILL These signals are used in the implementation for implicit null check, and so forth.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Thanks for the link. I appreciate it. By the way, the link in my post claims that he was able to call java from his signal handler. Now im confused. – user1506104 Aug 14 '18 at 14:51
  • @user1506104 Read the POSIX documentation I linked: "when a signal interrupts an unsafe function or equivalent ... and the signal-catching function calls an unsafe function, **the behavior is undefined**." The problems are only specified to happen at certain times, and then the results are "undefined behavior". In short, it can *appear* to work - until it fails. It's similar to overrunning an array - it might "work", but it's still wrong. And it can fail. – Andrew Henle Aug 14 '18 at 14:58
  • 1
    You are awesome! Thanks! – user1506104 Aug 14 '18 at 15:01
  • @user1506104 Thanks for that. I had to learn this the hard way, too. This question is also relevant, as the questioner was doing something similar: https://stackoverflow.com/questions/34547199/art-prevents-any-java-calls-from-jni-during-native-signal-handling/34553070#34553070 – Andrew Henle Aug 14 '18 at 15:02