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
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)