Exception

The division with zero denominator in integer will cause Floating Pointer Exception.

jint div(jint numerator, jint denominator) {
  return numerator / denominator;
}

jint intResult = div(3, 0);
LOGD("native int result is %d", intResult);
  • LogCat
A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
A/DEBUG: Build fingerprint: 'Android/vbox86p/vbox86p:8.0.0/OPR6.170623.017/233:userdebug/test-keys'
A/DEBUG: Revision: '0'
A/DEBUG: ABI: 'x86'
A/DEBUG: pid: 2156, tid: 2156, name: com.practice  >>> com.practice <<<
A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
A/DEBUG: Abort message: '=================================================================
    ==2156==ERROR: AddressSanitizer: FPE on unknown address 0xbc483609 (pc 0xbc483609 bp 0xff8c7188 sp 0xff8c7180 T0)
        #0 0xbc483608  (/data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libnative-lib.so+0x608)
        #1 0xbc4836b4  (/data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libnative-lib.so+0x6b4)
        #2 0xbccb00b4  (/data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/oat/x86/base.odex+0xf0b4)

    AddressSanitizer can
A/DEBUG:     eax 00000000  ebx 0000086c  ecx 0000086c  edx 00000006
A/DEBUG:     esi 0000086c  edi f2ef5088
A/DEBUG:     xcs 00000023  xds 0000002b  xes 0000002b  xfs 0000006b  xss 0000002b
A/DEBUG:     eip f2f55ba9  ebp f2ef50a8  esp f2ef503c  flags 00000296
A/DEBUG: backtrace:
A/DEBUG:     #00 pc 00000ba9  [vdso:f2f55000] (__kernel_vsyscall+9)
A/DEBUG:     #01 pc 00075dcc  /system/lib/libc.so (tgkill+28)
A/DEBUG:     #02 pc 0001f05e  /system/lib/libc.so (abort+110)
A/DEBUG:     #03 pc 0005d4c1  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libclang_rt.asan-i686-android.so (offset 0x52000) (_ZN11__sanitizer5AbortEv+81)
A/DEBUG:     #04 pc 0005c0bd  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libclang_rt.asan-i686-android.so (offset 0x52000) (_ZN11__sanitizer3DieEv+189)
A/DEBUG:     #05 pc 000d79fb  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libclang_rt.asan-i686-android.so (offset 0x52000) (_ZN6__asan19ScopedInErrorReportD2Ev+491)
A/DEBUG:     #06 pc 000d757f  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libclang_rt.asan-i686-android.so (offset 0x52000) (_ZN6__asan18ReportDeadlySignalERKN11__sanitizer13SignalContextE+207)
A/DEBUG:     #07 pc 000d6e1e  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libclang_rt.asan-i686-android.so (offset 0x52000) (_ZN6__asan18AsanOnDeadlySignalEiPvS0_+94)
A/DEBUG:     #08 pc 0001edef  /system/lib/libc.so
A/DEBUG:     #09 pc 00000608  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libnative-lib.so (_Z3divii+24)
A/DEBUG:     #10 pc 000006b4  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/lib/x86/libnative-lib.so (Java_com_practice_Lib_callNative+84)
A/DEBUG:     #11 pc 0000f0b4  /data/app/com.practice-cs4_BLEyZ1tn0ABduCMO6g==/oat/x86/base.odex (offset 0xf000)
A/DEBUG:     #12 pc 0000307f  <anonymous:ccf00000>

But it return Infinity in double division.

jdouble div(jdouble numerator, jdouble denominator) {
  return numerator / denominator;
}

jdouble result = div(3.0, 0.0);
LOGD("native result is %lf", result); // D/nativeCode: native result is inf

C++ warning: division of double by zero

Throw the exception from native

I have to check the input then throw the relative exception in native.

  • Lib.kt
package com.practice

class Lib {

  @Throws(ArithmeticException::class)
  external fun callNative(numerator: Double, denominator: Double): Double

  init {
    System.loadLibrary("native-lib")
  }
}
  • MainActivity.kt
package com.practice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    try {
      val value = Lib().callNative(3.0, 0.0)
      println("value is $value")
      textView.text = "$value"
    } catch (exception: ArithmeticException) {
      println("Got exception!")
      exception.printStackTrace()
      textView.text = exception.message
    }
  }

}
  • native-lib.cpp
jdouble div(jdouble numerator, jdouble denominator) {
  return numerator / denominator;
}

extern "C" JNIEXPORT jdouble JNICALL
Java_com_practice_Lib_callNative(JNIEnv *env, jobject /* this */, jdouble numerator, jdouble denominator) {
  if (denominator == 0.0) {
    jclass cls = env->FindClass("java/lang/ArithmeticException");
    if (cls != nullptr) {
      env->ThrowNew(cls, "denominator should not be zero");
    }
    env->DeleteLocalRef(cls);
    return NULL;
  }

  jdouble result = div(numerator, denominator);
  LOGD("native result is %lf", result);
  return result;
}
  • LogCat
