Issue #20393 has been reported by ioquatix (Samuel Williams).
----------------------------------------
Bug #20393: `after_fork_ruby` clears all pending interrupts for both parent and child process.
https://bugs.ruby-lang.org/issues/20393
* Author: ioquatix (Samuel Williams)
* Status: Open
* Assignee: ioquatix (Samuel Williams)
* Backport: 3.0: REQUIRED, 3.1: REQUIRED, 3.2: REQUIRED, 3.3: REQUIRED
----------------------------------------
In the following program, the behaviour of the parent process is affected by whether `Process.fork` is invoked or not.
```ruby
Thread.handle_interrupt(RuntimeError => :never) do
Thread.current.raise(RuntimeError, "Queued error")
puts "Pending interrupt: #{Thread.pending_interrupt?}" # true
pid = Process.fork do
puts "Pending interrupt (child process): #{Thread.pending_interrupt?}"
Thread.handle_interrupt(RuntimeError => :immediate){}
end
_, status = Process.waitpid2(pid)
puts "Child process status: #{status.inspect}"
puts "Pending interrupt: #{Thread.pending_interrupt?}" # false
end
puts "Exiting..."
```
I don't think the parent process pending interrupts should be cleared by `after_fork_ruby`:
```c
static void
after_fork_ruby(rb_pid_t pid)
{
rb_threadptr_pending_interrupt_clear(GET_THREAD());
if (pid == 0) {
// child
clear_pid_cache();
rb_thread_atfork();
}
else {
// parent
after_exec();
}
}
```
How about this implementation:
```c
static void
after_fork_ruby(rb_pid_t pid)
{
if (pid == 0) {
// child
rb_threadptr_pending_interrupt_clear(GET_THREAD());
clear_pid_cache();
rb_thread_atfork();
}
else {
// parent
after_exec();
}
}
```
cc @ko1
--
https://bugs.ruby-lang.org/
Issue #20168 has been reported by shia (Sangyong Sim).
----------------------------------------
Bug #20168: Process won't exit when Ractor.select waiting a Ractor
https://bugs.ruby-lang.org/issues/20168
* Author: shia (Sangyong Sim)
* Status: Open
* Priority: Normal
* ruby -v: 3.3.0
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
## Reproduction code
```ruby
trap(:INT) do
puts "SIGINT"
exit
end
trap(:TERM) do
puts "SIGTERM"
exit
end
r = Ractor.new do
loop do
sleep 1
end
end
Ractor.select(r) # stucked.
# SIGINT/SIGTERM sent to Ruby process(confirmed by trap),
# but process won't exit.
```
## Expected behavior
Process killed successfully with exit code 0.
## Affected Ruby version
3.3.0
3.2.x works as expected.
--
https://bugs.ruby-lang.org/
Issue #19236 has been reported by byroot (Jean Boussier).
----------------------------------------
Feature #19236: Allow to create hashes with a specific capacity from Ruby
https://bugs.ruby-lang.org/issues/19236
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
* Target version: 3.3
----------------------------------------
Followup on [Feature #18683] which added a C-API for this purpose.
Various protocol parsers such as Redis `RESP3` or `msgpack`, have to create hashes, and they know the size in advance.
For efficiency, it would be preferable if they could directly allocate a Hash of the necessary size, so that large hashes wouldn't cause many re-alloccations and re-hash.
`String` and `Array` both already offer similar APIs:
```ruby
String.new(capacity: XXX)
Array.new(XX) / rb_ary_new_capa(long)
```
However there's no such public API for Hashes in Ruby land.
### Proposal
I think `Hash` should have a way to create a new hash with a `capacity` parameter.
The logical signature of `Hash.new(capacity: 1000)` was deemed too incompatible in [Feature #18683].
@Eregon proposed to add `Hash.create(capacity: 1000)`.
--
https://bugs.ruby-lang.org/
Issue #20392 has been reported by tenderlovemaking (Aaron Patterson).
----------------------------------------
Bug #20392: Delegate super calls with a block
https://bugs.ruby-lang.org/issues/20392
* Author: tenderlovemaking (Aaron Patterson)
* Status: Open
* ruby -v: ruby 3.4.0dev (2024-03-15T18:08:39Z master e3a82d79fd) [arm64-darwin23]
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
I'm seeing strange behavior with calls to `super` when combined with `...` and a block. I'm not sure if this is expected behavior or not, so I'm filing this ticket.
Using delegate `...` with an explicit block will cause an error:
```ruby
# Example 1
def foo ...
yield
end
def bar ...
foo(...) { } # test.rb: test.rb:6: both block arg and actual block given (SyntaxError)
end
```
However, calling `super` and passing a block works:
```
# Example 2
class A
def foo
yield(3)
end
end
class B < A
def foo(...)
super do |x|
yield(2 + x)
end
end
end
p B.new.foo { |x| x } # 5
```
In the above code, I imagine the bare `super` to basically be equivalent of `super(...)` since I defined the method `foo` as `foo(...)`.
However, if I explicitly pass `...` to super, there is no syntax error, just the block I provided is ignored:
```ruby
# Example 3
class A
def foo
yield(3)
end
end
class B < A
def foo(...)
super(...) do |x|
raise "should I be called?"
end
end
end
p B.new.foo { |x| x } # 3
```
I'd expect Example 3 to raise an exception like Example 1. Additionally, I think the behavior in Example 2 is odd, but zsupers are "special" so I can understand if it is intended behavior.
Is Example 3 intended behavior? If not, how should it behave?
Thanks.
--
https://bugs.ruby-lang.org/
Issue #20389 has been reported by mdalessio (Mike Dalessio).
----------------------------------------
Bug #20389: Issue with chilled strings and mutability after 12be40ae
https://bugs.ruby-lang.org/issues/20389
* Author: mdalessio (Mike Dalessio)
* Status: Open
* ruby -v: ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
* Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
Commit 12be40ae introduced the concept of "chilled" strings when code is compiled with frozen-string-literals not explicitly enabled or disabled. I believe I've found a related bug, which I've bisected to this commit.
This reproduction has been simplified from a failing test case in the `http-cookie` gem:
``` ruby
puts RUBY_DESCRIPTION
re = %r{.(?<thing>.*)}
input = "x/dir[]/file.html"
match = re.match(input) # => "#<MatchData \"x/dir[]/file.html\" thing:\"/dir[]/file.html\">"
thing = match[:thing]
puts "before: #{thing.inspect}"
input[match.begin(:thing)...match.end(:thing)] = "/dir%5B%5D/file.html"
puts "after : #{thing.inspect}"
exit 1 unless thing == "/dir[]/file.html"
```
Ruby 3.3.0 and earlier is fine:
```
$ ruby ./issue-chilled-strings.rb
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir[]/file.html"
```
Master with frozen string explicitly disabled passes:
```
$ ruby --disable-frozen-string-literal ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir[]/file.html"
```
Master with frozen strings explicitly enabled fails as expected:
```
$ ruby --enable-frozen-string-literal ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
./issue-chilled-strings.rb:12:in 'String#[]=': can't modify frozen String: "x/dir[]/file.html" (FrozenError)
from ./issue-chilled-strings.rb:12:in '<main>'
```
But master with no frozen string setting ("chilled") fails, and modifies what should be a frozen string:
```
$ ruby ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir%5B%5D/file."
```
I believe in this case, the chilled warning should be emitted, but then the frozen string should not be modified.
--
https://bugs.ruby-lang.org/
Issue #19057 has been updated by byroot (Jean Boussier).
> the nagging from chilled strings
Eric, I understand that it won't make your annoyance go away, but just in case you didn't know, if you wish to get rid of these warnings easily, you can add `# frozen_string_literal: false` at the top of all Unicorn's source files, like so:
https://github.com/unicorn-ruby/unicorn/commit/23da1fc46a18ed0330081b55892b…
----------------------------------------
Feature #19057: Hide implementation of `rb_io_t`.
https://bugs.ruby-lang.org/issues/19057#change-107452
* Author: ioquatix (Samuel Williams)
* Status: Assigned
* Assignee: ioquatix (Samuel Williams)
* Target version: 3.4
----------------------------------------
In order to make improvements to the IO implementation like <https://bugs.ruby-lang.org/issues/18455>, we need to add new fields to `struct rb_io_t`.
By the way, ending types in `_t` is not recommended by POSIX, so I'm also trying to rename the internal implementation to drop `_t` where possible during this conversion.
Anyway, we should try to hide the implementation of `struct rb_io`. Ideally, we don't expose any of it, but the problem is backwards compatibility.
So, in order to remain backwards compatibility, we should expose some fields of `struct rb_io`, the most commonly used one is `fd` and `mode`, but several others are commonly used.
There are many fields which should not be exposed because they are implementation details.
## Current proposal
The current proposed change <https://github.com/ruby/ruby/pull/6511> creates two structs:
```c
// include/ruby/io.h
#ifndef RB_IO_T
struct rb_io {
int fd;
// ... public fields ...
};
#else
struct rb_io;
#endif
// internal/io.h
#define RB_IO_T
struct rb_io {
int fd;
// ... public fields ...
// ... private fields ...
};
```
However, we are not 100% confident this is safe according to the C specification. My experience is not sufficiently wide to say this is safe in practice, but it does look okay to both myself, and @Eregon + @tenderlovemaking have both given some kind of approval.
That being said, maybe it's not safe.
There are two alternatives:
## Hide all details
We can make public `struct rb_io` completely invisible.
```c
// include/ruby/io.h
#define RB_IO_HIDDEN
struct rb_io;
int rb_ioptr_descriptor(struct rb_io *ioptr); // accessor for previously visible state.
// internal/io.h
struct rb_io {
// ... all fields ...
};
```
This would only be forwards compatible, and code would need to feature detect like this:
```c
#ifdef RB_IO_HIDDEN
#define RB_IOPTR_DESCRIPTOR rb_ioptr_descriptor
#else
#define RB_IOPTR_DESCRIPTOR(ioptr) rb_ioptr_descriptor(ioptr)
#endif
```
## Nested public interface
Alternatively, we can nest the public fields into the private struct:
```c
// include/ruby/io.h
struct rb_io_public {
int fd;
// ... public fields ...
};
// internal/io.h
#define RB_IO_T
struct rb_io {
struct rb_io_public public;
// ... private fields ...
};
```
## Considerations
I personally think the "Hide all details" implementation is the best, but it's also the lest compatible. This is also what we are ultimately aiming for, whether we decide to take an intermediate "compatibility step" is up to us.
I think "Nested public interface" is messy and introduces more complexity, but it might be slightly better defined than the "Current proposal" which might create undefined behaviour. That being said, all the tests are passing.
--
https://bugs.ruby-lang.org/
Issue #19161 has been reported by werebus (Matt Moretti).
----------------------------------------
Bug #19161: Cannot compile 3.0.5 or 3.1.3 on Red Hat 7
https://bugs.ruby-lang.org/issues/19161
* Author: werebus (Matt Moretti)
* Status: Open
* Priority: Normal
* Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
When attempting to run `make` on either the 3.0.5 or 3.1.3 release, I get the following error (I included the whole output as it's pretty short):
```
BASERUBY = /opt/ruby/bin/ruby --disable=gems
CC = gcc -std=gnu11
LD = ld
LDSHARED = gcc -std=gnu11 -shared
CFLAGS = -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wdeprecated-declarations -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wwrite-strings -Wold-style-definition -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable
XCFLAGS = -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fno-strict-overflow -fvisibility=hidden -fexcess-precision=standard -DRUBY_EXPORT -fPIE -I. -I.ext/include/x86_64-linux -I./include -I. -I./enc/unicode/13.0.0
CPPFLAGS =
DLDFLAGS = -Wl,--compress-debug-sections=zlib -fstack-protector-strong -pie
SOLIBS = -lz -lpthread -lrt -lrt -ldl -lcrypt -lm
LANG = en_US.UTF-8
LC_ALL =
LC_CTYPE =
MFLAGS =
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
compiling ./main.c
compiling dmydln.c
compiling miniinit.c
In file included from vm_core.h:83:0,
from iseq.h:14,
from mini_builtin.c:3,
from miniinit.c:51:
thread_pthread.h:108:43: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘struct’
RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec;
^
In file included from iseq.h:14:0,
from mini_builtin.c:3,
from miniinit.c:51:
vm_core.h: In function ‘rb_current_execution_context’:
vm_core.h:1870:34: error: ‘ruby_current_ec’ undeclared (first use in this function)
rb_execution_context_t *ec = ruby_current_ec;
^
vm_core.h:1870:34: note: each undeclared identifier is reported only once for each function it appears in
miniinit.c: At top level:
cc1: warning: unrecognized command line option "-Wno-tautological-compare" [enabled by default]
cc1: warning: unrecognized command line option "-Wno-self-assign" [enabled by default]
cc1: warning: unrecognized command line option "-Wno-parentheses-equality" [enabled by default]
cc1: warning: unrecognized command line option "-Wno-constant-logical-operand" [enabled by default]
cc1: warning: unrecognized command line option "-Wno-cast-function-type" [enabled by default]
make: *** [miniinit.o] Error 1
```
Both Ruby 3.0.4 and 3.1.2 build without error and pass (all but one of) the `make check` tests.
I know RHEL 7 is getting to be pretty old; I suspect a factor here are the ancient build tools available to me. But... EOL for Ruby 2.7 comes before the one for RHEL 7, so I'm trying to prioritize.
--
https://bugs.ruby-lang.org/