This is an automated email from the ASF dual-hosted git repository.

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new a6e0ac5ad5a branch-3.1:[fix](jni)add ExceptionCheck for safe jni call. 
#51913 (#53343)
a6e0ac5ad5a is described below

commit a6e0ac5ad5a182004145148cfa6059861bd80a46
Author: daidai <[email protected]>
AuthorDate: Thu Jul 17 11:28:39 2025 +0800

    branch-3.1:[fix](jni)add ExceptionCheck for safe jni call. #51913 (#53343)
    
    cherry picked from #51913
---
 be/src/util/jni-util.cpp                           | 65 ++++++++++++++++------
 be/src/util/jni-util.h                             |  6 +-
 .../aggregate_function_java_udaf.h                 | 12 ++--
 .../format/table/trino_connector_jni_reader.cpp    |  3 +
 be/src/vec/exec/jni_connector.cpp                  | 46 +++++++++++----
 be/src/vec/exec/jni_connector.h                    | 24 ++++----
 be/src/vec/exec/vjdbc_connector.cpp                | 48 ++++++++++------
 be/src/vec/exec/vjdbc_connector.h                  |  6 +-
 .../exprs/table_function/udf_table_function.cpp    | 12 ++--
 .../vec/exprs/table_function/udf_table_function.h  |  2 +
 be/src/vec/functions/function_java_udf.cpp         | 14 +++--
 be/src/vec/functions/function_java_udf.h           |  2 +
 regression-test/pipeline/external/conf/be.conf     |  4 +-
 regression-test/pipeline/p0/conf/be.conf           |  4 +-
 14 files changed, 170 insertions(+), 78 deletions(-)

diff --git a/be/src/util/jni-util.cpp b/be/src/util/jni-util.cpp
index d0b24415eb6..47675ba1714 100644
--- a/be/src/util/jni-util.cpp
+++ b/be/src/util/jni-util.cpp
@@ -315,66 +315,83 @@ Status JniUtil::GetJniExceptionMsg(JNIEnv* env, bool 
log_stack, const string& pr
     return Status::RuntimeError("{}{}", prefix, msg_str_guard.get());
 }
 
