diff --git a/CHANGELOG.md b/CHANGELOG.md index 48bce6af..7822984c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ ### Removed ### Fixed +- The `fatal` exception raised when a Rust function bound to Ruby panics can no + longer be caught with `rescue Exception`. ### Security diff --git a/src/error.rs b/src/error.rs index 9b1afd21..b1c98a91 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,8 +5,8 @@ use std::{any::Any, borrow::Cow, ffi::CString, fmt, mem::transmute, os::raw::c_int}; use rb_sys::{ - rb_bug, rb_ensure, rb_errinfo, rb_exc_raise, rb_iter_break_value, rb_jump_tag, rb_protect, - rb_set_errinfo, rb_warning, ruby_special_consts, VALUE, + rb_bug, rb_ensure, rb_errinfo, rb_exc_fatal, rb_exc_raise, rb_iter_break_value, rb_jump_tag, + rb_protect, rb_set_errinfo, rb_warning, ruby_special_consts, VALUE, }; use crate::{ @@ -539,6 +539,15 @@ where pub(crate) fn raise(e: Error) -> ! { match e.0 { ErrorType::Jump(tag) => tag.resume(), + ErrorType::Error(class, _) + if class.as_rb_value() + == unsafe { Ruby::get_unchecked().exception_fatal().as_rb_value() } => + { + unsafe { rb_exc_fatal(e.exception().as_rb_value()) } + // friendly reminder: we really never get here, and as such won't + // drop any values still in scope, make sure everything has been + // consumed/dropped + } _ => { unsafe { rb_exc_raise(e.exception().as_rb_value()) } // friendly reminder: we really never get here, and as such won't diff --git a/src/lib.rs b/src/lib.rs index a10624a8..92950258 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -658,7 +658,7 @@ //! * `rb_eval_string`: See [`eval()`] or [`eval!`]. //! * `rb_eval_string_protect`: [`eval()`] or [`eval!`]. // * `rb_eval_string_wrap`: -// * `rb_exc_fatal`: +//! * `rb_exc_fatal`: Return an [`Error`] constructed from [`Ruby::exception_fatal`]. // * `rb_exc_new`: // * `rb_exc_new_cstr`: // * `rb_exc_new_str`: