The documentation says that Process::Status.wait sets the thread-local
variable $? when there are child processes, but it never does.
rb_process_status_wait does not call rb_last_status_set, and $? is left
untouched:
$? # => nil
Process.spawn('cat /nop') # => 4996
Process::Status.wait # => #<Process::Status: pid 4996 exit 1>
$? # => nil
The existing example showed this as well: the pid displayed for $?
(1155508) did not match the pid of the returned status (1155880),
contradicting the surrounding text.
Since $? is never set, the "does not set thread-local variable $?"
note in the no-child-process case is now redundant and has been folded
into the general description.
The Range Marshal compat dumper would allocate
an Object with no size information, hence get a 32B slot
with enough space for 2 ivars, then insert 3 ivars causing
it to spill.
This isn't a big problem, but somewhat shows that the interface
isn't WVA aware.
By introducing `rb_class_allocate_instance_capa` we can directly
allocate an object with enough room.
The decoration gems are loaded lazily on the first error display, which
in a pre-forking server happens after fork in each child. That loads
their code outside copy-on-write shared memory and busts method caches
at runtime when they prepend Exception#detailed_message.
Process.warmup, called before the first fork by such servers, now loads
them eagerly so the prepended decorators land in shared memory and the
cache invalidation happens during boot.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Track explicit lengths while parsing command strings and comparing the
current directory. This avoids relying on Ruby string terminators and
makes separators in the generated argument buffer explicit.
BSD/OS was discontinued in 2003 and the bsdi* target has been
unbuildable for decades. This also removes the BROKEN_SETREUID and
BROKEN_SETREGID fallbacks in process.c, which no other platform
ever defined.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Set RUBY_TYPED_THREAD_SAFE_FREE on TypedData types whose dfree function
is trivially safe, and only frees its own memory
Types not yet marked as THREAD_SAFE_FREE:
- id2ref_tbl_type: sets the process-global id2ref_tbl to NULL.
- mutex_data_type: unlinks itself from another thread's keeping_mutexes list.
- autoload_data_type: deletes nodes from a shared intrusive list.
- autoload_const_type: deletes itself from a shared list.
- rb_cont_data_type: mutates the shared fiber pool and the global first_jit_cont list.
- rb_fiber_data_type: delegates to cont_free.
- FiberPoolDataType: mutates shared fiber pool free-lists.
- ractor_data_type: reconfigures global VM event-hook flags and call caches.
- exported_object_registry: frees a global table under the VM lock.
- rb_box_data_type (Box::Entry): unlinks classext from other live class and module objects.
- box_ext_cleanup_type: dereferences another String object and calls unlink.
- monitor_data_type: uses the default free, so the flag has no effect.
Co-authored-by: Luke Gruber <luke.gruber@shopify.com>
In many place ALLOC_V / ALLOCV_N is used as a safer `alloca`,
and to behave like stack memory, `ALLOCV` does scan its buffer
for references using `rb_gc_mark_locations`.
The problem is that it's quite slow, and in many cases, the
temporary buffer is known not to contain any references.
e.g. `ALLOCV_N(uint32_t, buf0, len)` can't possibly contain references,
as the element size is too small.
[Bug #17516]
`fork(2)` only leave the calling thread alive in the child.
Because of this forking from the non-main ractor can easily
leave the VM in a corrupted state.
It may be possible in the future to carefully allow forking from non-main
Ractor, but shot term it's preferable to add this restriction.
`extra_fd` was leaked if `fd_set_cloexec` fails -- I can't think of any
chance of that happening here, but just in case.
Coverity Scan found this issue.
So that it doesn't get included in the generated binaries for builds
that don't support loading shared GC modules
Co-Authored-By: Peter Zhu <peter@peterzhu.ca>
Do not release GVL around get{pwuid,pwnam,grgid,grnam} calls,
as doing so is not thread-safe. Another C extension could have
a concurrent call, and derefencing the returned pointer from
these calls could result in a segfault.
Have rb_home_dir_of call rb_getpwdirnam_for_login if available,
so it can use getpwnam_r and release GVL in a thread-safe manner.
This is related to GVL releasing work in [Bug #20587].
[Feature #20590]
For better of for worse, fork(2) remain the primary provider of
parallelism in Ruby programs. Even though it's frowned uppon in
many circles, and a lot of literature will simply state that only
async-signal safe APIs are safe to use after `fork()`, in practice
most APIs work well as long as you are careful about not forking
while another thread is holding a pthread mutex.
One of the APIs that is known cause fork safety issues is `getaddrinfo`.
If you fork while another thread is inside `getaddrinfo`, a mutex
may be left locked in the child, with no way to unlock it.
I think we could reduce the impact of these problem by preventing
in for the most notorious and common cases, by locking around
`fork(2)` and known unsafe APIs with a read-write lock.
- Extract functions to check not-found conditions
- Set the length to the result of `rb_getlogin`
- Reentrant versions return an error numeber but not `errno`
- Check maybe-undefined macros with `defined`