ITADN

`deprecate.rb` methods fail in WASM (wasm32-wasi): blocks not received by `class_eval` / `define_method`

#9456Openaim2bpg 创建于 2026-04-05
RubyGems
A
aim2bpgcommented
### Describe the problem as clearly as you can In Ruby 3.4+ compiled to WebAssembly (wasm32-wasi), the block-based patterns in `lib/rubygems/deprecate.rb` fail at boot. Converting these methods to use `class_eval <<~RUBY` with `def` (instead of `define_method`) resolves the issue. The same code works correctly in Ruby 3.3 WASM builds and in all native (non-WASM) Ruby environments. ### Did you try upgrading RubyGems? <!-- Make sure you're using the latest version of both RubyGems by running `gem update --system`. --> ### Post steps to reproduce the problem 1. Build Ruby 3.4 or 4.0 for WASM with parse.y parser (to avoid the separate Prism crash — see ruby/prism#4065) 2. Boot a Rails application or any code that triggers `Gem::Deprecate` ### Which command did you run? Boot a Rails application or any code that triggers `Gem::Deprecate` on Ruby 3.4+ compiled to wasm32-wasi. ### What were you expecting to happen? The application boots successfully without errors, as it does in Ruby 3.3 WASM builds and all native Ruby environments. ### What actually happened? ``` ArgumentError: wrong number of arguments (given 0, expected 1..3) from internal:gem_prelude:2:in 'class_eval' from internal:gem_prelude:2:in 'module:Deprecate' from internal:gem_prelude:2:in 'module:Gem' from internal:gem_prelude:2:in '<main>' ``` We tested multiple approaches to isolate the problem. All tests used Ruby 3.4 compiled to WASM with parse.y as the parser. | No. | Approach | Result | Error | |-----|---------|--------|-------| | 1 | `class_eval do...end` (original) | Fail | `ArgumentError: wrong number of arguments (given 0, expected 1..3)` | | 2 | `class_eval {...}` | Fail | Same error as No.1 | | 3 | Remove `class_eval`, use `define_method` directly | Fail | `tried to create Proc object without a block` | | 4 | `define_method(name) do` (with parentheses) | Fail | Same error as No.3 | | 5 | `class_eval <<~RUBY` with `define_method` inside | Fail | Same error as No.3 (block not received within string eval) | | 6 | `class_eval <<~RUBY` with `def #{name}` | **Pass** | No error | Key observations: - Both `do...end` and `{}` block styles fail (No.1, No.2) - `define_method` also cannot receive blocks (No.3, No.4, No.5) - Only the combination of string-based `class_eval` and `def`-based method definition (no blocks at all) works (No.6) - The identical `class_eval do...end` code in Ruby 3.3 WASM builds works without issues ### Run `gem env` and paste the output below - Ruby: 3.4.8 / 4.0.2 (compiled to wasm32-unknown-wasip1 via ruby_wasm 2.9.0) - RubyGems: bundled (3.6.x for 3.4, 3.7.x for 4.0) - wasi_sdk: 24.0 --- **Workaround:** Convert `deprecate.rb`'s three methods (`deprecate`, `rubygems_deprecate`, `rubygems_deprecate_command`) from `class_eval do / define_method` to `class_eval <<~RUBY / def` style. This eliminates all block passing and has no effect on non-WASM environments. Patch file (for Ruby 4.0; minor differences for 3.4 due to method signature changes): https://github.com/aim2bpg/rubree/blob/main/ruby_wasm_patches/fix-deprecate-class-eval-block.patch **Related:** - ruby/prism#4065 — `pm_parser_init` out-of-bounds memory access in WASM (must be fixed independently)
1 条评论