From e4bcb64be1fe25c93a8f609a108d8d4c933d6a2f Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Sat, 20 Dec 2025 12:08:28 +0100 Subject: [PATCH 1/6] [Doc] prefer encoding objects over encoding names --- dir.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dir.rb b/dir.rb index a05bd18630b923..0088bb39fa5399 100644 --- a/dir.rb +++ b/dir.rb @@ -178,7 +178,7 @@ class Dir # if +nil+ (the default), the file system's encoding is used: # # Dir.open('.').read.encoding # => # - # Dir.open('.', encoding: 'US-ASCII').read.encoding # => # + # Dir.open('.', encoding: Encoding::US_ASCII).read.encoding # => # # def self.open(name, encoding: nil, &block) dir = Primitive.dir_s_open(name, encoding) @@ -206,7 +206,7 @@ def self.open(name, encoding: nil, &block) # if +nil+ (the default), the file system's encoding is used: # # Dir.new('.').read.encoding # => # - # Dir.new('.', encoding: 'US-ASCII').read.encoding # => # + # Dir.new('.', encoding: Encoding::US_ASCI).read.encoding # => # # def initialize(name, encoding: nil) Primitive.dir_initialize(name, encoding) From e6520de3442659def3463d3bfdca3432f41b2d6a Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Wed, 17 Dec 2025 17:28:47 -0500 Subject: [PATCH 2/6] [Bug #21792] Build rubyspec-capiext only when excuting `test-spec` rubyspec-capiext is only needed for running specs, not for building or installing Ruby. --- common.mk | 3 ++- defs/gmake.mk | 6 +----- win32/Makefile.sub | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/common.mk b/common.mk index c0d663f68e5658..08fee9119a1ef9 100644 --- a/common.mk +++ b/common.mk @@ -804,6 +804,7 @@ clean-platform distclean-platform realclean-platform: RUBYSPEC_CAPIEXT = spec/ruby/optional/capi/ext RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT) RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY) +RUBYSPEC_CAPIEXT_BUILD = $(enable_shared:yes=rubyspec-capiext) rubyspec-capiext: build-ext $(DOT_WAIT) # make-dependent rules should be included after this and built after build-ext. @@ -905,7 +906,7 @@ test: test-short # Separate to skip updating encs and exts by `make -o test-precheck` # for GNU make. -test-precheck: $(ENCSTATIC:static=lib)encs exts PHONY $(DOT_WAIT) +test-precheck: $(ENCSTATIC:static=lib)encs $(RUBYSPEC_CAPIEXT_BUILD) exts PHONY $(DOT_WAIT) yes-test-all-precheck: programs $(DOT_WAIT) test-precheck PRECHECK_TEST_ALL = yes-test-all-precheck diff --git a/defs/gmake.mk b/defs/gmake.mk index 2422151009599c..e6f553fa8c1b5d 100644 --- a/defs/gmake.mk +++ b/defs/gmake.mk @@ -529,11 +529,7 @@ RUBYSPEC_CAPIEXT_SO := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $( rubyspec-capiext: $(RUBYSPEC_CAPIEXT_SO) @ $(NULLCMD) -ifeq ($(ENABLE_SHARED),yes) -exts: rubyspec-capiext -endif - -spec/%/ spec/%_spec.rb: programs exts PHONY +spec/%/ spec/%_spec.rb: programs exts $(RUBYSPEC_CAPIEXT_BUILD) PHONY +$(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec-run -B $(srcdir)/spec/default.mspec $(SPECOPTS) $(patsubst %,$(srcdir)/%,$@) ruby.pc: $(filter-out ruby.pc,$(ruby_pc)) diff --git a/win32/Makefile.sub b/win32/Makefile.sub index c3db450abc30a0..80f8f5c2bf88a4 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -1425,8 +1425,6 @@ rubyspec-capiext: $(RUBYSPEC_CAPIEXT_EXTS) $(Q)$(LDSHARED) -Fe$(@) -Fo$(*).obj $(INCFLAGS) $(CFLAGS) $(CPPFLAGS) $< $(LIBRUBYARG) -link $(DLDFLAGS) $(XLDFLAGS) $(LIBS) $(LOCAL_LIBS) -implib:$*.lib -pdb:$*.pdb -def:$*.def $(Q)$(RM) $*.def $*.exp $*.lib $*.obj $*.pdb -exts: rubyspec-capiext - yesterday: (set TZ=UTC-9) && \ for /f "usebackq" %H in \ From 6bf921051ceba1742318e3c92dddd50ba4f05d17 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 19 Dec 2025 17:16:01 -0500 Subject: [PATCH 3/6] [ruby/mmtk] Call rb_bug when Ruby mutator thread panics This will allow the Ruby backtrace, memory mapping, etc. to be outputted when a Ruby mutator thread panics. https://github.com/ruby/mmtk/commit/d10fd325dd --- gc/mmtk/mmtk.c | 7 +++++++ gc/mmtk/mmtk.h | 1 + gc/mmtk/src/abi.rs | 1 + gc/mmtk/src/api.rs | 4 ++++ gc/mmtk/src/lib.rs | 8 ++++++++ 5 files changed, 21 insertions(+) diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 131aaf38b0fd27..52f653a299ca09 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -355,6 +355,12 @@ rb_mmtk_special_const_p(MMTk_ObjectReference object) return RB_SPECIAL_CONST_P(obj); } +static void +rb_mmtk_mutator_thread_panic_handler(void) +{ + rb_bug("Ruby mutator thread panicked"); +} + // Bootup MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_init_gc_worker_thread, @@ -374,6 +380,7 @@ MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_global_tables_count, rb_mmtk_update_finalizer_table, rb_mmtk_special_const_p, + rb_mmtk_mutator_thread_panic_handler, }; // Use max 80% of the available memory by default for MMTk diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h index b00133a820c546..18466c61108b40 100644 --- a/gc/mmtk/mmtk.h +++ b/gc/mmtk/mmtk.h @@ -69,6 +69,7 @@ typedef struct MMTk_RubyUpcalls { int (*global_tables_count)(void); void (*update_finalizer_table)(void); bool (*special_const_p)(MMTk_ObjectReference object); + void (*mutator_thread_panic_handler)(void); } MMTk_RubyUpcalls; typedef struct MMTk_RawVecOfObjRef { diff --git a/gc/mmtk/src/abi.rs b/gc/mmtk/src/abi.rs index 2214441c9d6db7..1bd19fbe7efd1d 100644 --- a/gc/mmtk/src/abi.rs +++ b/gc/mmtk/src/abi.rs @@ -314,6 +314,7 @@ pub struct RubyUpcalls { pub global_tables_count: extern "C" fn() -> c_int, pub update_finalizer_table: extern "C" fn(), pub special_const_p: extern "C" fn(object: ObjectReference) -> bool, + pub mutator_thread_panic_handler: extern "C" fn(), } unsafe impl Sync for RubyUpcalls {} diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs index 5217eb4a758da1..006e987ea9d060 100644 --- a/gc/mmtk/src/api.rs +++ b/gc/mmtk/src/api.rs @@ -138,6 +138,10 @@ pub unsafe extern "C" fn mmtk_init_binding( upcalls: *const RubyUpcalls, weak_reference_dead_value: ObjectReference, ) { + crate::MUTATOR_THREAD_PANIC_HANDLER + .set((unsafe { (*upcalls).clone() }).mutator_thread_panic_handler) + .unwrap_or_else(|_| panic!("MUTATOR_THREAD_PANIC_HANDLER is already initialized")); + crate::set_panic_hook(); let builder = unsafe { Box::from_raw(builder) }; diff --git a/gc/mmtk/src/lib.rs b/gc/mmtk/src/lib.rs index d16a5bf42f2ec5..4bcafb597a2bb6 100644 --- a/gc/mmtk/src/lib.rs +++ b/gc/mmtk/src/lib.rs @@ -55,6 +55,11 @@ impl VMBinding for Ruby { type VMMemorySlice = RubyMemorySlice; } +/// The callback for mutator thread panic handler (which calls rb_bug to output +/// debugging information such as the Ruby backtrace and memory maps). +/// This is set before BINDING is set because mmtk_init could panic. +pub static MUTATOR_THREAD_PANIC_HANDLER: OnceCell = OnceCell::new(); + /// The singleton object for the Ruby binding itself. pub static BINDING: OnceCell = OnceCell::new(); @@ -132,6 +137,9 @@ pub(crate) fn set_panic_hook() { handle_gc_thread_panic(panic_info); } else { old_hook(panic_info); + (crate::MUTATOR_THREAD_PANIC_HANDLER + .get() + .expect("MUTATOR_THREAD_PANIC_HANDLER is not set"))(); } })); } From 5cdda61d00a61a7da701efa3ef332267d3724424 Mon Sep 17 00:00:00 2001 From: Burdette Lamar Date: Sat, 20 Dec 2025 09:26:02 -0600 Subject: [PATCH 4/6] [DOC] Enhancements for globals.md (#15545) * [DOC] Enhancements for globals.md --- doc/language/globals.md | 139 +++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 67 deletions(-) diff --git a/doc/language/globals.md b/doc/language/globals.md index 716e62a7df87d5..4d42798b8ca154 100644 --- a/doc/language/globals.md +++ b/doc/language/globals.md @@ -10,76 +10,76 @@ To use the module: require 'English' ``` -## Summary +## In Brief ### Exceptions -| Variable | English | Contains | -|:--------:|:-----------------:|----------------------------------------------------| -| `$!` | `$ERROR_INFO` | Exception object; set by Kernel#raise. | -| `$@` | `$ERROR_POSITION` | Array of backtrace positions; set by Kernel#raise. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:--------:|:-----------------:|-----------------------------------------|:---------:|:---------:|---------------| +| `$!` | `$ERROR_INFO` | \Exception object or `nil` | `nil` | Yes | Kernel#raise | +| `$@` | `$ERROR_POSITION` | \Array of backtrace positions or `nil` | `nil` | Yes | Kernel#raise | ### Pattern Matching -| Variable | English | Contains | -|:-------------:|:-------------------:|--------------------------------------------------| -| `$~` | `$LAST_MATCH_INFO` | MatchData object; set by matcher method. | -| `$&` | `$MATCH` | Matched substring; set by matcher method. | -| `` $` `` | `$PRE_MATCH` | Substring left of match; set by matcher method. | -| `$'` | `$POST_MATCH` | Substring right of match; set by matcher method. | -| `$+` | `$LAST_PAREN_MATCH` | Last group matched; set by matcher method. | -| `$1` | | First group matched; set by matcher method. | -| `$2` | | Second group matched; set by matcher method. | -| $_n_ | | nth group matched; set by matcher method. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:-------------:|:-------------------:|-----------------------------------|:---------:|:---------:|-----------------| +| `$~` | `$LAST_MATCH_INFO` | \MatchData object or `nil` | `nil` | No | Matcher methods | +| `$&` | `$MATCH` | Matched substring or `nil` | `nil` | No | Matcher methods | +| `` $` `` | `$PRE_MATCH` | Substring left of match or `nil` | `nil` | No | Matcher methods | +| `$'` | `$POST_MATCH` | Substring right of match or `nil` | `nil` | No | Matcher methods | +| `$+` | `$LAST_PAREN_MATCH` | Last group matched or `nil` | `nil` | No | Matcher methods | +| `$1` | | First group matched or `nil` | `nil` | Yes | Matcher methods | +| `$2` | | Second group matched or `nil` | `nil` | Yes | Matcher methods | +| $_n_ | | nth group matched or `nil` | `nil` | Yes | Matcher methods | ### Separators -| Variable | English | Contains | -|:-----------:|:--------------------------:|--------------------------------------------| -| `$/`, `$-0` | `$INPUT_RECORD_SEPARATOR` | Input record separator; initially newline. | -| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator; initially `nil`. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:-----------:|:---------------------------:|-------------------------|:---------:|:---------:|----------| +| `$/`, `$-0` | `$INPUT_RECORD_SEPARATOR` | Input record separator | Newline | No | | +| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator | `nil` | No | | ### Streams -| Variable | English | Contains | -|:---------:|:---------------------------:|-----------------------------------------------| -| `$stdin` | | Standard input stream; initially `STDIN`. | -| `$stdout` | | Standard input stream; initially `STDIOUT`. | -| `$stderr` | | Standard input stream; initially `STDERR`. | -| `$<` | `$DEFAULT_INPUT` | Default standard input; `ARGF` or `$stdin`. | -| `$>` | `$DEFAULT_OUTPUT` | Default standard output; initially `$stdout`. | -| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream. | -| `$_` | `$LAST_READ_LINE` | String from most recently read stream. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:---------:|:----------------------------:|:-------------------------------------------:|:---------:|:---------:|----------------------| +| `$stdin` | | Standard input stream | `STDIN` | No | | +| `$stdout` | | Standard output stream | `STDOUT` | No | | +| `$stderr` | | Standard error stream | `STDERR` | No | | +| `$<` | `$DEFAULT_INPUT` | Default standard input | `ARGF` | Yes | | +| `$>` | `$DEFAULT_OUTPUT` | Default standard output | `STDOUT` | No | | +| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream | 0 | No | Certain read methods | +| `$_` | `$LAST_READ_LINE` | String from most recently read stream | `nil` | No | Certain read methods | ### Processes -| Variable | English | Contains | -|:-------------------------:|:---------------------:|--------------------------------------------------------| -| `$0` | | Initially, the name of the executing program. | -| `$*` | `$ARGV` | Points to the `ARGV` array. | -| `$$` | `$PROCESS_ID`, `$PID` | Process ID of the current process. | -| `$?` | `$CHILD_STATUS` | Process::Status of most recently exited child process. | -| `$LOAD_PATH`, `$:`, `$-I` | | Array of paths to be searched. | -| `$LOADED_FEATURES`, `$"` | | Array of paths to loaded files. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:-------------------------:|:----------------------:|---------------------------------|:-------------:|:---------:|----------| +| `$0`, `$PROGRAM_NAME` | | Program name | Program name | No | | +| `$*` | `$ARGV` | \ARGV array | `ARGV` | Yes | | +| `$$` | `$PROCESS_ID`, `$PID` | Process id | Process PID | Yes | | +| `$?` | `$CHILD_STATUS` | Status of recently exited child | `nil` | Yes | | +| `$LOAD_PATH`, `$:`, `$-I` | | \Array of search paths | Ruby defaults | Yes | | +| `$LOADED_FEATURES`, `$"` | | \Array of load paths | Ruby defaults | Yes | | ### Debugging -| Variable | English | Contains | -|:-----------:|:-------:|--------------------------------------------------------| -| `$FILENAME` | | The value returned by method ARGF.filename. | -| `$DEBUG` | | Initially, whether option `-d` or `--debug` was given. | -| `$VERBOSE` | | Initially, whether option `-V` or `-W` was given. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:-----------:|:--------:|--------------------------------------------|:----------------------------:|:---------:|----------| +| `$FILENAME` | | Value returned by method `ARGF.filename` | Command-line argument or '-' | Yes | | +| `$DEBUG` | | Whether option `-d` or `--debug` was given | Command-line option | No | | +| `$VERBOSE` | | Whether option `-V` or `-W` was given | Command-line option | No | | ### Other Variables -| Variable | English | Contains | -|:-----------:|:-------:|------------------------------------------------| -| `$-F`, `$;` | | Separator given with command-line option `-F`. | -| `$-a` | | Whether option `-a` was given. | -| `$-i` | | Extension given with command-line option `-i`. | -| `$-l` | | Whether option `-l` was given. | -| `$-p` | | Whether option `-p` was given. | -| `$F` | | Array of `$_` split by `$-F`. | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:-----------:|:--------:|-----------------------------------------------|:---------:|:---------:|----------| +| `$-F`, `$;` | | Separator given with command-line option `-F` | | | | +| `$-a` | | Whether option `-a` was given | | Yes | | +| `$-i` | | Extension given with command-line option `-i` | | No | | +| `$-l` | | Whether option `-l` was given | | Yes | | +| `$-p` | | Whether option `-p` was given | | Yes | | +| `$F` | | \Array of `$_` split by `$-F` | | | | ## Exceptions @@ -352,6 +352,10 @@ Aliased as `$-v` and `$-w`. ## Other Variables +### `$-a` + +Whether command-line option `-a` was given; read-only. + ### `$-F` The default field separator in String#split; must be a String or a @@ -407,27 +411,27 @@ obtained by splitting `$_` by `$-F` is assigned at the start of each ### Environment -| Constant | Contains | -|:---------------------:|-------------------------------------------------------------------------------| -| `ENV` | Hash of current environment variable names and values. | -| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. | -| `ARGV` | Array of the given command-line arguments. | -| `TOPLEVEL_BINDING` | Binding of the top level scope. | -| `RUBY_VERSION` | String Ruby version. | -| `RUBY_RELEASE_DATE` | String Ruby release date. | -| `RUBY_PLATFORM` | String Ruby platform. | -| `RUBY_PATCH_LEVEL` | String Ruby patch level. | -| `RUBY_REVISION` | String Ruby revision. | -| `RUBY_COPYRIGHT` | String Ruby copyright. | -| `RUBY_ENGINE` | String Ruby engine. | +| Constant | Contains | +|-----------------------|-------------------------------------------------------------------------------| +| `ENV` | Hash of current environment variable names and values. | +| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. | +| `ARGV` | Array of the given command-line arguments. | +| `TOPLEVEL_BINDING` | Binding of the top level scope. | +| `RUBY_VERSION` | String Ruby version. | +| `RUBY_RELEASE_DATE` | String Ruby release date. | +| `RUBY_PLATFORM` | String Ruby platform. | +| `RUBY_PATCH_LEVEL` | String Ruby patch level. | +| `RUBY_REVISION` | String Ruby revision. | +| `RUBY_COPYRIGHT` | String Ruby copyright. | +| `RUBY_ENGINE` | String Ruby engine. | | `RUBY_ENGINE_VERSION` | String Ruby engine version. | -| `RUBY_DESCRIPTION` | String Ruby description. | +| `RUBY_DESCRIPTION` | String Ruby description. | -### Embedded Data +### Embedded \Data -| Constant | Contains | -|:--------:|--------------------------------------------------------------------| -| `DATA` | File containing embedded data (lines following `__END__`, if any). | +| Constant | Contains | +|:---------------------:|-------------------------------------------------------------------------------| +| `DATA` | File containing embedded data (lines following `__END__`, if any). | ## Streams @@ -607,3 +611,4 @@ Output: [command-line option `-p`]: rdoc-ref:language/options.md@p-3A+-n-2C+with+Printing [command-line option `-v`]: rdoc-ref:language/options.md@v-3A+Print+Version-3B+Set+-24VERBOSE [command-line option `-w`]: rdoc-ref:language/options.md@w-3A+Synonym+for+-W1 + From fe9a7448b131a48ee37df720fbbfae3142d274ca Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sat, 20 Dec 2025 08:40:59 -0500 Subject: [PATCH 5/6] Check slot_size before zeroing memory for GC hook If the slot_size < RVALUE_SIZE then we would underflow in the memset. --- gc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index d229c1f5aba254..104b027cca788f 100644 --- a/gc.c +++ b/gc.c @@ -1001,7 +1001,10 @@ newobj_of(rb_ractor_t *cr, VALUE klass, VALUE flags, shape_id_t shape_id, bool w if (UNLIKELY(rb_gc_event_hook_required_p(RUBY_INTERNAL_EVENT_NEWOBJ))) { int lev = RB_GC_VM_LOCK_NO_BARRIER(); { - memset((char *)obj + RVALUE_SIZE, 0, rb_gc_obj_slot_size(obj) - RVALUE_SIZE); + size_t slot_size = rb_gc_obj_slot_size(obj); + if (slot_size > RVALUE_SIZE) { + memset((char *)obj + RVALUE_SIZE, 0, slot_size - RVALUE_SIZE); + } /* We must disable GC here because the callback could call xmalloc * which could potentially trigger a GC, and a lot of code is unsafe From 6d5605b28a800be19357ec57ff6c8e1118aabca0 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sat, 20 Dec 2025 11:39:58 -0500 Subject: [PATCH 6/6] [ruby/mmtk] Make rb_gc_impl_heap_id_for_size use MMTK_HEAP_COUNT https://github.com/ruby/mmtk/commit/2185189df4 --- gc/mmtk/mmtk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index 52f653a299ca09..c0c1bf30ea34c9 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -657,7 +657,7 @@ rb_gc_impl_obj_slot_size(VALUE obj) size_t rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size) { - for (int i = 0; i < 5; i++) { + for (int i = 0; i < MMTK_HEAP_COUNT; i++) { if (size == heap_sizes[i]) return i; if (size < heap_sizes[i]) return i; }