I/System.out: Got exception!
W/System.err: java.lang.ArithmeticException: denominator should not be zero
W/System.err:     at com.practice.Lib.callNative(Native Method)
W/System.err:     at com.practice.MainActivity.onCreate(MainActivity.kt:14)
W/System.err:     at android.app.Activity.performCreate(Activity.java:6975)
W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
W/System.err:     at android.app.ActivityThread.-wrap11(Unknown Source:0)
W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:105)
W/System.err:     at android.os.Looper.loop(Looper.java:164)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6541)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
W/System.err:     at com.android.internal.os.WrapperInit.main(WrapperInit.java:93)
W/System.err:     at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:284)

Process the Java exception in native

  • Lib.kt
package com.practice

class Lib {

  @Throws(ArithmeticException::class)
  fun div(numerator: Double, denominator: Double): Double {
    println("Lib.div($numerator, $denominator)")
    if (denominator == 0.0) {
      throw java.lang.ArithmeticException("denominator should not be zero")
    } else {
      val result: Double = numerator / denominator
      println(" = $result")
      return result
    }
  }

  external fun callNative()

  init {
    System.loadLibrary("native-lib")
  }
}
  • MainActivity.kt
package com.practice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    Lib().callNative()
  }
}
  • native-lib.cpp
#include <jni.h>
#include <android/log.h>

constexpr const char *TAG = "nativeCode";

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)

jmethodID getMethodId(JNIEnv *env, jclass cls, const char *methodName, const char *sig) {
  jmethodID result = env->GetMethodID(cls, methodName, sig);
  if (result == nullptr) {
    LOGE("method id for %s(%s) not found.", methodName, sig);
  }
  return result;
}

jdouble div(JNIEnv *env, jobject obj, jdouble numerator, jdouble denominator) {
  jclass cls = env->GetObjectClass(obj);
  if (cls == nullptr) {
    LOGE("can not find class");
  }

  jmethodID methodId = getMethodId(env, cls, "div", "(DD)D");
  if (methodId == nullptr) {
    LOGE("div method id is not found.");
  }

  jdouble result = env->CallDoubleMethod(obj, methodId, numerator, denominator);
  env->DeleteLocalRef(cls);
  return result;
}

extern "C" JNIEXPORT jdouble JNICALL
Java_com_practice_Lib_callNative(JNIEnv *env, jobject obj) {
  jdouble result = div(env, obj, 6.0, 0.0);
  jthrowable throwable = env->ExceptionOccurred();
  if (throwable) {
    LOGE("got exception");
    env->ExceptionDescribe();
    env->ExceptionClear();
  } else {
    LOGD("native result is %lf", result);
  }
}
  • LogCat
I/System.out: Lib.div(6.0, 0.0)
E/nativeCode: got exception
W/System.err: java.lang.ArithmeticException: denominator should not be zero
W/System.err:     at com.practice.Lib.div(Lib.kt:9)
W/System.err:     at com.practice.Lib.callNative(Native Method)
W/System.err:     at com.practice.MainActivity.onCreate(MainActivity.kt:12)
W/System.err:     at android.app.Activity.performCreate(Activity.java:6975)
W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
W/System.err:     at android.app.ActivityThread.-wrap11(Unknown Source:0)
W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:105)
W/System.err:     at android.os.Looper.loop(Looper.java:164)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6541)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
W/System.err:     at com.android.internal.os.WrapperInit.main(WrapperInit.java:93)
W/System.err:     at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:284)

But I do not know why getting this error:

    --------- beginning of crash
A/libc: Fatal signal 4 (SIGILL), code 2, fault addr 0xb3b5ada6 in tid 7365 (com.practice)
A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
A/DEBUG: Build fingerprint: 'Android/vbox86p/vbox86p:8.0.0/OPR6.170623.017/233:userdebug/test-keys'
A/DEBUG: Revision: '0'
A/DEBUG: ABI: 'x86'
A/DEBUG: pid: 7365, tid: 7365, name: com.practice  >>> com.practice <<<
A/DEBUG: signal 4 (SIGILL), code 2 (ILL_ILLOPN), fault addr 0xb3b5ada6
A/DEBUG:     eax 3b57082e  ebx b3b5cfbc  ecx 00590000  edx 00000000
A/DEBUG:     esi c2a01bc0  edi ffaac87c
A/DEBUG:     xcs 00000023  xds 0000002b  xes 0000002b  xfs 0000006b  xss 0000002b
A/DEBUG:     eip b3b5ada6  ebp ffaac858  esp ffaac7e0  flags 00010246
A/DEBUG: backtrace:
A/DEBUG:     #00 pc 00000da6  /data/app/com.practice-5jxlDgC56AqnHn9cuRTswg==/lib/x86/libnative-lib.so (Java_com_practice_Lib_callNative+262)
A/DEBUG:     #01 pc 0000f088  /data/app/com.practice-5jxlDgC56AqnHn9cuRTswg==/oat/x86/base.odex (offset 0xf000)
A/DEBUG:     #02 pc 0000307f  <anonymous:c3e00000>
A/DEBUG:     #03 pc 0044d69f  /dev/ashmem/dalvik-main space (region space) (deleted)

And addr2line always point to the latest line of Java_com_practice_Lib_callNative . Someone else got SIGILL with wrong signature of method. Finally I notice that Lib#callNative() is void method, so the correct one is:

extern "C" JNIEXPORT void JNICALL
Java_com_practice_Lib_callNative(JNIEnv *env, jobject obj)

results matching ""

    No results matching ""