Project

General

Profile

Actions

Bug #22280

open

Ruby::Box breaks $? after Kernel#system / IO.popen

Bug #22280: Ruby::Box breaks $? after Kernel#system / IO.popen

Added by hsbt (Hiroshi SHIBATA) 4 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.1.0dev (2026-08-31T05:43:42Z master 6eba15864c) +MN +PRISM [arm64-darwin27]

Description

Under RUBY_BOX=1, reading $? after Kernel#system or IO.popen returns an uninitialized Process::Status. Process.last_status is correct.

$ RUBY_BOX=1 ruby -e 'p system("false"); p $?; p Process.last_status'
false
#<Process::Status: uninitialized>
#<Process::Status: pid 69619 exit 1>

In a user box, rb_gvar_get caches gvar reads in the box gvar_tbl, storing a clone of the getter result. $? is a readonly virtual variable backed by per-thread state (rb_last_status_get), so the cache can never be right. Worse, Process::Status is TypedData and clone does not copy the wrapped struct, so even the first read yields an uninitialized status (exit 0). $$ has the same defect. A forked child reports the parent's pid.

The regexp special variables were already fixed this way. Readonly virtual variables ($&, $`, $', $+) are marked rb_gvar_box_ready so reads bypass the cache (commit 8ad6baa0174). $? and $$ need the same marking in InitVM_process.

This breaks rake's sh ("Command failed with status (0)") and bundler's env_helpers specs under RUBY_BOX=1. Related: #22275

This is fixed by https://github.com/ruby/ruby/pull/18577.


Related issues 1 (1 open0 closed)

Related to Ruby - Misc #22275: Ruby::Box support plan for RubyGems and BundlerOpenActions
Actions

Also available in: PDF Atom