From d5367cc0d1c4835f21b637f53daf18af553db9b4 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 6af1a247c3..4cec83d50f 100644 --- a/java/driver/jni/src/main/cpp/jni_wrapper.cc +++ b/java/driver/jni/src/main/cpp/jni_wrapper.cc @@ -337,6 +337,7 @@ Java_org_apache_arrow_adbc_driver_jni_impl_NativeAdbc_openDatabase( error_guard.error); const jsize num_params = env->GetArrayLength(parameters); + if (env->ExceptionCheck()) return nullptr; if (num_params % 2 != 0) { throw AdbcException{ .code = ADBC_STATUS_INVALID_ARGUMENT, @@ -346,8 +347,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); @@ -728,8 +731,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; } @@ -807,9 +812,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.error), error_guard.error); @@ -905,11 +912,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()); } @@ -948,9 +957,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); } @@ -1041,8 +1052,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; } @@ -1120,9 +1133,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.error), error_guard.error); @@ -1303,8 +1318,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; } @@ -1382,9 +1399,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.error), error_guard.error);