Skip to content

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

@aim2bpg

Description

@aim2bpg

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?

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 Prism parser crashes in WASM (wasm32-wasi): pm_parser_init out-of-bounds memory access 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:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions