From d7dcc4c7dd70333b5f80edec7efdba5154085cd4 Mon Sep 17 00:00:00 2001 From: David Li Date: Fri, 12 Jun 2026 15:03:12 +0900 Subject: [PATCH] fix(java/driver/jni): check for pending exceptions more thoroughly After JNI calls that can leave a pending Java exception (GetArrayLength, GetObjectArrayElement, GetIntArrayRegion, GetByteArrayRegion, NewByteArray, SetByteArrayRegion) and are followed by further JNI or native ADBC work, check env->ExceptionCheck() and return the function's existing error default, letting the pending exception propagate to Java rather than performing more work or raising a second exception. Generated-by: Claude Opus 4.8 --- java/driver/jni/src/main/cpp/jni_wrapper.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/java/driver/jni/src/main/cpp/jni_wrapper.cc b/java/driver/jni/src/main/cpp/jni_wrapper.cc index c76e70f0c6..6221a60cbc 100644 --- a/java/driver/jni/src/main/cpp/jni_wrapper.cc +++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc @@ -414,6 +414,7 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase( jclass nativeHandleKlass = RequireImplClass(env, "NativeDatabaseHandle"); jmethodID nativeHandleCtor = RequireMethod(env, nativeHandleKlass, "", "(J)V"); const jsize num_params = env->GetArrayLength(parameters); + if (env->ExceptionCheck()) return nullptr; if (num_params % 2 != 0) { throw AdbcException{ .code = ADBC_STATUS_INVALID_ARGUMENT, @@ -431,8 +432,10 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase( for (jsize i = 0; i < num_params; i += 2) { // N.B. assuming String because Java side is typed as String[] auto key = reinterpret_cast(env->GetObjectArrayElement(parameters, i)); + if (env->ExceptionCheck()) return nullptr; auto value = reinterpret_cast(env->GetObjectArrayElement(parameters, i + 1)); + if (env->ExceptionCheck()) return nullptr; JniStringView key_str(env, key); JniStringView value_str(env, value); @@ -820,8 +823,10 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementGetOptionBytes( return nullptr; } jbyteArray result = env->NewByteArray(static_cast(length)); + if (result == nullptr || env->ExceptionCheck()) return nullptr; env->SetByteArrayRegion(result, 0, static_cast(length), reinterpret_cast(buf.data())); + if (env->ExceptionCheck()) return nullptr; return result; } @@ -899,9 +904,11 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_statementSetOptionBytes( try { JniStringView key_str(env, key); jsize value_length = env->GetArrayLength(value); + if (env->ExceptionCheck()) return; std::vector value_buf(static_cast(value_length)); env->GetByteArrayRegion(value, 0, value_length, reinterpret_cast(value_buf.data())); + if (env->ExceptionCheck()) return; CHECK_ADBC_ERROR(AdbcStatementSetOptionBytes(stmt, key_str.value, value_buf.data(), value_buf.size(), &error_guard.value), error_guard.value); @@ -997,11 +1004,13 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetObjects( const char** c_table_types = nullptr; if (table_types != nullptr) { jsize len = env->GetArrayLength(table_types); + if (env->ExceptionCheck()) return nullptr; table_type_strings.reserve(len); table_type_ptrs.reserve(len + 1); for (jsize i = 0; i < len; i++) { auto element = reinterpret_cast(env->GetObjectArrayElement(table_types, i)); + if (env->ExceptionCheck()) return nullptr; table_type_strings.push_back(GetJniString(env, element)); table_type_ptrs.push_back(table_type_strings.back().c_str()); } @@ -1040,9 +1049,11 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetInfo( std::vector info_codes_vec; if (info_codes != nullptr) { jsize len = env->GetArrayLength(info_codes); + if (env->ExceptionCheck()) return nullptr; info_codes_vec.resize(len); env->GetIntArrayRegion(info_codes, 0, len, reinterpret_cast(info_codes_vec.data())); + if (env->ExceptionCheck()) return nullptr; c_info_codes = info_codes_vec.data(); info_codes_length = static_cast(len); } @@ -1133,8 +1144,10 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionGetOptionBytes( return nullptr; } jbyteArray result = env->NewByteArray(static_cast(length)); + if (result == nullptr || env->ExceptionCheck()) return nullptr; env->SetByteArrayRegion(result, 0, static_cast(length), reinterpret_cast(buf.data())); + if (env->ExceptionCheck()) return nullptr; return result; } @@ -1212,9 +1225,11 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_connectionSetOptionBytes( try { JniStringView key_str(env, key); jsize value_length = env->GetArrayLength(value); + if (env->ExceptionCheck()) return; std::vector value_buf(static_cast(value_length)); env->GetByteArrayRegion(value, 0, value_length, reinterpret_cast(value_buf.data())); + if (env->ExceptionCheck()) return; CHECK_ADBC_ERROR(AdbcConnectionSetOptionBytes(conn, key_str.value, value_buf.data(), value_buf.size(), &error_guard.value), error_guard.value); @@ -1395,8 +1410,10 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseGetOptionBytes( return nullptr; } jbyteArray result = env->NewByteArray(static_cast(length)); + if (result == nullptr || env->ExceptionCheck()) return nullptr; env->SetByteArrayRegion(result, 0, static_cast(length), reinterpret_cast(buf.data())); + if (env->ExceptionCheck()) return nullptr; return result; } @@ -1474,9 +1491,11 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_databaseSetOptionBytes( try { JniStringView key_str(env, key); jsize value_length = env->GetArrayLength(value); + if (env->ExceptionCheck()) return; std::vector value_buf(static_cast(value_length)); env->GetByteArrayRegion(value, 0, value_length, reinterpret_cast(value_buf.data())); + if (env->ExceptionCheck()) return; CHECK_ADBC_ERROR(AdbcDatabaseSetOptionBytes(db, key_str.value, value_buf.data(), value_buf.size(), &error_guard.value), error_guard.value);