@@ -716,104 +716,90 @@ Java_com_m2049r_xmrwallet_model_Wallet_getSeed(
716716 JNIEnv *env,
717717 jobject instance,
718718 jstring seedOffset) {
719-
719+
720720 LOGD (" getSeed: ENTER - thread: %ld" , (long )gettid ());
721-
721+
722722 // ============================================================
723- // PHASE 1: ALL JNI OPERATIONS - NO MUTEX YET
723+ // PHASE 1: ALL JNI OPERATIONS BEFORE MUTEX
724724 // ============================================================
725725
726- // Safety check: ensure env is valid
727726 if (env == nullptr ) {
728727 LOGE (" getSeed: ERROR - JNIEnv is null" );
729728 return nullptr ;
730729 }
731-
732- // Get wallet handle BEFORE mutex (read-only operation, safe)
733- Monero::Wallet *wallet = nullptr ;
734- try {
735- wallet = getHandle<Monero::Wallet>(env, instance);
736- } catch (...) {
737- LOGE (" getSeed: EXCEPTION getting wallet handle" );
738- return env->NewStringUTF (" " );
739- }
740-
730+
731+ // Get wallet handle
732+ Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
741733 if (!wallet) {
742734 LOGE (" getSeed: ERROR - Wallet handle is null" );
743735 return env->NewStringUTF (" " );
744736 }
745-
746- // Extract seedOffset string IMMEDIATELY - this is the critical fix
747- // We MUST do this BEFORE acquiring any mutex
737+
738+ // CRITICAL: Extract string content BEFORE mutex
748739 std::string offset;
749740 if (seedOffset != nullptr ) {
750741 const char *off = env->GetStringUTFChars (seedOffset, nullptr );
751-
752- // Check for JNI exceptions
753- if ( env->ExceptionCheck ()) {
754- env-> ExceptionClear ();
755- LOGE (" getSeed: JNI exception while reading seedOffset" );
742+ if (off == nullptr || env-> ExceptionCheck ()) {
743+ if (env-> ExceptionCheck ()) {
744+ env->ExceptionClear ();
745+ }
746+ LOGE (" getSeed: Failed to get UTF chars from seedOffset" );
756747 return env->NewStringUTF (" " );
757748 }
758-
759- if (off != nullptr ) {
760- offset.assign (off);
761- env->ReleaseStringUTFChars (seedOffset, off);
762- }
749+
750+ offset.assign (off);
751+ env->ReleaseStringUTFChars (seedOffset, off);
752+ // seedOffset jstring is now "dead" to us - never touch it again
763753 }
764754
765- // IMPORTANT: seedOffset jstring is NEVER touched again after this point
766- // We only use the std::string copy (offset) from now on
767-
768755 // ============================================================
769- // PHASE 2: CRITICAL SECTION - MUTEX HELD, NO JNI CALLS
756+ // PHASE 2: CRITICAL SECTION - NO JNI CALLS WHILE LOCKED
770757 // ============================================================
771758
772- // NOW acquire the mutex (after ALL JNI operations are complete)
773- std::lock_guard<std::mutex> lock (g_walletMutex);
774- LOGD (" getSeed: acquired wallet mutex" );
775-
776- // Wallet status check
777- if (wallet->status () != Monero::Wallet::Status_Ok) {
778- std::string err;
779- int status;
780- wallet->statusWithErrorString (status, err);
781- LOGE (" getSeed: Wallet status not OK (%d): %s" , status, err.c_str ());
782- // Return empty string on error
783- // Note: Returning while holding lock is fine - lock_guard destructor releases it
784- return env->NewStringUTF (" " );
785- }
786-
787- // Get seed using the C++ string copy (NOT the jstring parameter)
788759 std::string seed;
789- try {
790- seed = wallet->seed (offset);
791- } catch (const std::exception& e) {
792- LOGE (" getSeed: EXCEPTION in wallet->seed: %s" , e.what ());
793- return env->NewStringUTF (" " );
794- } catch (...) {
795- LOGE (" getSeed: UNKNOWN EXCEPTION in wallet->seed" );
796- return env->NewStringUTF (" " );
797- }
798-
799- // Lock is automatically released here when lock_guard goes out of scope
760+ {
761+ std::lock_guard<std::mutex> lock (g_walletMutex);
762+ LOGD (" getSeed: acquired wallet mutex" );
763+
764+ // Wallet status check
765+ if (wallet->status () != Monero::Wallet::Status_Ok) {
766+ std::string err;
767+ int status;
768+ wallet->statusWithErrorString (status, err);
769+ LOGE (" getSeed: Wallet status not OK (%d): %s" , status, err.c_str ());
770+ // Lock releases here when scope ends
771+ return env->NewStringUTF (" " );
772+ }
773+
774+ // Get seed using C++ string (safe - no JNI involved)
775+ try {
776+ seed = wallet->seed (offset);
777+ } catch (const std::exception& e) {
778+ LOGE (" getSeed: EXCEPTION in wallet->seed: %s" , e.what ());
779+ return env->NewStringUTF (" " );
780+ } catch (...) {
781+ LOGE (" getSeed: UNKNOWN EXCEPTION in wallet->seed" );
782+ return env->NewStringUTF (" " );
783+ }
784+ } // Lock automatically released here
800785
801786 // ============================================================
802- // PHASE 3: CREATE RETURN VALUE - MUTEX RELEASED, JNI SAFE
787+ // PHASE 3: CREATE RETURN VALUE - MUTEX RELEASED
803788 // ============================================================
804789
805- // Create Java string from the result
806790 jstring result = env->NewStringUTF (seed.c_str ());
807-
808- if (env->ExceptionCheck () || result == nullptr ) {
809- env->ExceptionClear ();
810- LOGE (" getSeed: Failed to create jstring" );
791+ if (result == nullptr || env->ExceptionCheck ()) {
792+ if (env->ExceptionCheck ()) {
793+ env->ExceptionClear ();
794+ }
795+ LOGE (" getSeed: Failed to create return jstring" );
811796 return env->NewStringUTF (" " );
812797 }
813-
798+
814799 LOGD (" getSeed: EXIT - success" );
815800 return result;
816801}
802+
817803JNIEXPORT jstring JNICALL
818804Java_com_m2049r_xmrwallet_model_Wallet_getSeedLanguage (
819805 JNIEnv *env,
0 commit comments