Ruby's second 3.2 preview adds WASI and regex timeouts
The preview ports CRuby to a WebAssembly environment and adds a time limit for regex matching. Both changes make execution constraints explicit, with important limits on platform support and timeout scope.
Running CRuby in a WebAssembly environment requires more than compiling C into a different instruction format. The interpreter relies on control-flow and memory-inspection behaviour that the target does not directly provide. Ruby's second 3.2 preview uses a transformation technique to bridge those requirements, making the port an adaptation of the runtime as well as a new build target.
The September 9 preview announcement describes initial WASI-based WebAssembly support. It also introduces regex matching timeouts. Both changes concern constraints on program execution, but at different levels. The port adapts the interpreter to a host environment, while a timeout limits how long one matching operation may continue.
I find Ruby approachable for expressing application logic. Making its existing interpreter available in another environment is more interesting to me than defining a similar-looking language with different behaviour. The preview's explicit limitations are part of understanding how much of that existing implementation the port currently supports.
The interpreter needs more than a system-call interface
WASI supplies a system interface for WebAssembly programs. The announcement describes browsers, serverless edge environments and other WebAssembly/WASI hosts as potential destinations for the CRuby binary. TryRuby is a concrete example, allowing the original interpreter to run in a browser playground.
The runtime still has requirements beyond that interface. The release explains that the current WebAssembly and WASI environment lacks some functionality needed for fibers, exceptions and garbage collection. CRuby uses Asyncify, a binary transformation technique that enables control over execution in user code, to fill those gaps.
The original WASI implementation patch makes the adaptation visible. It adds Asyncify-based emulation for fibers, setjmp and register scanning. Its build description also notes that optimization order matters, because WebAssembly-level inlining before the transformation can break assumptions Asyncify relies on.
That is a useful qualification to the phrase portable binary. The runtime's execution machinery and the transformation pipeline have to agree. Producing WebAssembly instructions is only one part of preserving the interpreter's required behaviour.
The announcement also describes a virtual filesystem layered over WASI so that a Ruby application can be packed into a single .wasm file. That addresses distribution of application contents alongside the runtime. It is separate from providing every operating-system feature a native Ruby application might expect.
Test coverage describes a limited initial port
The preview reports that the port passes basic and bootstrap tests that do not use the Thread API. That is a specific achievement with a specific exclusion. It should not be rewritten as a claim that every Ruby library or concurrent application runs unchanged in a browser.
The exclusion matters because an application can depend on runtime facilities indirectly through libraries. The announcement establishes an initial supported test scope. It does not establish that the presence of a .wasm executable makes native platform dependencies or threading assumptions disappear.
This gives the preview a clear purpose for exploration. It supplies actual CRuby in a new embedding environment, while leaving platform coverage visible as work in progress. The virtual filesystem and Asyncify adaptation explain how that result is constructed without implying general native-platform equivalence.
Matching gets an explicit time budget
The regex timeout feature addresses a different execution problem. A pattern can take unexpectedly long on a particular input, allowing an attacker to consume substantial work with a chosen subject string. The preview adds Regexp.timeout as a global configuration for limiting matching.
Regexp.timeout = 1.0
pattern = Regexp.new("[A-Z]+", timeout: 0.5)
p pattern.match?("READY")
The instance-specific timeout: argument lets a particular regex use a different policy from the global setting. The announcement also shows timeout: nil to disable the limit for a special case. Such an override therefore belongs in the behaviour of the regex object, not only in a process-wide startup choice.
If matching exceeds its budget, the new failure is Regexp::TimeoutError. The operation no longer has only the ordinary distinction between a match and no match. Application logic using the feature also has a limit-exceeded outcome to consider.
This mechanism constrains execution time. It does not rewrite a pattern into a more efficient algorithm, and the preview does not claim that all patterns now have the same complexity. An explicitly unlimited pattern can still run without interruption from this timeout mechanism, as the release's override example demonstrates.
I consider the per-pattern setting important because a global limit alone can hide differing requirements. A short request-path operation and an intentionally longer computation need not use identical budgets. The override makes that difference an explicit choice, including the consequential choice to allow no timeout.
Preview status and neighbouring changes remain distinct
This is Ruby 3.2.0-preview2, not the final stable release. The announcement invites feedback on the timeout facility. Its examples establish the API being offered for evaluation at this point, without supplying evidence about what a later release will retain or change.
Other changes also affect the surrounding build environment. The preview notes that Psych no longer carries libyaml source and that users need the library through their platform's package system. It separately reports YJIT support for arm64/aarch64 on Unix and a Rust build requirement. Those are different targets and toolchain concerns from the WASI port.
The preview also tightens keyword forwarding through methods that accept a rest argument. Its compatibility explanation requires each relevant forwarding method to carry ruby2_keywords when using that older delegation form. A flag accidentally preserved through an intermediate receiver no longer supplies an exception. This is a source-level calling convention concern, independent of whether the interpreter runs natively or through WebAssembly. A portable runtime still executes a particular language version's rules, so changing its destination does not remove the need to understand changes in those rules.
The meaningful distinction is between interpreter portability and limits within an interpreter operation. Asyncify and the virtual filesystem help construct a CRuby deployment for a WebAssembly host. Regex timeout settings bound a matching operation inside Ruby. Each feature exposes a previously difficult execution requirement, while the preview documents the limits of what it currently supports.