-jobject JniUtil::convert_to_java_map(JNIEnv* env, const std::map<std::string, 
std::string>& map) {
-    //TODO: ADD EXCEPTION CHECK.
+Status JniUtil::convert_to_java_map(JNIEnv* env, const std::map<std::string, 
std::string>& map,
+                                    jobject* hashmap_object) {
     jclass hashmap_class = env->FindClass("java/util/HashMap");
+    RETURN_ERROR_IF_EXC(env);
     jmethodID hashmap_constructor = env->GetMethodID(hashmap_class, "<init>", 
"(I)V");
-    jobject hashmap_object = env->NewObject(hashmap_class, 
hashmap_constructor, map.size());
+    RETURN_ERROR_IF_EXC(env);
+    jobject hashmap_local_object = env->NewObject(hashmap_class, 
hashmap_constructor, map.size());
+    RETURN_ERROR_IF_EXC(env);
     jmethodID hashmap_put = env->GetMethodID(
             hashmap_class, "put", 
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    RETURN_ERROR_IF_EXC(env);
     for (const auto& it : map) {
         jstring key = env->NewStringUTF(it.first.c_str());
         jstring value = env->NewStringUTF(it.second.c_str());
-        env->CallObjectMethod(hashmap_object, hashmap_put, key, value);
+        env->CallObjectMethod(hashmap_local_object, hashmap_put, key, value);
+        RETURN_ERROR_IF_EXC(env);
         env->DeleteLocalRef(key);
         env->DeleteLocalRef(value);
     }
     env->DeleteLocalRef(hashmap_class);
-    return hashmap_object;
+    RETURN_IF_ERROR(LocalToGlobalRef(env, hashmap_local_object, 
hashmap_object));
+    return Status::OK();
 }
 
-std::map<std::string, std::string> JniUtil::convert_to_cpp_map(JNIEnv* env, 
jobject map) {
-    std::map<std::string, std::string> resultMap;
-
+Status JniUtil::convert_to_cpp_map(JNIEnv* env, jobject map,
+                                   std::map<std::string, std::string>* 
resultMap) {
     // Get the class and method ID of the java.util.Map interface
     jclass mapClass = env->FindClass("java/util/Map");
+    RETURN_ERROR_IF_EXC(env);
     jmethodID entrySetMethod = env->GetMethodID(mapClass, "entrySet", 
"()Ljava/util/Set;");
 
     // Get the class and method ID of the java.util.Set interface
     jclass setClass = env->FindClass("java/util/Set");
+    RETURN_ERROR_IF_EXC(env);
     jmethodID iteratorSetMethod = env->GetMethodID(setClass, "iterator", 
"()Ljava/util/Iterator;");
 
     // Get the class and method ID of the java.util.Iterator interface
     jclass iteratorClass = env->FindClass("java/util/Iterator");
+    RETURN_ERROR_IF_EXC(env);
     jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext", 
"()Z");
     jmethodID nextMethod = env->GetMethodID(iteratorClass, "next", 
"()Ljava/lang/Object;");
 
     // Get the class and method ID of the java.util.Map.Entry interface
     jclass entryClass = env->FindClass("java/util/Map$Entry");
+    RETURN_ERROR_IF_EXC(env);
     jmethodID getKeyMethod = env->GetMethodID(entryClass, "getKey", 
"()Ljava/lang/Object;");
     jmethodID getValueMethod = env->GetMethodID(entryClass, "getValue", 
"()Ljava/lang/Object;");
 
     // Call the entrySet method to get the set of key-value pairs
     jobject entrySet = env->CallObjectMethod(map, entrySetMethod);
+    RETURN_ERROR_IF_EXC(env);
 
     // Call the iterator method on the set to iterate over the key-value pairs
     jobject iteratorSet = env->CallObjectMethod(entrySet, iteratorSetMethod);
+    RETURN_ERROR_IF_EXC(env);
 
     // Iterate over the key-value pairs
     while (env->CallBooleanMethod(iteratorSet, hasNextMethod)) {
+        RETURN_ERROR_IF_EXC(env);
+
         // Get the current entry
         jobject entry = env->CallObjectMethod(iteratorSet, nextMethod);
+        RETURN_ERROR_IF_EXC(env);
 
         // Get the key and value from the entry
         jobject javaKey = env->CallObjectMethod(entry, getKeyMethod);
+        RETURN_ERROR_IF_EXC(env);
+
         jobject javaValue = env->CallObjectMethod(entry, getValueMethod);
+        RETURN_ERROR_IF_EXC(env);
 
         // Convert the key and value to C++ strings
         const char* key = 
env->GetStringUTFChars(static_cast<jstring>(javaKey), nullptr);
         const char* value = 
env->GetStringUTFChars(static_cast<jstring>(javaValue), nullptr);
 
         // Store the key-value pair in the map
-        resultMap[key] = value;
+        (*resultMap)[key] = value;
 
         // Release the string references
         env->ReleaseStringUTFChars(static_cast<jstring>(javaKey), key);
@@ -394,7 +411,7 @@ std::map<std::string, std::string> 
JniUtil::convert_to_cpp_map(JNIEnv* env, jobj
     env->DeleteLocalRef(iteratorClass);
     env->DeleteLocalRef(entryClass);
 
-    return resultMap;
+    return Status::OK();
 }
 
 Status JniUtil::GetGlobalClassRef(JNIEnv* env, const char* class_str, jclass* 
class_ref) {
@@ -443,13 +460,12 @@ Status JniUtil::init_jni_scanner_loader(JNIEnv* env) {
             env->GetMethodID(jni_scanner_loader_cls, "loadAllScannerJars", 
"()V");
     RETURN_ERROR_IF_EXC(env);
 
-    jni_scanner_loader_obj_ =
+    jobject jni_scanner_loader_local_obj =
             env->NewObject(jni_scanner_loader_cls, 
jni_scanner_loader_constructor);
+    jni_scanner_loader_obj_ = env->NewGlobalRef(jni_scanner_loader_local_obj);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteLocalRef(jni_scanner_loader_local_obj);
     RETURN_ERROR_IF_EXC(env);
-    if (jni_scanner_loader_obj_ == NULL) {
-        if (env->ExceptionOccurred()) env->ExceptionDescribe();
-        return Status::InternalError("Failed to create ScannerLoader object.");
-    }
     env->CallVoidMethod(jni_scanner_loader_obj_, load_jni_scanner);
     RETURN_ERROR_IF_EXC(env);
 
@@ -468,8 +484,12 @@ Status JniUtil::init_jni_scanner_loader(JNIEnv* env) {
 Status JniUtil::clean_udf_class_load_cache(const std::string& 
function_signature) {
     JNIEnv* env = nullptr;
     RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
+    jstring function_signature_jstr = 
env->NewStringUTF(function_signature.c_str());
+    RETURN_ERROR_IF_EXC(env);
     env->CallVoidMethod(jni_scanner_loader_obj_, _clean_udf_cache_method_id,
-                        env->NewStringUTF(function_signature.c_str()));
+                        function_signature_jstr);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteLocalRef(function_signature_jstr);
     RETURN_ERROR_IF_EXC(env);
     return Status::OK();
 }
@@ -477,11 +497,20 @@ Status JniUtil::clean_udf_class_load_cache(const 
std::string& function_signature
 Status JniUtil::get_jni_scanner_class(JNIEnv* env, const char* classname,
                                       jclass* jni_scanner_class) {
     // Get JNI scanner class by class name;
-    jobject loaded_class_obj = env->CallObjectMethod(
-            jni_scanner_loader_obj_, jni_scanner_loader_method_, 
env->NewStringUTF(classname));
+    jstring class_name_str = env->NewStringUTF(classname);
     RETURN_ERROR_IF_EXC(env);
+
+    jobject loaded_class_obj = env->CallObjectMethod(jni_scanner_loader_obj_,
+                                                     
jni_scanner_loader_method_, class_name_str);
+    RETURN_ERROR_IF_EXC(env);
+
     *jni_scanner_class = 
reinterpret_cast<jclass>(env->NewGlobalRef(loaded_class_obj));
     RETURN_ERROR_IF_EXC(env);
+
+    env->DeleteLocalRef(loaded_class_obj);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteLocalRef(class_name_str);
+    RETURN_ERROR_IF_EXC(env);
     return Status::OK();
 }
 
diff --git a/be/src/util/jni-util.h b/be/src/util/jni-util.h
index df332951afe..1a2e751b69e 100644
--- a/be/src/util/jni-util.h
+++ b/be/src/util/jni-util.h
@@ -101,8 +101,10 @@ public:
         return INITIAL_RESERVED_BUFFER_SIZE << n;
     }
     static Status get_jni_scanner_class(JNIEnv* env, const char* classname, 
jclass* loaded_class);
-    static jobject convert_to_java_map(JNIEnv* env, const 
std::map<std::string, std::string>& map);
-    static std::map<std::string, std::string> convert_to_cpp_map(JNIEnv* env, 
jobject map);
+    static Status convert_to_java_map(JNIEnv* env, const std::map<std::string, 
std::string>& map,
+                                      jobject* hashmap_object);
+    static Status convert_to_cpp_map(JNIEnv* env, jobject map,
+                                     std::map<std::string, std::string>* 
resultMap);
     static size_t get_max_jni_heap_memory_size();
     static Status clean_udf_class_load_cache(const std::string& 
function_signature);
 
diff --git a/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h 
b/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
index 366b242927a..a215a3a7f8c 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
+++ b/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
@@ -132,11 +132,13 @@ public:
                 {"meta_address", std::to_string((long)input_table.get())},
                 {"required_fields", input_table_schema.first},
                 {"columns_types", input_table_schema.second}};
-        jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+        jobject input_map = nullptr;
+        RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params, 
&input_map));
         // invoke add batch
         env->CallObjectMethod(executor_obj, executor_add_batch_id, 
is_single_place, row_num_start,
                               row_num_end, places_address, place_offset, 
input_map);
-        env->DeleteLocalRef(input_map);
+        RETURN_ERROR_IF_EXC(env);
+        env->DeleteGlobalRef(input_map);
         return JniUtil::GetJniExceptionMsg(env);
     }
 
@@ -200,10 +202,12 @@ public:
         std::map<String, String> output_params = {{"is_nullable", 
output_nullable},
                                                   {"required_fields", 
output_table_schema.first},
                                                   {"columns_types", 
output_table_schema.second}};
-        jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+        jobject output_map = nullptr;
+        RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params, 
&output_map));
         long output_address =
                 env->CallLongMethod(executor_obj, executor_get_value_id, 
place, output_map);
-        env->DeleteLocalRef(output_map);
+        RETURN_ERROR_IF_EXC(env);
+        env->DeleteGlobalRef(output_map);
         RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
         return JniConnector::fill_block(&output_block, {0}, output_address);
     }
