New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement mrb_raise
with Rust panic!
#1904
base: trunk
Are you sure you want to change the base?
Conversation
- mruby/mruby#5728 - artichoke/mruby@d4d902b - artichoke/mruby#11 - artichoke/mruby#12 - https://github.com/artichoke/mruby/releases/tag/artichoke-vendor.10 This fix is required to make progress on: - #1904
f0019ad
to
ee80042
Compare
Blocked on |
ee80042
to
f6a053b
Compare
Errors with the latest nightly:
Nightly version $ rustc -v --version
rustc 1.64.0-nightly (f8588549c 2022-07-18)
binary: rustc
commit-hash: f8588549c3c3d45c32b404210cada01e2a45def3
commit-date: 2022-07-18
host: x86_64-apple-darwin
release: 1.64.0-nightly
LLVM version: 14.0.6 |
f6a053b
to
20157e8
Compare
Unblocked on nightly I believe now that |
The nightly changes made it, but now blocked on linker failures in mruby: |
20157e8
to
84506ca
Compare
84506ca
to
59e1fb4
Compare
The Rust team has put out a call for testing on the `c_unwind` feature and associated `C-unwind` ABI: - rust-lang/rfcs#2945 (comment) I intend to implement mruby's exception unwinding using Rust's panic infrastructure: - #35 This commit changes the Rust toolchain to nightly for this test. Merging this experiment will be blocked on the `C-unwind` ABI making it to stable.
`mruby-error` implements `mrb_protect` and `mrb_ensure`. These two functions are used to stop the propagation of exception unwinding in mruby, which natively uses either `setjmp`/`longjmp` or C++'s `catch` and `throw`. I intend to reimplement these functions in Rust using Rust panics: `std::panic::catch_unwind` and `std::panic::panic_any`. See: - #35
When `-DARTICHOKE` is passed when compiling mruby, `#ifndef` out the definition and implementation of the `exc_throw` static function and replace it with a forward declaration. This function normally uses the `MRB_THROW` macro to initiate an unwind. This prepares us to implement this function in Rust with a `#[no_mangle] unsafe extern "C-unwind" fn` item that unwinds with a Rust panic. The previous commit disables the implementations of `mrb_protect` and `mrb_ensure` which pair usage of `MRB_TRY` and `MRB_CATCH` with the `MRB_THROW` in `exc_throw`.
- Add a custom panic payload which wraps a `sys::mrb_value` and implements the necessary traits to be used with `panic!`. - Implement `exc_throw` with `std::panic::panic_any` and the custom panic payload. - Implement `mrb_protect` with `std::panic::catch_unwind` and downcasting to check for the custom panic payload. When using `std::panic::panic_any`, the built-in Rust panic hook is triggered which prints the panic to stderr and enables the `RUST_BACKTRACE` handler. This commit includes some code that experiments with disabling these built-in behaviors. Per feedback from upstream, `panic_any` should be replaced with `std::panic::resume_unwind` which initiates the panic with a custom payload and avoids running the registered panic hook.
Per feedback from upstream, to avoid printing to stderr when panicking, I can use `std::panic::resume_unwind` instead of `std::panic::panic_any`.
bindgen does not support customizing the ABI of function and function pointer bindings. This commit hacks support for `C-unwind` ABI into the generated bindings by doing a find and replace.
- Update `Free` function type alias. - Update `Method` function type alias. - Update `box_unbox_free` to use `C-unwind` ABI.
mruby supports compilation as a C++ library with a C++ compiler by defining the `MRB_USE_CXX_EXCEPTION` macro. Per upstream, it is always UB to unwind past stack frames that assume that no unwinding will occur. On most compilers, C code is compiled by default with this assumption. In Rust, C code compiled this way corresponds to the `unsafe extern "C" fn` ABI. This branch changes Rust functions and the mruby bindings to use the `C-unwind` ABI, which corresponds to C compiled with support for exceptions and unwinding. The unwinding mechanism used by Rust and its `C-unwind` ABI is the same mechanism used by C++ for its `try`/`catch` exception handling. These changes are similar to if mruby was compiled by a C compiler with `-fexceptions`. However, several parts of mruby, like the codegen module, use the `MRB_TRY` and `MRB_CATCH` macros still. Compiling mruby as C++ means `setjmp`/`longjmp` will no longer be used for these internal unwinding cases. `-x c++` is passed to the `cc` crate and to `clang` via `bindgen` to avoid this deprecation warning: warning: clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]
Neither Artichoke nor its vendored mruby sources call `mrb_ensure`, but implementing it ensures we have maintain an API/ABI compatible mruby implementation.
- Ensure Rust panics are propagated and ignored by `mrb_protect` and `mrb_ensure`. - Add safety comments to unsafe trait impls. - Add documentation to panic payload. - Add inline comments. - Properly forward Artichoke `Error`s.
Instead of disabling the static function `exc_throw` in C code when compiling for Artichoke and implementing the function with global linkage in Rust as a `#[no_mangle] extern "C" fn`, implement an Artichoke-specific `extern "C" fn` and make `exc_throw` an alias to it with a macro.
This commit includes changes to parse.y. The parser is regenerated with: ``` /usr/local/opt/bison/bin/bison -o artichoke-backend/vendor/mruby/mrbgems/mruby-compiler/core/y.tab.c artichoke-backend/vendor/mruby/mrbgems/mruby-compiler/core/parse.y sed -i '' -e 's#artichoke-backend/vendor/mruby/##g' artichoke-backend/vendor/mruby/mrbgems/mruby-compiler/core/y.tab.c ```
- Improve safety comment on `ExceptionPayload` unsafe impl - Document why `panic::resume_unwind` is used instead of `panic_any!`
59e1fb4
to
958bece
Compare
I think this PR is stuck. The VM relies on being able to catch unwinds so it can enter the rescue flow: artichoke/artichoke-backend/vendor/mruby/src/vm.c Lines 3034 to 3042 in 4018f41
|
Fixes #35.
WIP, blocked on stabilization of the
c_unwind
feature.Compatibility Notes
This PR changes Artichoke to compile mruby as C++ instead of C. A compiler that supports
c++17
is required.By compiling mruby as C++,
artichoke-backend
'sbuild.rs
is able to set-DMRB_USE_CXX_EXCEPTION
which uses C++try
/catch
instead ofsetjmp
/longjmp
for unwinding in the parser.C++ exceptions are possible now with the
C-unwind
ABI; whereas before they would be UB if passing through Rust stack frames.Hopefully this improves the state of the playground's Emscripten bundle when raising Ruby
Exception
s in native code:error::raise
crash the playground with an unreachable error playground#389