Skip to content

Commit 3fc301a

Browse files
0lai0mbutrovich
andauthored
fix: enhance JNI local frame management with error handling in with_env function (#4225)
Co-authored-by: Matt Butrovich <mbutrovich@users.noreply.github.com>
1 parent fbadc91 commit 3fc301a

1 file changed

Lines changed: 28 additions & 2 deletions

File tree

native/jni-bridge/src/lib.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,25 @@ use jni::{
2626
errors::Error,
2727
objects::{JMethodID, JObject, JString, JThrowable, JValueOwned},
2828
signature::ReturnType,
29-
Env, JavaVM,
29+
Env, JavaVM, DEFAULT_LOCAL_FRAME_CAPACITY,
3030
};
3131
use once_cell::sync::OnceCell;
3232

3333
use errors::{CometError, CometResult};
3434

3535
pub mod errors;
3636

37+
enum LocalFrameError<E> {
38+
Closure(E),
39+
Jni(jni::errors::Error),
40+
}
41+
42+
impl<E> From<jni::errors::Error> for LocalFrameError<E> {
43+
fn from(source: jni::errors::Error) -> Self {
44+
Self::Jni(source)
45+
}
46+
}
47+
3748
/// Global reference to the Java VM, initialized during native library setup.
3849
pub static JAVA_VM: OnceCell<JavaVM> = OnceCell::new();
3950

@@ -300,6 +311,13 @@ impl JVMClasses<'_> {
300311
}
301312

302313
/// Runs a closure with an attached JNI environment for the current thread.
314+
///
315+
/// The closure executes inside a JNI local frame. All JNI local references
316+
/// created inside the closure are freed when the frame is popped on return.
317+
/// Callers must return only Rust values (e.g. `Vec`, `ArrayRef`, scalars);
318+
/// returning a raw JNI local reference will produce a dangling reference
319+
/// after the frame is popped. Panic safety is guaranteed by
320+
/// `jni::Env::with_local_frame`, which pops the frame even on unwinding.
303321
pub fn with_env<T, E, F>(f: F) -> Result<T, E>
304322
where
305323
F: FnOnce(&mut Env) -> Result<T, E>,
@@ -316,7 +334,15 @@ impl JVMClasses<'_> {
316334
.attach_current_thread_guard(Default::default, &mut scope)
317335
.map_err(CometError::from)
318336
.map_err(E::from)?;
319-
f(guard.borrow_env_mut())
337+
guard
338+
.borrow_env_mut()
339+
.with_local_frame(DEFAULT_LOCAL_FRAME_CAPACITY, |env| {
340+
f(env).map_err(LocalFrameError::Closure)
341+
})
342+
.map_err(|err| match err {
343+
LocalFrameError::Closure(err) => err,
344+
LocalFrameError::Jni(err) => E::from(CometError::from(err)),
345+
})
320346
}
321347
}
322348
}

0 commit comments

Comments
 (0)