diff --git a/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp 
b/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
index 8c7f5e5440c..f4ebd432f67 100644
--- a/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
+++ b/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
@@ -107,9 +107,12 @@ Status TrinoConnectorJniReader::_set_spi_plugins_dir() {
     // call: setPluginsDir(String pluginsDir)
     jstring trino_connector_plugin_path =
             
env->NewStringUTF(doris::config::trino_connector_plugin_dir.c_str());
+    RETURN_ERROR_IF_EXC(env);
     env->CallStaticVoidMethod(plugin_loader_cls, set_plugins_dir_method,
                               trino_connector_plugin_path);
     RETURN_ERROR_IF_EXC(env);
+    env->DeleteLocalRef(trino_connector_plugin_path);
+    RETURN_ERROR_IF_EXC(env);
 
     return Status::OK();
 }
diff --git a/be/src/vec/exec/jni_connector.cpp 
b/be/src/vec/exec/jni_connector.cpp
index 47c84b72c6e..3030c2bde57 100644
--- a/be/src/vec/exec/jni_connector.cpp
+++ b/be/src/vec/exec/jni_connector.cpp
@@ -149,27 +149,36 @@ Status JniConnector::get_next_block(Block* block, size_t* 
read_rows, bool* eof)
 Status JniConnector::get_table_schema(std::string& table_schema_str) {
     JNIEnv* env = nullptr;
     RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
-    // Call org.apache.doris.jni.JniScanner#getTableSchema
-    // return the TableSchema information
+
     jstring jstr = (jstring)env->CallObjectMethod(_jni_scanner_obj, 
_jni_scanner_get_table_schema);
     RETURN_ERROR_IF_EXC(env);
-    table_schema_str = env->GetStringUTFChars(jstr, nullptr);
+
+    const char* cstr = env->GetStringUTFChars(jstr, nullptr);
     RETURN_ERROR_IF_EXC(env);
+
+    if (cstr == nullptr) {
+        return Status::RuntimeError("GetStringUTFChars returned null");
+    }
+
+    table_schema_str = std::string(cstr); // copy to std::string
+    env->ReleaseStringUTFChars(jstr, cstr);
+    env->DeleteLocalRef(jstr);
     return Status::OK();
 }
 
