From 5769c011bcd79575b8e2d6c14f838dcfc7c212f6 Mon Sep 17 00:00:00 2001 From: fanchao Date: Tue, 28 May 2024 11:34:52 +1000 Subject: [PATCH 1/6] Catch cxx exception --- libsession-util/src/main/cpp/contacts.cpp | 125 +++++++++++++--------- libsession-util/src/main/cpp/jni_utils.h | 53 +++++++++ 2 files changed, 126 insertions(+), 52 deletions(-) create mode 100644 libsession-util/src/main/cpp/jni_utils.h diff --git a/libsession-util/src/main/cpp/contacts.cpp b/libsession-util/src/main/cpp/contacts.cpp index 7d04904802..324d0f0ea8 100644 --- a/libsession-util/src/main/cpp/contacts.cpp +++ b/libsession-util/src/main/cpp/contacts.cpp @@ -1,100 +1,121 @@ #include "contacts.h" #include "util.h" +#include "jni_utils.h" extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_get(JNIEnv *env, jobject thiz, jstring session_id) { - std::lock_guard lock{util::util_mutex_}; - auto contacts = ptrToContacts(env, thiz); - auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); - auto contact = contacts->get(session_id_chars); - env->ReleaseStringUTFChars(session_id, session_id_chars); - if (!contact) return nullptr; - jobject j_contact = serialize_contact(env, contact.value()); - return j_contact; + // If an exception is thrown, return nullptr + return jni_utils::run_catching_cxx_exception_or( + [=]() -> jobject { + std::lock_guard lock{util::util_mutex_}; + auto contacts = ptrToContacts(env, thiz); + auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); + auto contact = contacts->get(session_id_chars); + env->ReleaseStringUTFChars(session_id, session_id_chars); + if (!contact) return nullptr; + jobject j_contact = serialize_contact(env, contact.value()); + return j_contact; + }, + [](const char *) -> jobject { return nullptr; } + ); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_getOrConstruct(JNIEnv *env, jobject thiz, jstring session_id) { - std::lock_guard lock{util::util_mutex_}; - auto contacts = ptrToContacts(env, thiz); - auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); - auto contact = contacts->get_or_construct(session_id_chars); - env->ReleaseStringUTFChars(session_id, session_id_chars); - return serialize_contact(env, contact); + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto contacts = ptrToContacts(env, thiz); + auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); + auto contact = contacts->get_or_construct(session_id_chars); + env->ReleaseStringUTFChars(session_id, session_id_chars); + return serialize_contact(env, contact); + }); } extern "C" JNIEXPORT void JNICALL Java_network_loki_messenger_libsession_1util_Contacts_set(JNIEnv *env, jobject thiz, jobject contact) { - std::lock_guard lock{util::util_mutex_}; - auto contacts = ptrToContacts(env, thiz); - auto contact_info = deserialize_contact(env, contact, contacts); - contacts->set(contact_info); + jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto contacts = ptrToContacts(env, thiz); + auto contact_info = deserialize_contact(env, contact, contacts); + contacts->set(contact_info); + }); } extern "C" JNIEXPORT jboolean JNICALL Java_network_loki_messenger_libsession_1util_Contacts_erase(JNIEnv *env, jobject thiz, jstring session_id) { - std::lock_guard lock{util::util_mutex_}; - auto contacts = ptrToContacts(env, thiz); - auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto contacts = ptrToContacts(env, thiz); + auto session_id_chars = env->GetStringUTFChars(session_id, nullptr); - bool result = contacts->erase(session_id_chars); - env->ReleaseStringUTFChars(session_id, session_id_chars); - return result; + bool result = contacts->erase(session_id_chars); + env->ReleaseStringUTFChars(session_id, session_id_chars); + return result; + }); } extern "C" #pragma clang diagnostic push #pragma ide diagnostic ignored "bugprone-reserved-identifier" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_00024Companion_newInstance___3B(JNIEnv *env, - jobject thiz, - jbyteArray ed25519_secret_key) { - std::lock_guard lock{util::util_mutex_}; - auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key); - auto* contacts = new session::config::Contacts(secret_key, std::nullopt); + jobject thiz, + jbyteArray ed25519_secret_key) { + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key); + auto *contacts = new session::config::Contacts(secret_key, std::nullopt); - jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts"); - jmethodID constructor = env->GetMethodID(contactsClass, "", "(J)V"); - jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast(contacts)); + jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts"); + jmethodID constructor = env->GetMethodID(contactsClass, "", "(J)V"); + jobject newConfig = env->NewObject(contactsClass, constructor, + reinterpret_cast(contacts)); - return newConfig; + return newConfig; + }); } extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_00024Companion_newInstance___3B_3B( JNIEnv *env, jobject thiz, jbyteArray ed25519_secret_key, jbyteArray initial_dump) { - std::lock_guard lock{util::util_mutex_}; - auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key); - auto initial = util::ustring_from_bytes(env, initial_dump); + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto secret_key = util::ustring_from_bytes(env, ed25519_secret_key); + auto initial = util::ustring_from_bytes(env, initial_dump); - auto* contacts = new session::config::Contacts(secret_key, initial); + auto *contacts = new session::config::Contacts(secret_key, initial); - jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts"); - jmethodID constructor = env->GetMethodID(contactsClass, "", "(J)V"); - jobject newConfig = env->NewObject(contactsClass, constructor, reinterpret_cast(contacts)); + jclass contactsClass = env->FindClass("network/loki/messenger/libsession_util/Contacts"); + jmethodID constructor = env->GetMethodID(contactsClass, "", "(J)V"); + jobject newConfig = env->NewObject(contactsClass, constructor, + reinterpret_cast(contacts)); - return newConfig; + return newConfig; + }); } #pragma clang diagnostic pop extern "C" JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_Contacts_all(JNIEnv *env, jobject thiz) { - std::lock_guard lock{util::util_mutex_}; - auto contacts = ptrToContacts(env, thiz); - jclass stack = env->FindClass("java/util/Stack"); - jmethodID init = env->GetMethodID(stack, "", "()V"); - jobject our_stack = env->NewObject(stack, init); - jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;"); - for (const auto& contact : *contacts) { - auto contact_obj = serialize_contact(env, contact); - env->CallObjectMethod(our_stack, push, contact_obj); - } - return our_stack; + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto contacts = ptrToContacts(env, thiz); + jclass stack = env->FindClass("java/util/Stack"); + jmethodID init = env->GetMethodID(stack, "", "()V"); + jobject our_stack = env->NewObject(stack, init); + jmethodID push = env->GetMethodID(stack, "push", "(Ljava/lang/Object;)Ljava/lang/Object;"); + for (const auto &contact: *contacts) { + auto contact_obj = serialize_contact(env, contact); + env->CallObjectMethod(our_stack, push, contact_obj); + } + return our_stack; + }); } \ No newline at end of file diff --git a/libsession-util/src/main/cpp/jni_utils.h b/libsession-util/src/main/cpp/jni_utils.h new file mode 100644 index 0000000000..959444407e --- /dev/null +++ b/libsession-util/src/main/cpp/jni_utils.h @@ -0,0 +1,53 @@ +#ifndef SESSION_ANDROID_JNI_UTILS_H +#define SESSION_ANDROID_JNI_UTILS_H + +#include +#include + +namespace jni_utils { + /** + * Run a C++ function and catch any exceptions, throwing a Java exception if one is caught, + * and returning a default-constructed value of the specified type. + * + * @tparam RetT The return type of the function + * @tparam Func The function type + * @param f The function to run + * @param fallbackRun The function to run if an exception is caught. The optional exception message reference will be passed to this function. + * @return The return value of the function, or the return value of the fallback function if an exception was caught + */ + template + RetT run_catching_cxx_exception_or(Func f, FallbackRun fallbackRun) { + try { + return f(); + } catch (const std::exception &e) { + return fallbackRun(e.what()); + } catch (...) { + return fallbackRun(nullptr); + } + } + + /** + * Run a C++ function and catch any exceptions, throwing a Java exception if one is caught. + * + * @tparam RetT The return type of the function + * @tparam Func The function type + * @param env The JNI environment + * @param f The function to run + * @return The return value of the function, or a default-constructed value of the specified type if an exception was caught + */ + template + RetT run_catching_cxx_exception_or_throws(JNIEnv *env, Func f) { + return run_catching_cxx_exception_or(f, [env](const char *msg) { + jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); + if (msg) { + env->ThrowNew(exceptionClass, msg); + } else { + env->ThrowNew(exceptionClass, "Unknown C++ exception"); + } + + return RetT(); + }); + } +} + +#endif //SESSION_ANDROID_JNI_UTILS_H From a78c11f25805530bcc0ba33e0ee1f6376a75f6fb Mon Sep 17 00:00:00 2001 From: fanchao Date: Tue, 28 May 2024 14:37:06 +1000 Subject: [PATCH 2/6] Wrap config_base.cpp also --- libsession-util/src/main/cpp/config_base.cpp | 27 +++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libsession-util/src/main/cpp/config_base.cpp b/libsession-util/src/main/cpp/config_base.cpp index 1c90b1b81c..f0596bd93b 100644 --- a/libsession-util/src/main/cpp/config_base.cpp +++ b/libsession-util/src/main/cpp/config_base.cpp @@ -1,5 +1,6 @@ #include "config_base.h" #include "util.h" +#include "jni_utils.h" extern "C" { JNIEXPORT jboolean JNICALL @@ -85,18 +86,20 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_confirmPushed(JNIEnv *en JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2(JNIEnv *env, jobject thiz, jobjectArray to_merge) { - std::lock_guard lock{util::util_mutex_}; - auto conf = ptrToConfigBase(env, thiz); - size_t number = env->GetArrayLength(to_merge); - std::vector> configs = {}; - for (int i = 0; i < number; i++) { - auto jElement = (jobject) env->GetObjectArrayElement(to_merge, i); - auto pair = extractHashAndData(env, jElement); - configs.push_back(pair); - } - auto returned = conf->merge(configs); - auto string_stack = util::build_string_stack(env, returned); - return string_stack; + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto conf = ptrToConfigBase(env, thiz); + size_t number = env->GetArrayLength(to_merge); + std::vector> configs = {}; + for (int i = 0; i < number; i++) { + auto jElement = (jobject) env->GetObjectArrayElement(to_merge, i); + auto pair = extractHashAndData(env, jElement); + configs.push_back(pair); + } + auto returned = conf->merge(configs); + auto string_stack = util::build_string_stack(env, returned); + return string_stack; + }); } JNIEXPORT jobject JNICALL From 3743ef42bd37d3995df7c9f4961b6e404d13a132 Mon Sep 17 00:00:00 2001 From: fanchao Date: Tue, 28 May 2024 14:51:25 +1000 Subject: [PATCH 3/6] Catch another merge function --- libsession-util/src/main/cpp/config_base.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/libsession-util/src/main/cpp/config_base.cpp b/libsession-util/src/main/cpp/config_base.cpp index f0596bd93b..50e474cd33 100644 --- a/libsession-util/src/main/cpp/config_base.cpp +++ b/libsession-util/src/main/cpp/config_base.cpp @@ -105,12 +105,15 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_merge___3Lkotlin_Pair_2( JNIEXPORT jobject JNICALL Java_network_loki_messenger_libsession_1util_ConfigBase_merge__Lkotlin_Pair_2(JNIEnv *env, jobject thiz, jobject to_merge) { - std::lock_guard lock{util::util_mutex_}; - auto conf = ptrToConfigBase(env, thiz); - std::vector> configs = {extractHashAndData(env, to_merge)}; - auto returned = conf->merge(configs); - auto string_stack = util::build_string_stack(env, returned); - return string_stack; + return jni_utils::run_catching_cxx_exception_or_throws(env, [=] { + std::lock_guard lock{util::util_mutex_}; + auto conf = ptrToConfigBase(env, thiz); + std::vector> configs = { + extractHashAndData(env, to_merge)}; + auto returned = conf->merge(configs); + auto string_stack = util::build_string_stack(env, returned); + return string_stack; + } } #pragma clang diagnostic pop From bc9bf59106aea8924dbc3499a0f74c9690bd71cf Mon Sep 17 00:00:00 2001 From: fanchao Date: Tue, 28 May 2024 15:04:18 +1000 Subject: [PATCH 4/6] Fix syntax error --- libsession-util/src/main/cpp/config_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util/src/main/cpp/config_base.cpp b/libsession-util/src/main/cpp/config_base.cpp index 50e474cd33..5af6483371 100644 --- a/libsession-util/src/main/cpp/config_base.cpp +++ b/libsession-util/src/main/cpp/config_base.cpp @@ -113,7 +113,7 @@ Java_network_loki_messenger_libsession_1util_ConfigBase_merge__Lkotlin_Pair_2(JN auto returned = conf->merge(configs); auto string_stack = util::build_string_stack(env, returned); return string_stack; - } + }); } #pragma clang diagnostic pop From 036b13084f1ab9b999a2ff8caa50c99159bd3cc3 Mon Sep 17 00:00:00 2001 From: fanchao Date: Wed, 29 May 2024 13:11:33 +1000 Subject: [PATCH 5/6] Message --- libsession-util/src/main/cpp/jni_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsession-util/src/main/cpp/jni_utils.h b/libsession-util/src/main/cpp/jni_utils.h index 959444407e..1c5e0a10c3 100644 --- a/libsession-util/src/main/cpp/jni_utils.h +++ b/libsession-util/src/main/cpp/jni_utils.h @@ -42,7 +42,7 @@ namespace jni_utils { if (msg) { env->ThrowNew(exceptionClass, msg); } else { - env->ThrowNew(exceptionClass, "Unknown C++ exception"); + env->ThrowNew(exceptionClass, "Unknown C++ exception from libsession"); } return RetT(); From c899d723b70300793d5c5cc74ac5ddcddf97b495 Mon Sep 17 00:00:00 2001 From: fanchao Date: Wed, 29 May 2024 14:09:48 +1000 Subject: [PATCH 6/6] Formatted message --- libsession-util/src/main/cpp/jni_utils.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libsession-util/src/main/cpp/jni_utils.h b/libsession-util/src/main/cpp/jni_utils.h index 1c5e0a10c3..c9ccd924a6 100644 --- a/libsession-util/src/main/cpp/jni_utils.h +++ b/libsession-util/src/main/cpp/jni_utils.h @@ -40,9 +40,10 @@ namespace jni_utils { return run_catching_cxx_exception_or(f, [env](const char *msg) { jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); if (msg) { - env->ThrowNew(exceptionClass, msg); + auto formatted_message = std::string("libsession: C++ exception: ") + msg; + env->ThrowNew(exceptionClass, formatted_message.c_str()); } else { - env->ThrowNew(exceptionClass, "Unknown C++ exception from libsession"); + env->ThrowNew(exceptionClass, "libsession: Unknown C++ exception"); } return RetT();