-std::map<std::string, std::string> JniConnector::get_statistics(JNIEnv* env) {
+Status JniConnector::get_statistics(JNIEnv* env, std::map<std::string, 
std::string>* result) {
+    result->clear();
     jobject metrics = env->CallObjectMethod(_jni_scanner_obj, 
_jni_scanner_get_statistics);
     jthrowable exc = (env)->ExceptionOccurred();
     if (exc != nullptr) {
         LOG(WARNING) << "get_statistics has error: "
                      << JniUtil::GetJniExceptionMsg(env).to_string();
         env->DeleteLocalRef(metrics);
-        return std::map<std::string, std::string> {};
+        return Status::OK();
     }
-    std::map<std::string, std::string> result = 
JniUtil::convert_to_cpp_map(env, metrics);
+    RETURN_IF_ERROR(JniUtil::convert_to_cpp_map(env, metrics, result));
     env->DeleteLocalRef(metrics);
-    return result;
+    return Status::OK();
 }
 
 Status JniConnector::close() {
@@ -180,12 +189,15 @@ Status JniConnector::close() {
             COUNTER_UPDATE(_open_scanner_time, _jni_scanner_open_watcher);
             COUNTER_UPDATE(_fill_block_time, _fill_block_watcher);
 
+            RETURN_ERROR_IF_EXC(env);
             int64_t _append = (int64_t)env->CallLongMethod(_jni_scanner_obj,
                                                            
_jni_scanner_get_append_data_time);
+            RETURN_ERROR_IF_EXC(env);
             COUNTER_UPDATE(_java_append_data_time, _append);
 
             int64_t _create = (int64_t)env->CallLongMethod(
                     _jni_scanner_obj, 
_jni_scanner_get_create_vector_table_time);
+            RETURN_ERROR_IF_EXC(env);
             COUNTER_UPDATE(_java_create_vector_table_time, _create);
 
             COUNTER_UPDATE(_java_scan_time, _java_scan_watcher - _append - 
_create);
@@ -197,8 +209,11 @@ Status JniConnector::close() {
             // _fill_block may be failed and returned, we should release table 
in close.
             // org.apache.doris.common.jni.JniScanner#releaseTable is 
idempotent
             env->CallVoidMethod(_jni_scanner_obj, _jni_scanner_release_table);
+            RETURN_ERROR_IF_EXC(env);
             env->CallVoidMethod(_jni_scanner_obj, _jni_scanner_close);
+            RETURN_ERROR_IF_EXC(env);
             env->DeleteGlobalRef(_jni_scanner_obj);
+            RETURN_ERROR_IF_EXC(env);
         }
         if (_jni_scanner_cls != nullptr) {
             // _jni_scanner_cls may be null if init connector failed
@@ -218,7 +233,7 @@ Status JniConnector::close() {
 Status JniConnector::_init_jni_scanner(JNIEnv* env, int batch_size) {
     RETURN_IF_ERROR(
             JniUtil::get_jni_scanner_class(env, _connector_class.c_str(), 
&_jni_scanner_cls));
-    if (_jni_scanner_cls == nullptr) {
+    if (_jni_scanner_cls == nullptr) [[unlikely]] {
         if (env->ExceptionOccurred()) {
             env->ExceptionDescribe();
         }
@@ -231,14 +246,15 @@ Status JniConnector::_init_jni_scanner(JNIEnv* env, int 
batch_size) {
     RETURN_ERROR_IF_EXC(env);
 
     // prepare constructor parameters
-    jobject hashmap_object = JniUtil::convert_to_java_map(env, 
_scanner_params);
+    jobject hashmap_object;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, _scanner_params, 
&hashmap_object));
     jobject jni_scanner_obj =
             env->NewObject(_jni_scanner_cls, scanner_constructor, batch_size, 
hashmap_object);
 
     RETURN_ERROR_IF_EXC(env);
 
     // prepare constructor parameters
-    env->DeleteLocalRef(hashmap_object);
+    env->DeleteGlobalRef(hashmap_object);
     RETURN_ERROR_IF_EXC(env);
 
     _jni_scanner_open = env->GetMethodID(_jni_scanner_cls, "open", "()V");
@@ -259,6 +275,7 @@ Status JniConnector::_init_jni_scanner(JNIEnv* env, int 
batch_size) {
     _jni_scanner_release_table = env->GetMethodID(_jni_scanner_cls, 
"releaseTable", "()V");
     _jni_scanner_get_statistics =
             env->GetMethodID(_jni_scanner_cls, "getStatistics", 
"()Ljava/util/Map;");
+    RETURN_ERROR_IF_EXC(env);
     RETURN_IF_ERROR(JniUtil::LocalToGlobalRef(env, jni_scanner_obj, 
&_jni_scanner_obj));
     env->DeleteLocalRef(jni_scanner_obj);
     RETURN_ERROR_IF_EXC(env);
@@ -781,7 +798,14 @@ void JniConnector::_collect_profile_before_close() {
             return;
         }
         // update scanner metrics
-        for (const auto& metric : get_statistics(env)) {
+        std::map<std::string, std::string> statistics_result;
+        st = get_statistics(env, &statistics_result);
+        if (!st) {
+            LOG(WARNING) << "failed to get_statistics when collect profile: " 
<< st;
+            return;
+        }
+
+        for (const auto& metric : statistics_result) {
             std::vector<std::string> type_and_name = split(metric.first, ":");
             if (type_and_name.size() != 2) {
                 LOG(WARNING) << "Name of JNI Scanner metric should be pattern 
like "
diff --git a/be/src/vec/exec/jni_connector.h b/be/src/vec/exec/jni_connector.h
index 89168b5a551..db35d14bd26 100644
--- a/be/src/vec/exec/jni_connector.h
+++ b/be/src/vec/exec/jni_connector.h
@@ -242,7 +242,7 @@ public:
     /**
      * Get performance metrics from java scanner
      */
-    std::map<std::string, std::string> get_statistics(JNIEnv* env);
+    Status get_statistics(JNIEnv* env, std::map<std::string, std::string>* 
result);
 
     /**
      * Call java side function JniScanner.getTableSchema.
@@ -305,17 +305,17 @@ private:
 
     bool _closed = false;
     bool _scanner_opened = false;
-    jclass _jni_scanner_cls;
-    jobject _jni_scanner_obj;
-    jmethodID _jni_scanner_open;
-    jmethodID _jni_scanner_get_append_data_time;
-    jmethodID _jni_scanner_get_create_vector_table_time;
-    jmethodID _jni_scanner_get_next_batch;
-    jmethodID _jni_scanner_get_table_schema;
-    jmethodID _jni_scanner_close;
-    jmethodID _jni_scanner_release_column;
-    jmethodID _jni_scanner_release_table;
-    jmethodID _jni_scanner_get_statistics;
+    jclass _jni_scanner_cls = nullptr;
+    jobject _jni_scanner_obj = nullptr;
+    jmethodID _jni_scanner_open = nullptr;
+    jmethodID _jni_scanner_get_append_data_time = nullptr;
+    jmethodID _jni_scanner_get_create_vector_table_time = nullptr;
+    jmethodID _jni_scanner_get_next_batch = nullptr;
+    jmethodID _jni_scanner_get_table_schema = nullptr;
+    jmethodID _jni_scanner_close = nullptr;
+    jmethodID _jni_scanner_release_column = nullptr;
+    jmethodID _jni_scanner_release_table = nullptr;
+    jmethodID _jni_scanner_get_statistics = nullptr;
 
     TableMetaAddress _table_meta;
 
diff --git a/be/src/vec/exec/vjdbc_connector.cpp 
b/be/src/vec/exec/vjdbc_connector.cpp
index f3f4b4d8a1c..a8d8d6fd210 100644
--- a/be/src/vec/exec/vjdbc_connector.cpp
+++ b/be/src/vec/exec/vjdbc_connector.cpp
@@ -77,10 +77,13 @@ Status JdbcConnector::close(Status /*unused*/) {
     JNIEnv* env = nullptr;
     RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
     env->CallNonvirtualVoidMethod(_executor_obj, _executor_clazz, 
_executor_close_id);
+    RETURN_ERROR_IF_EXC(env);
     env->DeleteGlobalRef(_executor_factory_clazz);
+    RETURN_ERROR_IF_EXC(env);
     env->DeleteGlobalRef(_executor_clazz);
     RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
     env->DeleteGlobalRef(_executor_obj);
+    RETURN_ERROR_IF_EXC(env);
     return Status::OK();
 }
 
@@ -100,7 +103,8 @@ Status JdbcConnector::open(RuntimeState* state, bool read) {
             GetStaticMethodID(_executor_factory_clazz, "getExecutorClass",
                               
"(Lorg/apache/doris/thrift/TOdbcTableType;)Ljava/lang/String;"));
 
-    jobject jtable_type = _get_java_table_type(env, _conn_param.table_type);
+    jobject jtable_type = nullptr;
+    RETURN_IF_ERROR(_get_java_table_type(env, _conn_param.table_type, 
&jtable_type));
 
     JNI_CALL_METHOD_CHECK_EXCEPTION_DELETE_REF(
             jobject, executor_name, env,
@@ -110,8 +114,11 @@ Status JdbcConnector::open(RuntimeState* state, bool read) 
{
     const char* executor_name_str = 
env->GetStringUTFChars((jstring)executor_name, nullptr);
 
     RETURN_IF_ERROR(JniUtil::get_jni_scanner_class(env, executor_name_str, 
&_executor_clazz));
-    env->DeleteLocalRef(jtable_type);
+
+    env->DeleteGlobalRef(jtable_type);
+    RETURN_ERROR_IF_EXC(env);
     env->ReleaseStringUTFChars((jstring)executor_name, executor_name_str);
+    RETURN_ERROR_IF_EXC(env);
 
 #undef GET_BASIC_JAVA_CLAZZ
     RETURN_IF_ERROR(_register_func_id(env));
@@ -236,6 +243,7 @@ Status JdbcConnector::get_next(bool* eos, Block* block, int 
batch_size) {
         SCOPED_RAW_TIMER(&_jdbc_statistic._has_next_timer); // Timer for 
hasNext check
         has_next = env->CallNonvirtualBooleanMethod(_executor_obj, 
_executor_clazz,
                                                     _executor_has_next_id);
+        RETURN_ERROR_IF_EXC(env);
     } // _has_next_timer stops here
 
     if (has_next != JNI_TRUE) {
@@ -248,10 +256,10 @@ Status JdbcConnector::get_next(bool* eos, Block* block, 
int batch_size) {
     auto column_size = _tuple_desc->slots().size();
     auto slots = _tuple_desc->slots();
 
-    jobject map;
+    jobject map = nullptr;
     {
         SCOPED_RAW_TIMER(&_jdbc_statistic._prepare_params_timer); // Timer for 
preparing params
-        map = _get_reader_params(block, env, column_size);
+        RETURN_IF_ERROR(_get_reader_params(block, env, column_size, &map));
     } // _prepare_params_timer stops here
 
     long address = 0;
@@ -264,7 +272,8 @@ Status JdbcConnector::get_next(bool* eos, Block* block, int 
batch_size) {
     } // _get_block_address_timer stops here
 
     RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
-    env->DeleteLocalRef(map);
+    env->DeleteGlobalRef(map);
+    RETURN_ERROR_IF_EXC(env);
 
     std::vector<size_t> all_columns;
     for (size_t i = 0; i < column_size; ++i) {
@@ -315,10 +324,12 @@ Status JdbcConnector::exec_stmt_write(Block* block, const 
VExprContextSPtrs& out
     std::map<String, String> write_params = {{"meta_address", 
std::to_string(meta_address)},
                                              {"required_fields", 
table_schema.first},
                                              {"columns_types", 
table_schema.second}};
-    jobject hashmap_object = JniUtil::convert_to_java_map(env, write_params);
+    jobject hashmap_object = nullptr;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, write_params, 
&hashmap_object));
+
     env->CallNonvirtualIntMethod(_executor_obj, _executor_clazz, 
_executor_stmt_write_id,
                                  hashmap_object);
-    env->DeleteLocalRef(hashmap_object);
+    env->DeleteGlobalRef(hashmap_object);
     RETURN_ERROR_IF_EXC(env);
     *num_rows_sent = block->rows();
     return Status::OK();
@@ -396,7 +407,8 @@ Status JdbcConnector::_register_func_id(JNIEnv* env) {
     return Status::OK();
 }
 
-jobject JdbcConnector::_get_reader_params(Block* block, JNIEnv* env, size_t 
column_size) {
+Status JdbcConnector::_get_reader_params(Block* block, JNIEnv* env, size_t 
column_size,
+                                         jobject* ans) {
     std::ostringstream columns_nullable;
     std::ostringstream columns_replace_string;
     std::ostringstream required_fields;
@@ -447,7 +459,7 @@ jobject JdbcConnector::_get_reader_params(Block* block, 
JNIEnv* env, size_t colu
                                               {"replace_string", 
columns_replace_string.str()},
                                               {"required_fields", 
required_fields.str()},
                                               {"columns_types", 
columns_types.str()}};
-    return JniUtil::convert_to_java_map(env, reader_params);
+    return JniUtil::convert_to_java_map(env, reader_params, ans);
 }
 
 Status JdbcConnector::_cast_string_to_special(Block* block, JNIEnv* env, 
size_t column_size) {
@@ -605,13 +617,17 @@ Status JdbcConnector::_cast_string_to_json(const 
SlotDescriptor* slot_desc, Bloc
     return Status::OK();
 }
 
-jobject JdbcConnector::_get_java_table_type(JNIEnv* env, TOdbcTableType::type 
tableType) {
-    jclass enumClass = 
env->FindClass("org/apache/doris/thrift/TOdbcTableType");
-    jmethodID findByValueMethod = env->GetStaticMethodID(
-            enumClass, "findByValue", 
"(I)Lorg/apache/doris/thrift/TOdbcTableType;");
-    jobject javaEnumObj =
-            env->CallStaticObjectMethod(enumClass, findByValueMethod, 
static_cast<jint>(tableType));
-    return javaEnumObj;
+Status JdbcConnector::_get_java_table_type(JNIEnv* env, TOdbcTableType::type 
table_type,
+                                           jobject* java_enum_obj) {
+    jclass enum_class = 
env->FindClass("org/apache/doris/thrift/TOdbcTableType");
+    jmethodID find_by_value_method = env->GetStaticMethodID(
+            enum_class, "findByValue", 
"(I)Lorg/apache/doris/thrift/TOdbcTableType;");
+    jobject java_enum_local_obj = env->CallStaticObjectMethod(enum_class, 
find_by_value_method,
+                                                              
static_cast<jint>(table_type));
+    RETURN_ERROR_IF_EXC(env);
+    RETURN_IF_ERROR(JniUtil::LocalToGlobalRef(env, java_enum_local_obj, 
java_enum_obj));
+    env->DeleteLocalRef(java_enum_local_obj);
+    return Status::OK();
 }
 
 std::string JdbcConnector::_get_real_url(const std::string& url) {
diff --git a/be/src/vec/exec/vjdbc_connector.h 
b/be/src/vec/exec/vjdbc_connector.h
index a09d390dc7c..3505d830a36 100644
--- a/be/src/vec/exec/vjdbc_connector.h
+++ b/be/src/vec/exec/vjdbc_connector.h
@@ -127,7 +127,7 @@ protected:
 private:
     Status _register_func_id(JNIEnv* env);
 
-    jobject _get_reader_params(Block* block, JNIEnv* env, size_t column_size);
+    Status _get_reader_params(Block* block, JNIEnv* env, size_t column_size, 
jobject* ans);
 
     Status _cast_string_to_special(Block* block, JNIEnv* env, size_t 
column_size);
     Status _cast_string_to_hll(const SlotDescriptor* slot_desc, Block* block, 
int column_index,
@@ -136,7 +136,9 @@ private:
                                   int rows);
     Status _cast_string_to_json(const SlotDescriptor* slot_desc, Block* block, 
int column_index,
                                 int rows);
-    jobject _get_java_table_type(JNIEnv* env, TOdbcTableType::type tableType);
+
+    Status _get_java_table_type(JNIEnv* env, TOdbcTableType::type table_type,
+                                jobject* java_enum_obj);
 
     std::string _get_real_url(const std::string& url);
 
diff --git a/be/src/vec/exprs/table_function/udf_table_function.cpp 
b/be/src/vec/exprs/table_function/udf_table_function.cpp
index bb794737a3d..0a51cd6a54d 100644
--- a/be/src/vec/exprs/table_function/udf_table_function.cpp
+++ b/be/src/vec/exprs/table_function/udf_table_function.cpp
@@ -115,7 +115,8 @@ Status UDFTableFunction::process_init(Block* block, 
RuntimeState* state) {
             {"required_fields", input_table_schema.first},
             {"columns_types", input_table_schema.second}};
 
-    jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+    jobject input_map = nullptr;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params, 
&input_map));
     _array_result_column = _return_type->create_column();
     _result_column_idx = block->columns();
     block->insert({_array_result_column, _return_type, "res"});
@@ -125,13 +126,16 @@ Status UDFTableFunction::process_init(Block* block, 
RuntimeState* state) {
                                               {"required_fields", 
output_table_schema.first},
                                               {"columns_types", 
output_table_schema.second}};
 
-    jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+    jobject output_map = nullptr;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params, 
&output_map));
     DCHECK(_jni_ctx != nullptr);
     DCHECK(_jni_ctx->executor != nullptr);
     long output_address = env->CallLongMethod(_jni_ctx->executor, 
_jni_ctx->executor_evaluate_id,
                                               input_map, output_map);
-    env->DeleteLocalRef(input_map);
-    env->DeleteLocalRef(output_map);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteGlobalRef(input_map);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteGlobalRef(output_map);
     RETURN_ERROR_IF_EXC(env);
     RETURN_IF_ERROR(JniConnector::fill_block(block, {_result_column_idx}, 
output_address));
     block->erase(_result_column_idx);
diff --git a/be/src/vec/exprs/table_function/udf_table_function.h 
b/be/src/vec/exprs/table_function/udf_table_function.h
index b0937198467..88427d7a257 100644
--- a/be/src/vec/exprs/table_function/udf_table_function.h
+++ b/be/src/vec/exprs/table_function/udf_table_function.h
@@ -77,7 +77,9 @@ private:
                 return status;
             }
             env->CallNonvirtualVoidMethodA(executor, executor_cl, 
executor_close_id, nullptr);
+            RETURN_ERROR_IF_EXC(env);
             env->DeleteGlobalRef(executor);
+            RETURN_ERROR_IF_EXC(env);
             env->DeleteGlobalRef(executor_cl);
             RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
             is_closed = true;
diff --git a/be/src/vec/functions/function_java_udf.cpp 
b/be/src/vec/functions/function_java_udf.cpp
index fd55cdaddb2..5136081cee6 100644
--- a/be/src/vec/functions/function_java_udf.cpp
+++ b/be/src/vec/functions/function_java_udf.cpp
@@ -105,19 +105,23 @@ Status JavaFunctionCall::execute_impl(FunctionContext* 
context, Block& block,
             {"meta_address", std::to_string((long)input_table.get())},
             {"required_fields", input_table_schema.first},
             {"columns_types", input_table_schema.second}};
-    jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+    jobject input_map = nullptr;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params, 
&input_map));
     auto output_table_schema = JniConnector::parse_table_schema(&block, 
{result}, true);
     std::string output_nullable =
             block.get_by_position(result).type->is_nullable() ? "true" : 
"false";
     std::map<String, String> output_params = {{"is_nullable", output_nullable},
                                               {"required_fields", 
output_table_schema.first},
                                               {"columns_types", 
output_table_schema.second}};
-    jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+    jobject output_map = nullptr;
+    RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params, 
&output_map));
     long output_address = env->CallLongMethod(jni_ctx->executor, 
jni_ctx->executor_evaluate_id,
                                               input_map, output_map);
-    env->DeleteLocalRef(input_map);
-    env->DeleteLocalRef(output_map);
-    RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteGlobalRef(input_map);
+    RETURN_ERROR_IF_EXC(env);
+    env->DeleteGlobalRef(output_map);
+    RETURN_ERROR_IF_EXC(env);
     return JniConnector::fill_block(&block, {result}, output_address);
 }
 
diff --git a/be/src/vec/functions/function_java_udf.h 
b/be/src/vec/functions/function_java_udf.h
index e35fc67881a..4c358c71bc6 100644
--- a/be/src/vec/functions/function_java_udf.h
+++ b/be/src/vec/functions/function_java_udf.h
@@ -144,7 +144,9 @@ private:
                 return status;
             }
             env->CallNonvirtualVoidMethodA(executor, executor_cl, 
executor_close_id, nullptr);
+            RETURN_ERROR_IF_EXC(env);
             env->DeleteGlobalRef(executor);
+            RETURN_ERROR_IF_EXC(env);
             env->DeleteGlobalRef(executor_cl);
             RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
             is_closed = true;
diff --git a/regression-test/pipeline/external/conf/be.conf 
b/regression-test/pipeline/external/conf/be.conf
index 61ba46218ec..4e38d398899 100644
--- a/regression-test/pipeline/external/conf/be.conf
+++ b/regression-test/pipeline/external/conf/be.conf
@@ -20,10 +20,10 @@ CUR_DATE=`date +%Y%m%d-%H%M%S`
 PPROF_TMPDIR="$DORIS_HOME/log/"
 
 # For jdk 8
-JAVA_OPTS="-Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log 
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
+JAVA_OPTS="-Xcheck:jni -Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log 
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
 
 # For jdk 17, this JAVA_OPTS will be used as default JVM options
-JAVA_OPTS_FOR_JDK_17="-Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log 
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
 -Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED 
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED 
--add-opens=java.base/java.io=AL [...]
+JAVA_OPTS_FOR_JDK_17="-Xcheck:jni -Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log 
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
 -Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED 
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.bas [...]
 
 # Set your own JAVA_HOME
 # JAVA_HOME=/path/to/jdk/
diff --git a/regression-test/pipeline/p0/conf/be.conf 
b/regression-test/pipeline/p0/conf/be.conf
index f73fa0dafdf..264fded9dc6 100644
--- a/regression-test/pipeline/p0/conf/be.conf
+++ b/regression-test/pipeline/p0/conf/be.conf
@@ -20,10 +20,10 @@ CUR_DATE=`date +%Y%m%d-%H%M%S`
 PPROF_TMPDIR="$DORIS_HOME/log/"
 
 # For jdk 8
-JAVA_OPTS="-Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log 
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
+JAVA_OPTS="-Xcheck:jni -Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log 
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M 
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
 
 # For jdk 17, this JAVA_OPTS will be used as default JVM options
-JAVA_OPTS_FOR_JDK_17="-Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log 
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
 -Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED 
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED 
--add-opens=java.base/java.io=AL [...]
+JAVA_OPTS_FOR_JDK_17="-Xcheck:jni -Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log 
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
 -Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true 
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives 
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED 
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.bas [...]
 
 # Set your own JAVA_HOME
 # JAVA_HOME=/path/to/jdk/


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to