Ruby Issue Tracking System: Issueshttps://bugs.ruby-lang.org/https://bugs.ruby-lang.org/favicon.ico?17113305112024-03-29T01:55:10ZRuby Issue Tracking System
Redmine Ruby master - Bug #20401 (Open): Duplicated when clause warning line numberhttps://bugs.ruby-lang.org/issues/204012024-03-29T01:55:10Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>When you have a duplicated when clause, you get a warning for it. For example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="n">foo</span>
<span class="k">when</span> <span class="ss">:bar</span>
<span class="k">when</span> <span class="ss">:baz</span>
<span class="k">when</span> <span class="ss">:bar</span>
<span class="k">end</span>
</code></pre>
<p>you get <code>warning: duplicated `when' clause with line 2 is ignored</code>.</p>
<p>But the when clause that is ignored is the one on line 4, not line 2. It seems like it's warning for the wrong line.</p> Ruby master - Bug #20400 (Open): Nested BEGIN{} execution orderhttps://bugs.ruby-lang.org/issues/204002024-03-28T18:13:35Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>Right now there are specs for the order in which <code>BEGIN{}</code> should be executed, which is the order they appear in the file. For example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"1"</span> <span class="p">}</span>
<span class="nb">print</span> <span class="s2">"4"</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"2"</span> <span class="p">}</span>
<span class="nb">print</span> <span class="s2">"5"</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"3"</span> <span class="p">}</span>
</code></pre>
<p>should output "12345". However, I couldn't find any tests/specs on what happens when <code>BEGIN{}</code> is nested. The order appears to be somewhat confusing, so I wanted to clarify if it was intentional or a bug. For example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">BEGIN</span> <span class="p">{</span>
<span class="nb">print</span> <span class="s2">"1"</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"2"</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>prints "21", and:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">BEGIN</span> <span class="p">{</span>
<span class="nb">print</span> <span class="s2">"1"</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"2"</span> <span class="p">}</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"3"</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>prints "231", and finally:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">BEGIN</span> <span class="p">{</span>
<span class="nb">print</span> <span class="s2">"1"</span>
<span class="k">BEGIN</span> <span class="p">{</span>
<span class="nb">print</span> <span class="s2">"2"</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"3"</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">BEGIN</span> <span class="p">{</span> <span class="nb">print</span> <span class="s2">"4"</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>prints "3241". Is this intentional?</p> Ruby master - Bug #20399 (Open): Ripper doesn't respect implicit -xhttps://bugs.ruby-lang.org/issues/203992024-03-28T14:27:26Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>For the given script:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#!/bin/sh</span>
<span class="c1"># -*- ruby -*-</span>
<span class="nb">exec</span> <span class="s2">"${RUBY-ruby}"</span> <span class="s2">"-x"</span> <span class="s2">"$0"</span> <span class="s2">"$@"</span> <span class="o">&&</span> <span class="p">[</span> <span class="p">]</span> <span class="k">if</span> <span class="kp">false</span>
<span class="c1">#!ruby</span>
<span class="c1"># This needs ruby 2.0, Subversion and Git.</span>
<span class="c1"># As a Ruby committer, run this in an SVN repository</span>
<span class="c1"># to commit a change.</span>
<span class="nb">require</span> <span class="s1">'tempfile'</span>
<span class="nb">require</span> <span class="s1">'net/http'</span>
</code></pre>
<p>I would expect all of the various Ripper APIs (<code>lex</code>, <code>sexp</code>, <code>sexp_raw</code>, <code>new.parse</code>, etc.) to start parsing on line 4, because that's what the parser does. Instead, it starts parsing on line 1.</p> Ruby master - Bug #20397 (Open): The nkf license in LEGAL file seems to be obsoletehttps://bugs.ruby-lang.org/issues/203972024-03-27T17:22:36Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>The LEGAL file seems to contain <a href="https://github.com/ruby/ruby/blob/a69f0047cb489c136001937442c1d2ffd8ea1dd7/LEGAL?plain=1#L730-L746" class="external">obsolete information</a> about nkf license.</p>
<p>It seems that nkf indeed use such license, but in upstream, it was first changed to <a href="https://github.com/nurse/nkf/commit/c12280757bfb275d6f9e6b0bf6293a28b060e77b" class="external">MIT</a> and then immediately to <a href="https://github.com/nurse/nkf/commit/2ed3e1c270f1deb9487f7bc7d7586030fe7dabc5" class="external">zlib</a> license.</p>
<p>Ruby has picked up that change with <a class="changeset" title="* ext/nkf/nkf-utf8/nkf.c: Update nkf to 2.0.9. revert -s meaning as Shift_JIS, etc. git-svn-id..." href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/13313688b243882aff7815598ddd9fcbae69bc17">git|13313688b243882aff7815598ddd9fcbae69bc17</a></p>
<p>Maybe <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/5">@naruse (Yui NARUSE)</a> can comment about this.</p> Ruby master - Feature #20396 (Open): ObjectSpace.dump_all(string_value: false): skip dumping the ...https://bugs.ruby-lang.org/issues/203962024-03-27T08:29:34Zbyroot (Jean Boussier)byroot@ruby-lang.org
<p><code>ObjectSpace.dump_all</code> is a very useful method to debug memory leaks and such, hence is frequently needed in production. But since all the 7bit strings content is included in the dump, it incur the risk of leaking personal data, or secrets.</p>
<p>Also, in many case the strings content isn't that helpful and is just making the dump much bigger for no good reason. And only pure-ASCII strings are dumped this way, which means all the tools that process these dumps should already be compatible with a dump without any string content.</p>
<a name="Feature"></a>
<h3 >Feature<a href="#Feature" class="wiki-anchor">¶</a></h3>
<p>I propose to add another optional parameter to <code>dump_all</code>: <code>string_value: false</code>. When passed, no String content is ever dumped regardless of its coderange.</p>
<p>Implementation: <a href="https://github.com/ruby/ruby/pull/10382" class="external">https://github.com/ruby/ruby/pull/10382</a></p>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1677">@zzak (zzak _)</a></p> Ruby master - Bug #20395 (Open): Invalid license note in vsnprintf.chttps://bugs.ruby-lang.org/issues/203952024-03-26T11:19:39Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>I am looking into Ruby licenses and I stumble upon vsnprintf.c, namely about these lines:</p>
<pre><code>/*
* IMPORTANT NOTE:
* --------------
* From ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
* paragraph 3 above is now null and void.
*/
</code></pre>
<p>I doubt the note is valid since <a class="changeset" title="* missing/crypt.c: replaced with 4.4BSD version. * missing/erf.c: ditto. * missing/vsnprintf.c:..." href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/626f1ee196fe06514d66771ff0e3f82d7686af25">git|626f1ee196fe06514d66771ff0e3f82d7686af25</a>, which actually removes the 3rd clause, while the (broken) URL refers to "4bsd". Can somebody please review? The note from the URL can be likely viewed e.g. <a href="https://www.freebsd.org/copyright/license/" class="external">here</a></p> Ruby master - Misc #20387 (Open): Meta-ticket for ASAN supporthttps://bugs.ruby-lang.org/issues/203872024-03-22T01:58:03Zkjtsanaktsidis (KJ Tsanaktsidis)kjtsanaktsidis@gmail.com
<p>I was asked to provide a bit of information about the current status of ASAN in CRuby, so I thought I'd open this meta-ticket to track all of the work I've been performing on fixing up address sanitizer support.</p>
<p>So far, I have fixed the following issues related to ASAN support:</p>
<ul>
<li>
<a href="https://bugs.ruby-lang.org/issues/20001" class="external">https://bugs.ruby-lang.org/issues/20001</a> + <a href="https://github.com/ruby/ruby/pull/9505" class="external">https://github.com/ruby/ruby/pull/9505</a>, which dealt with two main themes:
<ul>
<li>Pushing the logic for capturing the start of the machine stack much closer to the top of the call stack, so that VALUEs stored close to the top of the machine stack get marked properly</li>
<li>Marking VALUEs stored on ASAN fake stacks during machine stack marking</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20220" class="external">https://bugs.ruby-lang.org/issues/20220</a> + <a href="https://github.com/ruby/ruby/pull/9734" class="external">https://github.com/ruby/ruby/pull/9734</a>, which made M:N threading notify ASAN about stack switches in the same way that fibers do
<ul>
<li>Note: ASAN still doesn't work with M:N threading, but that actually has nothing to do with ASAN; it's because the most recent versions of Clang which are needed for ASAN just don't work with M:N threading either. See <a href="https://bugs.ruby-lang.org/issues/20243" class="external">https://bugs.ruby-lang.org/issues/20243</a> for more info about that.</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20273" class="external">https://bugs.ruby-lang.org/issues/20273</a> + <a href="https://github.com/ruby/ruby/pull/10012" class="external">https://github.com/ruby/ruby/pull/10012</a>, which disables <code>callcc</code> (and the associated tests) when ASAN is enabled
<ul>
<li>callcc is very rarely used in real code and the way it works is just fundamentally incompatible with ASAN (it performs longjmp's which I think are technically undefined behaviour)</li>
</ul>
</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20221" class="external">https://bugs.ruby-lang.org/issues/20221</a> + <a href="https://github.com/ruby/ruby/pull/9865" class="external">https://github.com/ruby/ruby/pull/9865</a>, which ignore some global symbols that ASAN defines from the global symbol leak checker</li>
<li>
<a href="https://bugs.ruby-lang.org/issues/20274" class="external">https://bugs.ruby-lang.org/issues/20274</a> + <a href="https://github.com/ruby/ruby/pull/10087" class="external">https://github.com/ruby/ruby/pull/10087</a>, which ignores some false positive tests about memory leaks when ASAN is enabl</li>
<li>I updated the ASAN docs in <a href="https://github.com/ruby/ruby/pull/9922" class="external">https://github.com/ruby/ruby/pull/9922</a> to more closely reflect current reality</li>
</ul>
<p>The current state of things is that, by following the instructions in <a href="https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md" class="external">https://github.com/ruby/ruby/blob/master/doc/contributing/building_ruby.md</a>, you can successfully build Ruby with ASAN enabled, however, the test suite has several failures. I'm currently working on addressing these:</p>
<p>The next step is to merge <a href="https://github.com/ruby/ruby/pull/10122" class="external">https://github.com/ruby/ruby/pull/10122</a> (<a href="https://bugs.ruby-lang.org/issues/20310" class="external">https://bugs.ruby-lang.org/issues/20310</a>) which I plan to do next week (I'm currently away on a work trip). That makes sure that VALUEs stored in ASAN fake stacks from threads other than the currently running thread get marked during GC.</p>
<p>After that, I need to push up patches for the remaining few issues. I mostly have these patches ready to go already; in fact, last week I got the full <code>make check</code> suite passing all tests with ASAN enabled!</p>
<p>Once that's working, I'd like to investigate how ASAN can fit into CRuby's CI matrix somewhere so that it <em>stays</em> working, although I have not thought too deeply about this yet.</p>
<p>I will provide further updates on this ticket so anybody interested can stay in the loop.</p> Ruby master - Feature #20384 (Open): RubyVM::InstructionSequence.{new,compile} use --parser optionhttps://bugs.ruby-lang.org/issues/203842024-03-20T20:27:42Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>Right now we have <code>RubyVM::InstructionSequence.compile</code> and <code>RubyVM::InstructionSequence.compile_prism</code>. We introduced this API in order to properly test the integration, even when running with <code>--parser=parse.y</code>.</p>
<p>I'm running into issues, however, when tests are comparing between <code>eval</code> and <code>RubyVM::InstructionSequence.new</code>. The latter always uses <code>parse.y</code>, even if <code>--parser=prism</code> is passed on the command line. I would like to change that so that <code>RubyVM::InstructionSequence.{new,compile}</code> respects the <code>--parser</code> option so that it's consistent.</p>
<p>Would this change be okay? It would only impact processes with <code>--parser=prism</code>, so I don't imagine there's any kind of risk here.</p> Ruby master - Feature #20351 (Open): Optionally extract common GC routines into a DSOhttps://bugs.ruby-lang.org/issues/203512024-03-20T14:57:13Zeightbitraptor (Matthew Valentine-House)matt@eightbitraptor.com
<p><a href="https://github.com/ruby/ruby/pull/10302" class="external">Github PR#10302</a></p>
<p><strong>NOTE: This proposal does not change the default build of Ruby, and therefore<br>
should NOT cause performance degradation for Ruby built in the usual way</strong></p>
<p>Our long term goal is to standardise Ruby's GC interface, allowing alternative<br>
GC implementations to be used. This will be acheived by optionally building<br>
Ruby's GC as a shared object; enabling it to be replaced at runtime using using<br>
<code>LD_LIBRARY_PATH</code>. eg:</p>
<pre><code>LD_LIBRARY_PATH=/custom_gc_location ruby script.rb
</code></pre>
<p>This ticket proposes the first step towards this goal. A new experimental build<br>
option, <code>--enable-shared-gc</code>, that will compile and link a module into the built<br>
<code>ruby</code> binary as a shared object - <code>miniruby</code> will remain statically linked to<br>
the existing GC in all cases.</p>
<p>Similar methods of replacing functionality relied on by Ruby have<br>
precedent. <code>jemalloc</code> uses <code>LD_PRELOAD</code> to replace <code>glibc</code> provided <code>malloc</code> and<br>
<code>free</code> at runtime. Although this project will be the first time a technique such<br>
as this has been used to replace core Ruby functionality.</p>
<p>This flag will be marked as experimental & <strong>disabled by default</strong>.</p>
<p><a href="https://github.com/ruby/ruby/pull/10302" class="external">The PR linked from this ticket</a> implements the new build flag, along with the<br>
absolute minimum code required to test it's implementation (a single debug<br>
function).</p>
<p>The implementation of the new build flag is based on the existing implementation<br>
of <code>--enable-shared</code> and behaves as follows:</p>
<ul>
<li>
<p><code>--enable-shared --enable-shared-gc</code></p>
<p>This will build both <code>libruby</code> and <code>librubygc</code> as shared objects. <code>ruby</code> will<br>
link dynamically to both <code>libruby</code> and <code>librubygc</code>.</p>
</li>
<li>
<p><code>--disable-shared --enable-shared-gc</code></p>
<p>This will build <code>librubygc</code> as a shared object, and build <code>libruby</code> as a<br>
static object. <code>libruby</code> will link dynamically to <code>librubygc</code> and <code>ruby</code> will<br>
be statically linked to <code>libruby</code>.</p>
</li>
<li>
<p><code>--disable-shared-gc</code></p>
<p><strong>This will be the default</strong>, and when this case is true the build behaviour<br>
will be exactly the same as it is currently. ie. the existing Ruby GC will be<br>
built and linked statically into either <code>ruby</code> or <code>libruby.so</code> depending on<br>
the state of <code>--enable-shared</code>.</p>
</li>
</ul>
<p>We are aware that there will be a small performance penalty from moving the GC<br>
logic into a shared object, but this is an opt-in configuration turned on at<br>
build time intended to be used by experienced users.</p>
<p>Still, we anticipate that, even with this configuration turned on, this penalty<br>
will be negligible compared the the benefit that being able to use high<br>
performance GC algorithms will provide.</p>
<p>This performance penalty is also the reason that <strong>this feature will be disabled<br>
by default</strong>. There will be no performance impact for anyone compiling Ruby in<br>
the usual manner, without explicitly enabling this feature.</p>
<p>We have discussed this proposal with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> who has approved our work on this<br>
project - having a clear abstraction between the VM and the GC will enable us to<br>
iterate faster on improvements to Ruby's existing GC.</p>
<a name="Motivation"></a>
<h2 >Motivation<a href="#Motivation" class="wiki-anchor">¶</a></h2>
<p>In the long term we want to provide the ability to override the current Ruby GC<br>
implementation in order to:</p>
<ul>
<li>Experiment with modern high-performance GC implementations, such as Immix, G1,<br>
LXR etc.</li>
<li>Easily split-test changes to the GC, or the GC tuning, in production without<br>
having to rebuild Ruby</li>
<li>Easily use debug builds of the GC to help identify production problems and<br>
bottlenecks without having to rebuild Ruby</li>
<li>Encourage the academic memory management research community to consider Ruby<br>
for their research (the current work on <a href="https://github.com/mmtk/mmtk-ruby" class="external">MMTk & Ruby</a> is a good example of<br>
this).</li>
</ul>
<a name="Future-work"></a>
<h2 >Future work<a href="#Future-work" class="wiki-anchor">¶</a></h2>
<p>The initial implementation of the shared GC module in this PR is deliberately<br>
small, and exists only for testing the build system integration.</p>
<p>The next steps are to identify boundaries between the GC and the VM and begin to<br>
extract common functionality into this GC wrapper module to serve as the<br>
foundation of our GC interface.</p>
<a name="Whos-working-on-this"></a>
<h2 >Who's working on this<a href="#Whos-working-on-this" class="wiki-anchor">¶</a></h2>
<ul>
<li><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/31800">@eightbitraptor (Matthew Valentine-House)</a></li>
<li><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/73">@tenderlovemaking (Aaron Patterson)</a></li>
<li><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/42491">@peterzhu2118 (Peter Zhu)</a></li>
<li><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/9236">@eileencodes (Eileen Uchitelle)</a></li>
</ul> Ruby master - Feature #20350 (Open): Return chilled string from Symbol#to_shttps://bugs.ruby-lang.org/issues/203502024-03-19T21:06:42ZDan0042 (Daniel DeLorme)
<p>During Ruby 2.7 development there was an attempt to return a frozen string from Symbol#to_s (<a class="issue tracker-2 status-1 priority-4 priority-default" title="Feature: Add a way to request a frozen string from to_s (Open)" href="https://bugs.ruby-lang.org/issues/16150#note-22">#16150#note-22</a>)</p>
<p>This had to be rolled back due to incompatibility, but now we have chilled strings (<a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Enable `frozen_string_literal` by default (Closed)" href="https://bugs.ruby-lang.org/issues/20205">#20205</a>)</p>
<p>Symbol#to_s can safely return a chilled string, giving developers time to fix warnings before switching to a frozen string.</p> Ruby master - Feature #20349 (Open): Pattern Matching - Expose local variable captureshttps://bugs.ruby-lang.org/issues/203492024-03-19T17:58:11Zbaweaver (Brandon Weaver)keystonelemur@gmail.com
<p>In Regular Expressions we have the ability to utilize <code>Regexp.last_match</code> (<a href="https://ruby-doc.org/3.2.2/Regexp.html#method-c-last_match" class="external">link</a>) to access the most recent match data from a regular expression match. I would like to propose that we have similar functionality for pattern matching:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"rubocop"</span>
<span class="k">def</span> <span class="nf">ast_from</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="k">case</span> <span class="n">string</span>
<span class="k">when</span> <span class="no">String</span> <span class="k">then</span> <span class="n">processed_source_from</span><span class="p">(</span><span class="n">string</span><span class="p">).</span><span class="nf">ast</span>
<span class="k">when</span> <span class="no">RuboCop</span><span class="o">::</span><span class="no">ProcessedSource</span> <span class="k">then</span> <span class="n">string</span><span class="p">.</span><span class="nf">ast</span>
<span class="k">when</span> <span class="no">RuboCop</span><span class="o">::</span><span class="no">AST</span><span class="o">::</span><span class="no">Node</span> <span class="k">then</span> <span class="n">string</span>
<span class="k">else</span> <span class="kp">nil</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">longform_block?</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="n">node</span> <span class="k">in</span> <span class="p">[</span><span class="ss">:block</span><span class="p">,</span> <span class="c1"># s(:block,</span>
<span class="p">[</span><span class="ss">:send</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">target_method</span><span class="p">],</span> <span class="c1"># s(:send, s(:array), :select),</span>
<span class="p">[[</span><span class="ss">:arg</span><span class="p">,</span> <span class="n">v</span><span class="p">]],</span> <span class="c1"># s(:args, s(:arg, :v)),</span>
<span class="p">[</span><span class="ss">:send</span><span class="p">,</span> <span class="p">[</span><span class="ss">:lvar</span><span class="p">,</span> <span class="o">^</span><span class="n">v</span><span class="p">],</span> <span class="n">block_method</span><span class="p">]</span> <span class="c1"># s(:send, s(:lvar, :v), :even?))</span>
<span class="p">]</span>
<span class="k">end</span>
<span class="n">longform_block?</span><span class="p">(</span><span class="n">ast_from</span><span class="p">(</span><span class="s2">"[1, 2, 3].select { |v| v.even? }"</span><span class="p">))</span>
<span class="c1"># => true</span>
<span class="c1"># Name is not important, idea is, name can be debated. `source` is used to not</span>
<span class="c1"># show AST nodes</span>
<span class="no">PatternMatch</span><span class="p">.</span><span class="nf">last_match</span><span class="p">.</span><span class="nf">transform_values</span><span class="p">(</span><span class="o">&</span><span class="ss">:source</span><span class="p">)</span>
<span class="c1"># => {:node=>"[1, 2, 3].select { |v| v.even? }",</span>
<span class="c1"># :result=>"[1, 2, 3].select { |v| v.even? }",</span>
<span class="c1"># :target=>"[1, 2, 3]",</span>
<span class="c1"># :target_method=>:select,</span>
<span class="c1"># :v=>:v,</span>
<span class="c1"># :block_method=>:even?}</span>
<span class="c1"># Hacky version to show how / where behavior could be captured</span>
<span class="k">def</span> <span class="nf">longform_block?</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">node</span> <span class="k">in</span> <span class="p">[</span><span class="ss">:block</span><span class="p">,</span> <span class="c1"># s(:block,</span>
<span class="p">[</span><span class="ss">:send</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="n">target_method</span><span class="p">],</span> <span class="c1"># s(:send, s(:array), :select),</span>
<span class="p">[[</span><span class="ss">:arg</span><span class="p">,</span> <span class="n">v</span><span class="p">]],</span> <span class="c1"># s(:args, s(:arg, :v)),</span>
<span class="p">[</span><span class="ss">:send</span><span class="p">,</span> <span class="p">[</span><span class="ss">:lvar</span><span class="p">,</span> <span class="o">^</span><span class="n">v</span><span class="p">],</span> <span class="n">block_method</span><span class="p">]</span> <span class="c1"># s(:send, s(:lvar, :v), :even?))</span>
<span class="p">]</span>
<span class="n">pp</span><span class="p">(</span><span class="nb">binding</span><span class="p">.</span><span class="nf">local_variables</span><span class="p">.</span><span class="nf">to_h</span> <span class="p">{</span> <span class="p">[</span><span class="n">_1</span><span class="p">,</span> <span class="nb">binding</span><span class="p">.</span><span class="nf">local_variable_get</span><span class="p">(</span><span class="n">_1</span><span class="p">).</span><span class="nf">then</span> <span class="p">{</span> <span class="o">|</span><span class="n">s</span><span class="o">|</span> <span class="n">s</span><span class="p">.</span><span class="nf">source</span> <span class="k">rescue</span> <span class="n">s</span> <span class="p">}]</span> <span class="p">})</span>
<span class="n">result</span>
<span class="k">end</span>
</code></pre> Ruby master - Feature #20347 (Assigned): Separate docs task from allhttps://bugs.ruby-lang.org/issues/203472024-03-19T09:10:29Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I would like to migrate RDoc as bundled gems at Ruby 3.5.</p>
<p>We need to handle <code>install-doc</code> and related task with that. I removed <code>docs</code> task from <code>all</code> and re-order <code>docs</code> task at <code>install-all</code>.</p>
<p><a href="https://github.com/ruby/ruby/pull/10282" class="external">https://github.com/ruby/ruby/pull/10282</a></p>
<p>It works with RDoc as bundled gems. We can keep current behavior with this migration.</p>
<p>I hope to merge changes for <code>all</code> task and re-order <code>install-all</code> task at Ruby 3.4.</p>
<p><a href="https://github.com/ruby/ruby/pull/10282/commits/b160083175aed062c320b8d76eafe1c8706309d4" class="external">https://github.com/ruby/ruby/pull/10282/commits/b160083175aed062c320b8d76eafe1c8706309d4</a></p>
<p>After that, the default <code>make</code> task will not generate rdoc. We need to add <code>make all docs</code> for that.</p> Ruby master - Bug #20346 (Open): FiberScheduler.unblock not called by Thread#join when Thread bod...https://bugs.ruby-lang.org/issues/203462024-03-18T19:06:21Zforthoney (Seong-Heon Jung)castlehoneyjung@gmail.com
<p>When using a <code>Ractor.take</code> inside a different thread, <code>Thread#join</code> on the thread running <code>Ractor.take</code> fails to call <code>FiberScheduler.unblock</code>. The below code can replicate this behavior</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"async"</span>
<span class="k">class</span> <span class="nc">RactorWrapper</span>
<span class="k">def</span> <span class="nf">initialize</span>
<span class="vi">@ractor</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">recv</span> <span class="c1"># Ractor doesn't start until explicitly told to</span>
<span class="c1"># Do some calculations</span>
<span class="n">fib</span> <span class="o">=</span> <span class="o">-></span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o"><</span> <span class="mi">2</span> <span class="p">?</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">fib</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="p">}</span>
<span class="n">fib</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">take_async</span>
<span class="vi">@ractor</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="kp">nil</span><span class="p">)</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="vi">@ractor</span><span class="p">.</span><span class="nf">take</span> <span class="p">}.</span><span class="nf">join</span><span class="p">.</span><span class="nf">value</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Async</span> <span class="k">do</span> <span class="o">|</span><span class="n">task</span><span class="o">|</span>
<span class="mi">10000</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span>
<span class="n">task</span><span class="p">.</span><span class="nf">async</span> <span class="k">do</span>
<span class="no">RactorWrapper</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">take_async</span>
<span class="nb">puts</span> <span class="n">i</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>The above code deadlocks, and when we leave a debugging print statement inside of <code>Async</code>'s scheduler's <code>block</code> and <code>unblock</code> method, we can confirm that we only call <code>Scheduler.block</code>, and never <code>Scheduler.unblock</code></p> Ruby master - Feature #20345 (Open): Add `--target-rbconfig` option to mkmfhttps://bugs.ruby-lang.org/issues/203452024-03-18T16:26:54Zkatei (Yuta Saito)
<a name="Motivation"></a>
<h2 >Motivation<a href="#Motivation" class="wiki-anchor">¶</a></h2>
<p>Today, CRuby runs on many platforms. But not all platforms are capable of running build tools (e.g. WebAssembly/WASI), so cross-target compilation against extensions libraries is essential for those platforms.</p>
<p>We currently have 3 major mkmf users (<code>extconf.rb</code> consumers in in other words):</p>
<ol>
<li>CRuby build system</li>
<li>rake-compiler</li>
<li>RubyGems</li>
</ol>
<p>[1] CRuby build system and [2] rake-compiler have their bespoke tricks to support cross compilation but [3] does not support cross compilation yet. So we are going to support cross-compilation in RubyGems to unlock the use of gems including non-precompiled extension libraries.</p>
<p>However, introducing the same tricks to RubyGems to support cross compilation as well as the other two is not ideal and cannot handle some edge cases properly.<br>
Therefore, this proposal aims to add cross-compilation support in mkmf itself and remove the need for special tricks in mkmf users.</p>
<p>Note that cross-compilation here includes:</p>
<ul>
<li>Cross <em>platform</em> compilation: Build extension libraries for platform A on platform B.</li>
<li>Cross <em>ruby version</em> compilation: Build extension libraries for Ruby X with running mkmf.rb bundled with Ruby X on Ruby Y.</li>
</ul>
<a name="Existing-Solutions"></a>
<h2 >Existing Solutions<a href="#Existing-Solutions" class="wiki-anchor">¶</a></h2>
<p>We currently have two solutions to cross-compile extension libraries, but both solutions are based on faking <code>rbconfig</code>.</p>
<a name="CRuby-build-system"></a>
<h3 >CRuby build system<a href="#CRuby-build-system" class="wiki-anchor">¶</a></h3>
<p>CRuby build system is capable for cross-compiling extension libraries for cross-platform and cross ruby version.<br>
The key trick here is that CRuby build system generates -fake.rb that fakes <code>RUBY_</code> constants like <code>RUBY_PLATFORM</code> and loads just built <code>rbconfig</code> describing Ruby version X for platform A and prevents loading <code>rbconfig</code> for Ruby version Y for platform B.</p>
<p>As a result, this fakes the global <code>RbConfig</code> constant and mkmk generates Makefile using the faked <code>RbConfig</code>.</p>
<a name="rake-compiler"></a>
<h3 >rake-compiler<a href="#rake-compiler" class="wiki-anchor">¶</a></h3>
<p>rake-compiler also fakes <code>RbConfig</code> as well as CRuby build system does. One of the notable tricks here is that the faking script loads <code>resolv</code>, which expects the original <code>RUBY_PLATFORM</code>, at first and fake RbConfig after that.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># From https://github.com/rake-compiler/rake-compiler/blob/7357f9e917dae79350687782c22596a036693405/lib/rake/extensiontask.rb#L559-L563</span>
<span class="c1"># Pre-load resolver library before faking, in order to avoid error</span>
<span class="c1"># "cannot load such file -- win32/resolv" when it is required later on.</span>
<span class="c1"># See also: https://github.com/tjschuck/rake-compiler-dev-box/issues/5</span>
<span class="nb">require</span> <span class="s1">'resolv'</span>
<span class="nb">require</span> <span class="s1">'rbconfig'</span>
</code></pre>
<p>This has been introduced as a workaround but this indicates that the faking method cannot be generally applied.</p>
<a name="Problems"></a>
<h2 >Problems<a href="#Problems" class="wiki-anchor">¶</a></h2>
<p>Based on insights from the existing solutions, the problems here are:</p>
<ol>
<li>There is no way to tell the target <code>RbConfig</code> to <code>mkmf</code> without polluting the global <code>RbConfig</code> constant.</li>
<li>There is no public API to retrieve the deployment target info, so existing <code>extconf.rb</code> assumes <code>::RbConfig</code> is the one.</li>
</ol>
<a name="Proposal"></a>
<h2 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h2>
<p>I propose adding those interfaces to <code>mkmf</code>:</p>
<ol>
<li>
<code>--target-rbconfig</code> option to override the RbConfig used for generating Makefiles without replacing the global top-level <code>RbConfig</code> module.</li>
<li>
<code>MakeMakefile::RbConfig</code> constant to access the RbConfig for the target platform.<br>
By default, it's an alias of top-level <code>RbConfig</code>. If <code>--target-rbconfig</code> is given, it points to the specified <code>RbConfig</code> definition.</li>
</ol>
<pre><code data-language="console=">$ ruby extconf.rb --target-rbconfig=path/to/rbconfig.rb
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"mkmf"</span>
<span class="nb">system</span><span class="p">(</span>
<span class="s2">"./libyaml/configure"</span><span class="p">,</span>
<span class="c1"># Before:</span>
<span class="c1"># "--host=#{RbConfig::CONFIG['host']}",</span>
<span class="s2">"--host=</span><span class="si">#{</span><span class="no">MakeMakefile</span><span class="o">::</span><span class="no">RbConfig</span><span class="o">::</span><span class="no">CONFIG</span><span class="p">[</span><span class="s1">'host'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
<span class="o">...</span>
<span class="p">)</span>
<span class="c1"># Before:</span>
<span class="c1"># case RUBY_PLATFORM</span>
<span class="k">case</span> <span class="no">MakeMakefile</span><span class="o">::</span><span class="no">RbConfig</span><span class="o">::</span><span class="no">CONFIG</span><span class="p">[</span><span class="s1">'platform'</span><span class="p">]</span>
<span class="k">when</span> <span class="sr">/mswin|mingw|bccwin/</span>
<span class="o">...</span>
<span class="k">when</span> <span class="sr">/linux/</span>
<span class="o">...</span>
<span class="k">end</span>
<span class="n">create_makefile</span><span class="p">(</span><span class="s2">"psych"</span><span class="p">)</span>
</code></pre>
<p>Extension library authors who want to support cross-compilation just need to replace their use of some constants in <code>extconf.rb</code> that assume the config describes the deployment target. Here is the list of faked constant variables and corresponding representations compatible with cross-compilation.</p>
<table>
<thead>
<tr>
<th align="left">Before</th>
<th align="left">After (to make the ext x-compile ready)</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left"><code>RbConfig</code></td>
<td align="left"><code>MakeMakefile::RbConfig</code></td>
</tr>
<tr>
<td align="left"><code>RUBY_PLATFORM</code></td>
<td align="left"><code>MakeMakefile::RbConfig::CONFIG["platform"]</code></td>
</tr>
<tr>
<td align="left"><code>RUBY_VERSION</code></td>
<td align="left"><code>MakeMakefile::RbConfig::expand("$(MAJOR).$(MINOR).$(TEENY)")</code></td>
</tr>
<tr>
<td align="left"><code>RUBY_DESCRIPTION</code></td>
<td align="left">No corresponding config entry</td>
</tr>
</tbody>
</table>
<a name="Compatibility"></a>
<h2 >Compatibility<a href="#Compatibility" class="wiki-anchor">¶</a></h2>
<p>This is a completely additive change, so I expect there is no compatibility issues for existing <code>extconf.rb</code>.</p>
<p>Note that migrating <code>RbConfig</code> to <code>MakeMakefile::RbConfig</code> does not break existing faked <code>RbConfig</code> based cross-compilation because <code>MakeMakefile::RbConfig</code> is an alias of <code>::RbConfig</code> by default and it's the faked config describing the deployment target in this scenario.</p>
<p>Also extension library authors who want to support cross-compilation and want to keep build with older Ruby before this change can include the following snippet at the beginning of <code>extconf.rb</code>:</p>
<pre><code data-language="ruby=">MakeMakefile::RbConfig ||= RbConfig
</code></pre>
<a name="Implementation"></a>
<h2 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h2>
<p>Literally a few lines of changes: <a href="https://github.com/kateinoigakukun/ruby/commit/9f3090c26ae1e5712dee702c19ba7a50695dd86a" class="external">https://github.com/kateinoigakukun/ruby/commit/9f3090c26ae1e5712dee702c19ba7a50695dd86a</a></p>
<a name="Evaluation"></a>
<h2 >Evaluation<a href="#Evaluation" class="wiki-anchor">¶</a></h2>
<p>I ported nokogiri gem, which has <a href="https://github.com/sparklemotion/nokogiri/blob/v1.16.3/ext/nokogiri/extconf.rb" class="external">1k lines of <code>extconf.rb</code></a> and several platform specific branches, to WebAssembly/WASI with this change, and the new API was enough to satisfy the cross-compilation scenario.</p> Ruby master - Bug #20344 (Open): argument stack underflow (-1)https://bugs.ruby-lang.org/issues/203442024-03-18T15:37:22Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>This file produces argument stack underflow, since ruby 2.5.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">proc</span> <span class="k">do</span>
<span class="k">next</span> <span class="k">if</span> <span class="kp">true</span>
<span class="k">case</span> <span class="kp">nil</span>
<span class="k">when</span> <span class="s2">"a"</span>
<span class="k">next</span>
<span class="k">when</span> <span class="s2">"b"</span>
<span class="k">when</span> <span class="s2">"c"</span>
<span class="nb">proc</span> <span class="p">{}</span>
<span class="k">end</span>
<span class="k">next</span> <span class="k">unless</span> <span class="kp">true</span>
<span class="k">end</span>
</code></pre>
<pre><code>-- raw disasm--------
trace: 100
0000 nop ( 1)
<L000> [sp: 0, unremovable: 1, refcnt: 5]
trace: 1
<L004> [sp: 0, unremovable: 0, refcnt: 1]
adjust: [label: 0]
0001 putnil ( 2)
0002 leave ( 13)
<L008> [sp: 1, unremovable: 0, refcnt: 1]
adjust: [label: 0]
0003 putnil ( 6)
0004 leave ( 13)
adjust: [label: 8]
0005 jump <L005> ( 5)
0007 pop ( 7)
0008 jump <L005> ( 7)
* 0010 pop ( 8)
trace: 1
<L011> [sp: -1, unremovable: 1, refcnt: 1]
0011 putself ( 9)
0012 send <calldata:proc, 0>, nil ( 9)
<L012> [sp: -1, unremovable: 0, refcnt: 2]
0015 pop ( 9)
<L005> [sp: 1, unremovable: 0, refcnt: 2]
trace: 1
0016 putnil ( 12)
<L001> [sp: -1, unremovable: 0, refcnt: 3]
trace: 200
0017 leave ( 13)
---------------------
</code></pre> Ruby master - Bug #20342 (Open): Top level `public`, `private` and `ruby2_keywords` do not work i...https://bugs.ruby-lang.org/issues/203422024-03-16T10:21:57Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>With this file:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># load.rb</span>
<span class="kp">public</span> <span class="k">def</span> <span class="nf">f</span> <span class="o">=</span> <span class="ss">:ok</span>
</code></pre>
<p>It is OK when <code>require</code>d.</p>
<pre><code data-language="sh-session">$ ruby -r ./load.rb -e 'p f'
:ok
</code></pre>
<p>Simple <code>load</code> is OK too.</p>
<pre><code data-language="sh-session">$ ruby -e 'load ARGV[0]; p f' load.rb
:ok
</code></pre>
<p>Wrapped <code>load</code> fails.</p>
<pre><code data-language="sh-session">$ ruby -e 'load ARGV[0], true' load.rb
load.rb:1:in 'public': undefined method 'f' for class 'Object' (NameError)
public def f = :ok
^^^^^^
from load.rb:1:in '<top (required)>'
from -e:1:in 'Kernel#load'
from -e:1:in '<main>'
</code></pre> Ruby master - Bug #20340 (Open): Ractor comments not applying to constant targetshttps://bugs.ruby-lang.org/issues/203402024-03-14T19:39:40Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>In this example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">C</span><span class="p">,</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">foo: </span><span class="n">bar</span> <span class="p">}</span>
</code></pre>
<p>You get:</p>
<pre><code>== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(1,17)>
0000 putobject :foo ( 1)[Li]
0002 putself
0003 opt_send_without_block <calldata!mid:bar, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0005 newhash 2
0007 dup
0008 expandarray 1, 0
0011 putspecialobject 3
0013 setconstant :C
0015 leave
</code></pre>
<p>But there's no difference from:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># shareable_constant_value: literal</span>
<span class="no">C</span><span class="p">,</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">foo: </span><span class="n">bar</span> <span class="p">}</span>
</code></pre>
<p>I would have expected:</p>
<pre><code>== disasm: #<ISeq:<main>@test.rb:1 (1,0)-(2,16)>
0000 putobject RubyVM::FrozenCore ( 2)[Li]
0002 putobject :foo
0004 putobject RubyVM::FrozenCore
0006 putself
0007 opt_send_without_block <calldata!mid:bar, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0009 putobject "C"
0011 opt_send_without_block <calldata!mid:ensure_shareable, argc:2, ARGS_SIMPLE>
0013 newhash 2
0015 opt_send_without_block <calldata!mid:make_shareable, argc:1, ARGS_SIMPLE>
0017 dup
0018 expandarray 1, 0
0021 putspecialobject 3
0023 setconstant :C
0025 leave
</code></pre>
<p>Is this omission intentional? For context, I'm building this in prism and I need to know if I should explicitly disable this behavior.</p> Ruby master - Bug #20337 (Open): Complex#inspect mutates the string returned by `real.inspect`https://bugs.ruby-lang.org/issues/203372024-03-14T11:23:54ZEregon (Benoit Daloze)
<pre><code>irb(main):001:0> n = Numeric.new
=> #<Numeric:0x00007f81b2308578>
irb(main):004:0> class Numeric; def inspect = super.freeze; end
=> :inspect
irb(main):006:0> Complex(n, 1).inspect
(irb):6:in `inspect': can't modify frozen String: "#<Numeric:0x00007f81b2308578>" (FrozenError)
from (irb):6:in `<main>'
from /home/eregon/.rubies/ruby-3.2.2/lib/ruby/gems/3.2.0/gems/irb-1.6.2/exe/irb:11:in `<top (required)>'
from /home/eregon/.rubies/ruby-3.2.2/bin/irb:25:in `load'
from /home/eregon/.rubies/ruby-3.2.2/bin/irb:25:in `<main>'
</code></pre>
<p>It feels wrong to mutate the result of inspect at least in general, for instance <code>true.inspect</code> is frozen.</p>
<p>Discovered by <a href="https://github.com/ruby/spec/pull/1142" class="external">https://github.com/ruby/spec/pull/1142</a></p> Ruby master - Misc #20336 (Open): DevMeeting-2024-04-17https://bugs.ruby-lang.org/issues/203362024-03-14T10:17:44Zmame (Yusuke Endoh)mame@ruby-lang.org
<a name="The-next-dev-meeting"></a>
<h1 >The next dev meeting<a href="#The-next-dev-meeting" class="wiki-anchor">¶</a></h1>
<p><strong>Date: 2024/04/17 13:00-17:00</strong> (JST)<br>
Log: <em>TBD</em></p>
<ul>
<li>Dev meeting <em>IS NOT</em> a decision-making place. All decisions should be done at the bug tracker.</li>
<li>Dev meeting is a place we can ask Matz, nobu, nurse and other developers directly.</li>
<li>Matz is a very busy person. Take this opportunity to ask him. If you can not attend, other attendees can ask instead of you (if attendees can understand your issue).</li>
<li>We will write a record of the discussion in the file or to each ticket in English.</li>
<li>All activities are best-effort (keep in mind that most of us are volunteer developers).</li>
<li>The date, time and place of the meeting are scheduled according to when/where we can reserve Matz's time.</li>
<li>
<em>DO NOT</em> discuss then on this ticket, please.</li>
</ul>
<a name="Call-for-agenda-items"></a>
<h1 >Call for agenda items<a href="#Call-for-agenda-items" class="wiki-anchor">¶</a></h1>
<p>If you have a ticket that you want matz and committers to discuss, please post it into this ticket in the following format:</p>
<pre><code>* [Ticket ref] Ticket title (your name)
* Comment (A summary of the ticket, why you put this ticket here, what point should be discussed, etc.)
</code></pre>
<p>Example:</p>
<pre><code>* [Feature #14609] `Kernel#p` without args shows the receiver (ko1)
* I feel this feature is very useful and some people say :+1: so let discuss this feature.
</code></pre>
<ul>
<li>It is recommended to add a comment by 2024/04/14. We hold a preparatory meeting to create an agenda a few days before the dev-meeting.</li>
<li>The format is strict. We'll use <a href="https://gist.github.com/mame/b0390509ce1491b43610b9ebb665eb86" class="external">this script to automatically create an markdown-style agenda</a>. We may ignore a comment that does not follow the format.</li>
<li>Your comment is mandatory. We cannot read all discussion of the ticket in a limited time. We appreciate it if you could write a short summary and update from a previous discussion.</li>
</ul> Ruby master - Feature #20335 (Open): `Thread.each_caller_location` should accept the same argumen...https://bugs.ruby-lang.org/issues/203352024-03-14T09:32:41Zbyroot (Jean Boussier)byroot@ruby-lang.org
<p><code>Thread.each_caller_location</code> was added to Ruby 3.2 as part of [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Add block or filtered forms of Kernel#caller to allow early bail-out (Closed)" href="https://bugs.ruby-lang.org/issues/16663">#16663</a>] and is a very useful API for emitting warnings with a proper source location and similar use cases.</p>
<p>However in many of the cases where I used it, or seen it used, it was needed to skip the first, or a couple frames:</p>
<p>Examples:</p>
<p>Sorbet: <a href="https://github.com/Shopify/sorbet/blob/b27a14c247ace7cabdf0f348bfb11fdf0b7e9ab4/gems/sorbet-runtime/lib/types/private/caller_utils.rb#L6-L18" class="external">https://github.com/Shopify/sorbet/blob/b27a14c247ace7cabdf0f348bfb11fdf0b7e9ab4/gems/sorbet-runtime/lib/types/private/caller_utils.rb#L6-L18</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">find_caller</span>
<span class="n">skiped_first</span> <span class="o">=</span> <span class="kp">false</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">each_caller_location</span> <span class="k">do</span> <span class="o">|</span><span class="n">loc</span><span class="o">|</span>
<span class="k">unless</span> <span class="n">skiped_first</span>
<span class="n">skiped_first</span> <span class="o">=</span> <span class="kp">true</span>
<span class="k">next</span>
<span class="k">end</span>
<span class="k">next</span> <span class="k">if</span> <span class="n">loc</span><span class="p">.</span><span class="nf">path</span><span class="o">&</span><span class="p">.</span><span class="nf">start_with?</span><span class="p">(</span><span class="s2">"<internal:"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">loc</span> <span class="k">if</span> <span class="k">yield</span><span class="p">(</span><span class="n">loc</span><span class="p">)</span>
<span class="k">end</span>
<span class="kp">nil</span>
<span class="k">end</span>
</code></pre>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1241">@fxn (Xavier Noria)</a> 's PR: <a href="https://github.com/ruby/ruby/blob/9c2e686719a5a4df5ea0b8a3b6a373ca6003c229/lib/bundled_gems.rb#L140-L146" class="external">https://github.com/ruby/ruby/blob/9c2e686719a5a4df5ea0b8a3b6a373ca6003c229/lib/bundled_gems.rb#L140-L146</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"> <span class="n">frames_to_skip</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">location</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="no">Thread</span><span class="p">.</span><span class="nf">each_caller_location</span> <span class="k">do</span> <span class="o">|</span><span class="n">cl</span><span class="o">|</span>
<span class="k">if</span> <span class="n">frames_to_skip</span> <span class="o">>=</span> <span class="mi">1</span>
<span class="n">frames_to_skip</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">next</span>
<span class="k">end</span>
<span class="c1"># snipp...</span>
</code></pre>
<a name="Proposal"></a>
<h3 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h3>
<p>I think it would be very useful if <code>Thread.each_caller_location</code> accepted the same arguments as <code>caller</code> and <code>caller_locations</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#each_caller_location(start = 1, length = nil)</span>
<span class="c1">#each_caller_location(range)</span>
</code></pre>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1604">@jeremyevans0 (Jeremy Evans)</a> what do you think?</p> Ruby master - Bug #20332 (Open): After upgrading to ruby v 3.2.3 rb_scan_args() skips argument va...https://bugs.ruby-lang.org/issues/203322024-03-12T18:06:04Zpraveenrocket (Praveen N)
<p>Hi,</p>
<p>Note: I am not an expert at ruby.</p>
<p>I am working on ibm_db gem, its an adapter developed using ruby C extension, which helps ruby & rails applications to connect to DB2 database.<br>
Here is a github link for its source <a href="https://github.com/ibmdb/ruby-ibmdb/tree/master" class="external">https://github.com/ibmdb/ruby-ibmdb/tree/master</a></p>
<p>As of now ibm_db gem is compatible with ruby v 3.1.<br>
Now I am trying to make ibm_db gem compatible with ruby v 3.2.3.</p>
<p>All my test cases were working for ruby v 3.1, but post upgrading to ruby v 3.2.3, most of my test cases are failing.</p>
<p>After debugging using gdb what I see is, my ruby test cases calls ruby C extension API passing required arguments, but inside C extension code arguments are not parsed, indeed nothing is read. Because of this most of test cases are failing.</p>
<p>Below is a sample ruby script which when run calls ibm_db extension,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="err">$</span> <span class="n">irb</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">001</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="nb">require</span> <span class="s1">'ibm_db'</span>
<span class="o">=></span> <span class="kp">true</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">002</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">conn</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="p">.</span><span class="nf">connect</span><span class="p">(</span><span class="s2">"DATABASE=sample;HOSTNAME=waldevdbclnxtst06.dev.rocketsoftware.com;PORT=60000;PROTOCOL=TCPIP;UID=zurbie;PWD=A2m8test;"</span><span class="p">,</span><span class="s1">''</span><span class="p">,</span><span class="s1">''</span><span class="p">)</span>
<span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">2</span><span class="p">:</span> <span class="ss">warning: </span><span class="n">undefining</span> <span class="n">the</span> <span class="n">allocator</span> <span class="n">of</span> <span class="no">T_DATA</span> <span class="k">class</span> <span class="nc">IBM_DB::Connection</span>
<span class="o">=></span> <span class="c1">#<IBM_DB::Connection:0x00007ff60314ce58></span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">003</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="n">stmt</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="p">.</span><span class="nf">exec</span> <span class="n">conn</span><span class="p">,</span><span class="s1">'create table abc(C1 int)'</span>
<span class="o">=></span> <span class="kp">false</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">004</span><span class="p">:</span><span class="mi">0</span><span class="o">></span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">005</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="no">IBM_DB</span><span class="p">.</span><span class="nf">close</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="o">=></span> <span class="kp">true</span>
<span class="n">irb</span><span class="p">(</span><span class="n">main</span><span class="p">):</span><span class="mo">006</span><span class="p">:</span><span class="mi">0</span><span class="o">></span> <span class="nb">exit</span>
</code></pre>
<p>Above, If you observe IBM_DB.exec is called passing two arguments conn & string with create table query.<br>
In extension code <a href="https://github.com/ibmdb/ruby-ibmdb/blob/master/IBM_DB_Driver/ibm_db.c" class="external">https://github.com/ibmdb/ruby-ibmdb/blob/master/IBM_DB_Driver/ibm_db.c</a>,<br>
below function will be called</p>
<pre><code class="c syntaxhl" data-language="c"><span class="n">VALUE</span> <span class="nf">ibm_db_exec</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="n">VALUE</span> <span class="o">*</span><span class="n">argv</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">self</span><span class="p">)</span>
<span class="p">{</span>
<span class="p">....</span>
<span class="n">rb_scan_args</span><span class="p">(</span><span class="n">argc</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="s">"21"</span><span class="p">,</span> <span class="o">&</span><span class="n">connection</span><span class="p">,</span> <span class="o">&</span><span class="n">stmt</span><span class="p">,</span> <span class="o">&</span><span class="n">options</span><span class="p">);</span>
<span class="p">......</span>
<span class="p">}</span>
</code></pre>
<p>Note: Please refer <a href="https://github.com/ibmdb/ruby-ibmdb/blob/master/IBM_DB_Driver/ibm_db.c" class="external">https://github.com/ibmdb/ruby-ibmdb/blob/master/IBM_DB_Driver/ibm_db.c</a> for complete code.</p>
<p>rb_scan_args used to parse arguments very well in ruby v 3.1, but now its failing to do so. I see stmt parameter doesnt hold anything.</p>
<p>I just want to know whats issue here, Am I passing arguments in wrong way (in ruby script), or am I not using rb_scan_args properly ?</p>
<p>To reproduce,<br>
Install ruby v 3.2.3,<br>
Install ibm_db gem version 5.4.1 (latest)<br>
Run above sample ruby script using IRB.</p>
<p>Response at earliest is much appreciated.</p>
<p>Thanks<br>
Praveen</p> Ruby master - Feature #20331 (Open): Should parser warn hash duplication and when clause?https://bugs.ruby-lang.org/issues/203312024-03-12T13:15:42Zyui-knk (Kaneko Yuichiro)
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>Right now, parser warns duplicated hash keys (#1) and when clause (#2).<br>
For example,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span><span class="mi">1</span> <span class="o">=></span> <span class="ss">:a</span><span class="p">,</span> <span class="mi">1</span> <span class="o">=></span> <span class="ss">:b</span><span class="p">}</span>
<span class="c1"># => warning: key 1 is duplicated and overwritten on line 1</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">case</span> <span class="mi">2</span>
<span class="k">when</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span>
<span class="k">else</span>
<span class="k">end</span>
<span class="c1"># => test.rb:2: warning: duplicated `when' clause with line 2 is ignored</span>
</code></pre>
<p>The parser compares different cardinality numbers.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span>
<span class="mi">1</span> <span class="o">=></span> <span class="ss">:a</span><span class="p">,</span>
<span class="mh">0x1</span> <span class="o">=></span> <span class="ss">:b</span><span class="p">,</span>
<span class="mb">0b1</span> <span class="o">=></span> <span class="ss">:b</span><span class="p">,</span>
<span class="mi">0</span><span class="n">d1</span> <span class="o">=></span> <span class="ss">:b</span><span class="p">,</span>
<span class="mi">0</span><span class="n">o1</span> <span class="o">=></span> <span class="ss">:b</span><span class="p">,</span>
<span class="p">}</span>
<span class="c1"># => test.rb:2: warning: key 1 is duplicated and overwritten on line 3</span>
<span class="c1"># => test.rb:3: warning: key 1 is duplicated and overwritten on line 4</span>
<span class="c1"># => test.rb:4: warning: key 1 is duplicated and overwritten on line 5</span>
<span class="c1"># => test.rb:5: warning: key 1 is duplicated and overwritten on line 6</span>
</code></pre>
<a name="Problem"></a>
<h1 >Problem<a href="#Problem" class="wiki-anchor">¶</a></h1>
<p>Currently this is implemeted by converting string like <code>"123"</code> to Ruby Object and compare them.<br>
It's needed to remove Ruby Object from parse.y for Universal Parser.<br>
I created PR <a href="https://github.com/ruby/ruby/pull/10079" class="external">https://github.com/ruby/ruby/pull/10079</a> which implements bignum for parse.y without dependency on Ruby Object, however nobu and mame express concern about the cost and benefit of implmenting bignum for parser.<br>
I want to discuss which is the best approach for this problem.</p>
<p>By the way, it's needed to calculate irreducible fraction for Rational key if we will keep warning messages.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="err">$</span> <span class="n">ruby</span> <span class="o">-</span><span class="n">wc</span> <span class="o">-</span><span class="n">e</span> <span class="s1">'{10.2r => :a, 10.2r => :b}'</span>
<span class="o">-</span><span class="n">e</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span> <span class="ss">warning: </span><span class="n">key</span> <span class="p">(</span><span class="mi">51</span><span class="o">/</span><span class="mi">5</span><span class="p">)</span> <span class="n">is</span> <span class="n">duplicated</span> <span class="ow">and</span> <span class="n">overwritten</span> <span class="n">on</span> <span class="n">line</span> <span class="mi">1</span>
<span class="o">-</span><span class="n">e</span><span class="p">:</span><span class="mi">1</span><span class="p">:</span> <span class="ss">warning: </span><span class="n">unused</span> <span class="n">literal</span> <span class="n">ignored</span>
<span class="no">Syntax</span> <span class="no">OK</span>
</code></pre>
<a name="Options"></a>
<h1 >Options<a href="#Options" class="wiki-anchor">¶</a></h1>
<a name="1-Warnings-on-parser"></a>
<h2 >1. Warnings on parser<a href="#1-Warnings-on-parser" class="wiki-anchor">¶</a></h2>
<p>Pros:</p>
<ul>
<li>Users of Universal Parser don't need to implement warnings by themselves. I guess developers of other Ruby implementation may get benefit of reducing their effort.</li>
<li>Warnings are shown by <code>ruby -wc</code>.</li>
</ul>
<p>Cons:</p>
<ul>
<li>We need to maintain bignum implementation for parser.</li>
</ul>
<p>There are two approaches for this option.</p>
<a name="1-1-Implement-bignum-for-parser"></a>
<h3 >1-1. Implement bignum for parser<a href="#1-1-Implement-bignum-for-parser" class="wiki-anchor">¶</a></h3>
<p>The PR is this approach, implementing sub set of Ruby bignum for parser.</p>
<a name="1-2-Extract-existing-bignum-implementation-then-use-it"></a>
<h3 >1-2. Extract existing bignum implementation then use it<a href="#1-2-Extract-existing-bignum-implementation-then-use-it" class="wiki-anchor">¶</a></h3>
<p>Make existing bignum implementation to be independent of Ruby Object and use it from both bignum.c and parse.y.</p>
<a name="2-Moving-warnings-logic-into-compile-phase"></a>
<h2 >2. Moving warnings logic into compile phase<a href="#2-Moving-warnings-logic-into-compile-phase" class="wiki-anchor">¶</a></h2>
<p>We can use Ruby Object in compile.c. Then moving the logic into compile.c solves this problem.</p>
<p>Pros:</p>
<ul>
<li>No need to implement bignum for parser.</li>
</ul>
<p>Cons:</p>
<ul>
<li>Users of Universal Parser need to implement warnings by themselves.</li>
<li>Warnings are not shown by <code>ruby -wc</code>.</li>
</ul> Ruby master - Bug #20330 (Open): [BUG] Segmentation fault at 0xffffffffffffffffhttps://bugs.ruby-lang.org/issues/203302024-03-09T10:33:11Zl33tname (Sir l33tname)sirl33tname@gmail.com
<p>I get a segfault from ruby on fly.io (a platform to run full stack apps).<br>
As you can see from the stacktracke im using a jemalloc version but im getting the same crash with the<br>
ruby:3.3.0-slim docker image. (Thats the docker file: <a href="https://github.com/Binaergewitter/serious-bg/blob/be890bf6af110b02f22f359d395bedb0659f4243/Dockerfile.fly" class="external">https://github.com/Binaergewitter/serious-bg/blob/be890bf6af110b02f22f359d395bedb0659f4243/Dockerfile.fly</a> based on quay.io/evl.ms/fullstaq-ruby:3.3.0-jemalloc-slim)</p>
<p>Reverting back to ruby 3.2.3 solved the issue for now: <a href="https://github.com/Binaergewitter/serious-bg/commit/4eed4119706303383ce5994c796bc5a8a1813afc" class="external">https://github.com/Binaergewitter/serious-bg/commit/4eed4119706303383ce5994c796bc5a8a1813afc</a></p>
<p>I was not able to reproduce it locally.<br>
But the application is open source -> <a href="https://github.com/Binaergewitter/serious-bg" class="external">https://github.com/Binaergewitter/serious-bg</a></p>
<pre><code>2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info][ 0.037737] Spectre V2 : WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!
2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info][ 0.041193] PCI: Fatal: No config space access function found
2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info] INFO Starting init (commit: 913ad9c)...
2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info] INFO Preparing to run: `bundle exec puma -e production -b tcp://0.0.0.0:8080 -t 0:5` as root
2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info] INFO [fly api proxy] listening at /.fly/api
2024-03-09T09:31:07Z app[3d8d7d99f40128] iad [info]2024/03/09 09:31:07 listening on [fdaa:0:182f:a7b:22c:a04d:ac4:2]:22 (DNS: [fdaa::3]:53)
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems.rb:165: [BUG] Segmentation fault at 0xffffffffffffffff
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +jemalloc [x86_64-linux]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- Control frame information -----------------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]c:0005 p:0074 s:0023 e:000021 CLASS /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems.rb:165
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]c:0004 p:0045 s:0019 e:000018 TOP /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems.rb:115 [FINISH]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]c:0003 p:---- s:0012 e:000011 CFUNC :require
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]c:0002 p:0012 s:0007 e:000006 TOP <internal:gem_prelude>:2 [FINISH]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]c:0001 p:0000 s:0003 E:0001c0 DUMMY [FINISH]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- Ruby level backtrace information ----------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]<internal:gem_prelude>:2:in `<internal:gem_prelude>'
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]<internal:gem_prelude>:2:in `require'
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems.rb:115:in `<top (required)>'
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems.rb:165:in `<module:Gem>'
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- Threading information ---------------------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]Total ractor count: 1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]Ruby thread count for this ractor: 1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- Machine register context ------------------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] RIP: 0x00007fc80e6c51b4 RBP: 0x00007fc80c400050 RSP: 0x00007ffee5a36a98
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] RAX: 0xffffffffffffffff RBX: 0x00007fc80c4003e8 RCX: 0x00007fc80c4003e9
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] RDX: 0xffffffffffffffff RDI: 0x00007fc80d8170d0 RSI: 0x000000000000c2d3
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] R8: 0x0000000000000000 R9: 0x00007fc80da36340 R10: 0x0000000000000001
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] R11: 0x00007fc80e026880 R12: 0x00007fc80ea4b860 R13: 0x0000000000000001
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] R14: 0x00007fc80c400550 R15: 0x00007fc80e026880 EFL: 0x0000000000010202
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- C level backtrace information -------------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_vm_bugreport+0x96b) [0x7fc80e77adab]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_bug_for_fatal_signal+0x100) [0x7fc80e576720]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(sigsegv+0x4b) [0x7fc80e6c74db]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/lib/x86_64-linux-gnu/libc.so.6(0x7fc80e13a050) [0x7fc80e13a050]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_insert_aux+0x364) [0x7fc80e6c51b4]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x8f) [0x7fc80e6c552f]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x6d) [0x7fc80e6c550d]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x6d) [0x7fc80e6c550d]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x6d) [0x7fc80e6c550d]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x6d) [0x7fc80e6c550d]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(redblack_cache_ancestors+0x6d) [0x7fc80e6c550d]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_shape_get_next+0x2a8) [0x7fc80e6c6458]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_class_ivar_set+0xb0) [0x7fc80e742560]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_ivar_set+0x83) [0x7fc80e742743]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(vm_exec_core+0x8ca) [0x7fc80e75ea1a]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_vm_exec+0x179) [0x7fc80e7640f9]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(require_internal+0xd2f) [0x7fc80e5e84bf]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_require_string+0x66) [0x7fc80e5e9156]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(vm_call_cfunc_other+0x169) [0x7fc80e74cf29]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(vm_exec_core+0x129) [0x7fc80e75e279]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_vm_exec+0x179) [0x7fc80e7640f9]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(ruby_opt_init.part.0+0xbf) [0x7fc80e6c185f]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(load_file_internal+0x47e) [0x7fc80e6c1e7e]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(rb_ensure+0x110) [0x7fc80e580190]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(process_options+0x15fb) [0x7fc80e6c38ab]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(ruby_process_options+0x145) [0x7fc80e6c3ff5]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3(ruby_options+0xc9) [0x7fc80e581249]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby(0x56225c24510a) [0x56225c24510a]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/lib/x86_64-linux-gnu/libc.so.6(0x7fc80e12524a) [0x7fc80e12524a]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x85) [0x7fc80e125305]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]/usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby(_start+0x21) [0x56225c245151]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]-- Other runtime information -----------------------------------------------
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]* Loaded script: /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]* Loaded features:
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 0 enumerator.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 1 thread.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 2 fiber.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 3 rational.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 4 complex.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 5 ruby2_keywords.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 6 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 7 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 8 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/rbconfig.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 9 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems/compatibility.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 10 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems/defaults.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 11 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems/deprecate.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info] 12 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/rubygems/errors.rb
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]* Process memory map:
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]56225c244000-56225c245000 r--p 00000000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]56225c245000-56225c246000 r-xp 00001000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]56225c246000-56225c247000 r--p 00002000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]56225c247000-56225c248000 r--p 00002000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]56225c248000-56225c249000 rw-p 00003000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80994f000-7fc80a000000 r--s 00000000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a000000-7fc80a400000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a54a000-7fc80a720000 r--s 00000000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a720000-7fc80a7b0000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a7bf000-7fc80a7c0000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a7c0000-7fc80a861000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a861000-7fc80a862000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a862000-7fc80a903000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a903000-7fc80a904000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a904000-7fc80a9a5000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a9a5000-7fc80a9a6000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80a9a6000-7fc80aa47000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aa47000-7fc80aa48000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aa48000-7fc80aae9000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aae9000-7fc80aaea000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aaea000-7fc80ab8b000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ab8b000-7fc80ab8c000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ab8c000-7fc80ac2d000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ac2d000-7fc80ac2e000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ac2e000-7fc80accf000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80accf000-7fc80acd0000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80acd0000-7fc80ad71000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ad71000-7fc80ad72000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ad72000-7fc80ae13000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ae13000-7fc80ae14000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ae14000-7fc80aeb5000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aeb5000-7fc80aeb6000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aeb6000-7fc80af57000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80af57000-7fc80af58000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80af58000-7fc80aff9000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80aff9000-7fc80affa000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80affa000-7fc80b09b000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b09b000-7fc80b09c000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b09c000-7fc80b13d000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b13d000-7fc80b13e000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b13e000-7fc80b1df000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b1df000-7fc80b1e0000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b1e0000-7fc80b281000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b281000-7fc80b282000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b282000-7fc80b323000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b323000-7fc80b324000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b324000-7fc80b3c5000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b3c5000-7fc80b3c6000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b3c6000-7fc80b467000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b467000-7fc80b468000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b468000-7fc80b509000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b509000-7fc80b50a000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b50a000-7fc80b5ab000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b5ab000-7fc80b5ac000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b5ac000-7fc80b64d000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b64d000-7fc80b64e000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b64e000-7fc80b6ef000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b6ef000-7fc80b6f0000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b6f0000-7fc80b791000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b791000-7fc80b792000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b792000-7fc80b833000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b833000-7fc80b834000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b834000-7fc80b8d5000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b8d5000-7fc80b8d6000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b8d6000-7fc80b977000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b977000-7fc80b978000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80b978000-7fc80ba19000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ba19000-7fc80ba1a000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ba1a000-7fc80babb000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80babb000-7fc80babc000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80babc000-7fc80bb5d000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80bb5d000-7fc80bb5e000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80bb5e000-7fc80bbff000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80bbff000-7fc80bc00000 ---p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80bc00000-7fc80e000000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e010000-7fc80e020000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e020000-7fc80e070000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e074000-7fc80e075000 r--p 00000000 fe:00 136223 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e075000-7fc80e076000 r-xp 00001000 fe:00 136223 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e076000-7fc80e077000 r--p 00002000 fe:00 136223 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e077000-7fc80e078000 r--p 00002000 fe:00 136223 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e078000-7fc80e079000 rw-p 00003000 fe:00 136223 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/trans/transdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e079000-7fc80e07a000 r--p 00000000 fe:00 136179 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e07a000-7fc80e07b000 r-xp 00001000 fe:00 136179 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e07b000-7fc80e07c000 r--p 00002000 fe:00 136179 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e07c000-7fc80e07d000 r--p 00002000 fe:00 136179 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e07d000-7fc80e07e000 rw-p 00003000 fe:00 136179 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/ruby/3.3.0/x86_64-linux/enc/encdb.so
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e07e000-7fc80e085000 r--s 00000000 fe:00 131755 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e085000-7fc80e0dc000 r--p 00000000 fe:00 131399 /usr/lib/locale/C.utf8/LC_CTYPE
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0dc000-7fc80e0de000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0de000-7fc80e0e1000 r--p 00000000 fe:00 131804 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0e1000-7fc80e0f8000 r-xp 00003000 fe:00 131804 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0f8000-7fc80e0fc000 r--p 0001a000 fe:00 131804 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0fc000-7fc80e0fd000 r--p 0001d000 fe:00 131804 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0fd000-7fc80e0fe000 rw-p 0001e000 fe:00 131804 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e0fe000-7fc80e124000 r--p 00000000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e124000-7fc80e279000 r-xp 00026000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e279000-7fc80e2cc000 r--p 0017b000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e2cc000-7fc80e2d0000 r--p 001ce000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e2d0000-7fc80e2d2000 rw-p 001d2000 fe:00 131782 /usr/lib/x86_64-linux-gnu/libc.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e2d2000-7fc80e2e1000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e2e1000-7fc80e2f1000 r--p 00000000 fe:00 131821 /usr/lib/x86_64-linux-gnu/libm.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e2f1000-7fc80e364000 r-xp 00010000 fe:00 131821 /usr/lib/x86_64-linux-gnu/libm.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e364000-7fc80e3be000 r--p 00083000 fe:00 131821 /usr/lib/x86_64-linux-gnu/libm.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3be000-7fc80e3bf000 r--p 000dc000 fe:00 131821 /usr/lib/x86_64-linux-gnu/libm.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3bf000-7fc80e3c0000 rw-p 000dd000 fe:00 131821 /usr/lib/x86_64-linux-gnu/libm.so.6
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3c0000-7fc80e3c2000 r--p 00000000 fe:00 131791 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3c2000-7fc80e3d8000 r-xp 00002000 fe:00 131791 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3d8000-7fc80e3f2000 r--p 00018000 fe:00 131791 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3f2000-7fc80e3f3000 r--p 00031000 fe:00 131791 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3f3000-7fc80e3f4000 rw-p 00032000 fe:00 131791 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3f4000-7fc80e3fc000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3fc000-7fc80e3ff000 r--p 00000000 fe:00 134861 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libjemalloc.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e3ff000-7fc80e436000 r-xp 00003000 fe:00 134861 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libjemalloc.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e436000-7fc80e43e000 r--p 0003a000 fe:00 134861 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libjemalloc.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e43e000-7fc80e440000 r--p 00042000 fe:00 134861 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libjemalloc.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e440000-7fc80e441000 rw-p 00044000 fe:00 134861 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libjemalloc.so.1
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e441000-7fc80e442000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e442000-7fc80e445000 r--p 00000000 fe:00 131881 /usr/lib/x86_64-linux-gnu/libz.so.1.2.13
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e445000-7fc80e458000 r-xp 00003000 fe:00 131881 /usr/lib/x86_64-linux-gnu/libz.so.1.2.13
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e458000-7fc80e45f000 r--p 00016000 fe:00 131881 /usr/lib/x86_64-linux-gnu/libz.so.1.2.13
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e45f000-7fc80e460000 r--p 0001c000 fe:00 131881 /usr/lib/x86_64-linux-gnu/libz.so.1.2.13
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e460000-7fc80e461000 rw-p 0001d000 fe:00 131881 /usr/lib/x86_64-linux-gnu/libz.so.1.2.13
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e461000-7fc80e465000 r--s 00000000 fe:00 134645 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/bin/ruby
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e465000-7fc80e4b0000 r--p 00000000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e4b0000-7fc80e89a000 r-xp 0004b000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80e89a000-7fc80ea21000 r--p 00435000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea21000-7fc80ea38000 r--p 005bb000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea38000-7fc80ea3c000 rw-p 005d2000 fe:00 134864 /usr/lib/fullstaq-ruby/versions/3.3.0-jemalloc/lib/libruby.so.3.3.0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea3c000-7fc80ea53000 rw-p 00000000 00:00 0
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea53000-7fc80ea54000 r--p 00000000 fe:00 131764 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea54000-7fc80ea79000 r-xp 00001000 fe:00 131764 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea79000-7fc80ea83000 r--p 00026000 fe:00 131764 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea83000-7fc80ea85000 r--p 00030000 fe:00 131764 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7fc80ea85000-7fc80ea87000 rw-p 00032000 fe:00 131764 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7ffee523b000-7ffee5a3a000 rw-p 00000000 00:00 0 [stack]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7ffee5ba8000-7ffee5bac000 r--p 00000000 00:00 0 [vvar]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]7ffee5bac000-7ffee5bae000 r-xp 00000000 00:00 0 [vdso]
2024-03-09T09:31:08Z app[3d8d7d99f40128] iad [info]ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
</code></pre> Ruby master - Feature #20329 (Open): Clean up `--dump` sub-optionshttps://bugs.ruby-lang.org/issues/203292024-03-08T09:46:29Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>Currently we have 5 options for <code>--dump</code> command line option.</p>
<ul>
<li>insns</li>
<li>insns_without_opt</li>
<li>yydebug(+error-tolerant)</li>
<li>parsetree(+error-tolerant)</li>
<li>parsetree_with_comment(+error-tolerant)</li>
</ul>
<p>Among these, <code>insns_without_opt</code> is a variant of <code>insns</code>, and <code>parsetree_with_comment</code> is a variant of <code>parsetree</code>.<br>
However, there is now another way to specify variants (e.g. <code>+error-tolerant</code>).<br>
How about unifying the two so that the former can also be specified in the same form, such as <code>--dump=parsetree+comment+error-tolerant</code>?<br>
It also will be able to abbreviate as <code>parse+comm+err</code> or more.</p> Ruby master - Bug #20328 (Open): optparse omits the option's description in the --help output if ...https://bugs.ruby-lang.org/issues/203282024-03-07T22:03:25Zpostmodern (Hal Brodigan)postmodern.mod3@gmail.com
<p>If you define an option using <code>OptionParser#on</code>, but give the option's description as a multi-line Array, then the option's description is omitted from the <code>--help</code> output.</p>
<a name="Steps-To-Reproduce"></a>
<h2 >Steps To Reproduce<a href="#Steps-To-Reproduce" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#!/usr/bin/env ruby</span>
<span class="nb">require</span> <span class="s1">'optparse'</span>
<span class="n">optparser</span> <span class="o">=</span> <span class="no">OptionParser</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">opts</span><span class="o">|</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">banner</span> <span class="o">=</span> <span class="s1">'usage: test.rb [options]'</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="s1">'-o'</span><span class="p">,</span> <span class="s1">'--opt [OPT]'</span><span class="p">,</span> <span class="s1">'Line one'</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">opt</span><span class="o">|</span>
<span class="k">end</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="s1">'-m'</span><span class="p">,</span> <span class="s1">'--multiline-opt'</span><span class="p">,</span> <span class="p">[</span><span class="s1">'Line one'</span><span class="p">,</span> <span class="s1">'Line two'</span><span class="p">])</span> <span class="k">do</span> <span class="o">|</span><span class="nb">test</span><span class="o">|</span>
<span class="k">end</span>
<span class="n">opts</span><span class="p">.</span><span class="nf">on</span><span class="p">(</span><span class="s1">'-h'</span><span class="p">,</span> <span class="s1">'--help'</span><span class="p">,</span> <span class="s1">'Prints this help'</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">puts</span> <span class="n">opts</span>
<span class="nb">exit</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">optparser</span><span class="p">.</span><span class="nf">parse</span><span class="p">([</span><span class="s1">'--help'</span><span class="p">])</span>
</code></pre>
<a name="Expected-result"></a>
<h3 >Expected result<a href="#Expected-result" class="wiki-anchor">¶</a></h3>
<pre><code>usage: test.rb [options]
-o, --opt [OPT] Line one
-m, --multiline-opt Line one
Line two
-h, --help Prints this help
</code></pre>
<a name="Actual-Result"></a>
<h3 >Actual Result<a href="#Actual-Result" class="wiki-anchor">¶</a></h3>
<pre><code>usage: test.rb [options]
-o, --opt [OPT] Line one
-m, --multiline-opt
-h, --help Prints this help
</code></pre>
<p>or an <code>ArgumentError</code> should be raised if Array descriptions are not allowed/supported.</p>
<a name="Version-Info"></a>
<h2 >Version Info<a href="#Version-Info" class="wiki-anchor">¶</a></h2>
<p>Tested against optparse 0.1.0, 0.2.0, 0.3.1, and the master branch.</p> Ruby master - Bug #20325 (Open): Enumerator.product.size bug with zero * infinite enumeratorshttps://bugs.ruby-lang.org/issues/203252024-03-05T15:21:08Zmarcandre (Marc-Andre Lafortune)marcandre-ruby-core@marc-andre.ca
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">to_a</span> <span class="c1"># => [] (OK)</span>
<span class="no">Enumerator</span><span class="p">.</span><span class="nf">product</span><span class="p">([],</span> <span class="mi">1</span><span class="o">..</span><span class="p">).</span><span class="nf">size</span> <span class="c1"># => Infinity (Should be 0)</span>
</code></pre> Ruby master - Misc #20320 (Open): Using OSU Open Source Lab native ppc64le/s390x CI services trig...https://bugs.ruby-lang.org/issues/203202024-03-01T16:26:28Zjaruga (Jun Aruga)
<p>We have been using Travis CI to run unit tests the native arm64/ppc64le/s390x in the ruby/ruby, ruby/zlib and ruby/prism repositories in the Ruby project.</p>
<p>One of the challenges is Travis CI's chronic unstable infra issues. To be fair, folks at Travis CI support are helpful, usually responding quickly, sometimes not. And I hope Travis CI will find the root causes of the issues. However, I would like to find alternative way to run the native ppc64le/s390x pipelines on pull-requests to change the current challenge fundamentally.</p>
<p>And I heard from folks at IBM that the there were CI services that we could run on the pull-requests. The CI services are Jenkins services provided by Oregon State University (OSU) Open Source Lab below. The CI services are the only alternative of running the native ppc64le/s390x pipelines on pull-requests as far as I know. As a note, we are already using SSH-accessing servers provided by OSU Open Source Lab.</p>
<ul>
<li>PowerPC64 (ppc64le): <a href="https://osuosl.org/services/powerdev/" class="external">https://osuosl.org/services/powerdev/</a> - POWER Continuous Integration (POWER CI)</li>
<li>IBM Z (s390x): <a href="https://osuosl.org/services/ibm-z/" class="external">https://osuosl.org/services/ibm-z/</a> - IBM Z Continuous Integration (IBM Z CI)</li>
</ul>
<p>Today I requested the CI services from the request form pages above. And I will try the services by myself first. Then if it looks good to us, I want to migrate the Travis CI ppc64le/s390x pipelines to the OSU Open Source Lab's ones. I will comment on this ticket when there are updates.</p>
<p>Note:<br>
Oregon State University Open Source Lab (OSUOSL) support email: <a href="mailto:support@osuosl.org" class="email">support@osuosl.org</a> and <a href="https://osuosl.org/contact/" class="external">other contacts</a>.</p> Ruby master - Bug #20319 (Open): Singleton class is being frozen lazily in some caseshttps://bugs.ruby-lang.org/issues/203192024-03-01T11:52:12Zandrykonchin (Andrew Konchin)
<p>I've noticed suspicious behaviour (it doesn't affect anything in practice for me though) when an object becomes frozen only its own singleton class becomes frozen immediately.</p>
<p>A singleton class of the object immediate singleton class becomes frozen lazily after <code>#singleton_class</code> method call:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">o</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="n">klass</span> <span class="o">=</span> <span class="n">o</span><span class="p">.</span><span class="nf">singleton_class</span><span class="p">.</span><span class="nf">singleton_class</span>
<span class="n">o</span><span class="p">.</span><span class="nf">freeze</span>
<span class="nb">puts</span> <span class="n">klass</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># false <== here we expect true</span>
<span class="nb">puts</span> <span class="n">o</span><span class="p">.</span><span class="nf">singleton_class</span><span class="p">.</span><span class="nf">singleton_class</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># true</span>
<span class="nb">puts</span> <span class="n">klass</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># true</span>
</code></pre>
<p>I would expect all created (and visible to user) singleton classes in an object singleton classes chain to become frozen immediately when the object gets frozen.</p> Ruby master - Feature #20318 (Open): Pattern matching `case ... in` support for triple-dot argumentshttps://bugs.ruby-lang.org/issues/203182024-03-01T03:11:07Zbradgessler (Brad Gessler)
<a name="Premise"></a>
<h1 >Premise<a href="#Premise" class="wiki-anchor">¶</a></h1>
<p>Sometimes when I'm creating a method for an API, I'd like to do pattern matching against the arguments. Today I have to do something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span> <span class="n">args</span><span class="p">:,</span> <span class="n">kwargs</span><span class="p">:,</span> <span class="ss">block: </span><span class="p">}</span>
<span class="k">in</span> <span class="ss">args: </span><span class="p">[</span><span class="nb">name</span><span class="p">]</span>
<span class="nb">puts</span> <span class="nb">name</span>
<span class="k">in</span> <span class="ss">args: </span><span class="p">[</span><span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="p">]</span>
<span class="nb">puts</span> <span class="s2">"Hi there </span><span class="si">#{</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">last_name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">in</span> <span class="ss">kwargs: </span><span class="p">{</span><span class="n">greeting</span><span class="p">:}</span>
<span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="n">greeting</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"No match: </span><span class="si">#{</span><span class="n">args</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">foo</span> <span class="s2">"Hi"</span>
<span class="n">foo</span> <span class="s2">"Brad"</span><span class="p">,</span> <span class="s2">"Gessler"</span>
<span class="n">foo</span> <span class="ss">greeting: </span><span class="s2">"Brad"</span>
</code></pre>
<p>Or an array like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
<span class="k">case</span> <span class="p">[</span><span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">,</span> <span class="n">block</span><span class="p">]</span>
<span class="k">in</span> <span class="p">[</span><span class="nb">name</span><span class="p">],</span> <span class="p">{},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="nb">name</span>
<span class="k">in</span> <span class="p">[</span><span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="p">],</span> <span class="p">{},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="s2">"Hi there </span><span class="si">#{</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">last_name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">in</span> <span class="p">[],</span> <span class="p">{</span><span class="n">greeting</span><span class="p">:},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="n">greeting</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"No match: </span><span class="si">#{</span><span class="n">args</span><span class="si">}</span><span class="s2">, </span><span class="si">#{</span><span class="n">kwargs</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">bar</span> <span class="s2">"Howdy"</span>
<span class="n">bar</span> <span class="s2">"Bradley"</span><span class="p">,</span> <span class="s2">"Gessler"</span>
<span class="n">bar</span> <span class="ss">greeting: </span><span class="s2">"Bradley"</span>
</code></pre>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<p>I'd like to propose the same thing, but for <code>...</code>, like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">case</span> <span class="o">...</span>
<span class="k">in</span> <span class="ss">args: </span><span class="p">[</span><span class="nb">name</span><span class="p">]</span>
<span class="nb">puts</span> <span class="nb">name</span>
<span class="k">in</span> <span class="ss">args: </span><span class="p">[</span><span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="p">]</span>
<span class="nb">puts</span> <span class="s2">"Hi there </span><span class="si">#{</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">last_name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">in</span> <span class="ss">kwargs: </span><span class="p">{</span><span class="n">greeting</span><span class="p">:}</span>
<span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="n">greeting</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"No match: </span><span class="si">#{</span><span class="n">args</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">foo</span> <span class="s2">"Hi"</span>
<span class="n">foo</span> <span class="s2">"Brad"</span><span class="p">,</span> <span class="s2">"Gessler"</span>
<span class="n">foo</span> <span class="ss">greeting: </span><span class="s2">"Brad"</span>
</code></pre>
<p>One thing I'm not sure sure about: the <code>args</code>, <code>kwargs</code>, and <code>block</code> names appear out of thin air, so ideally those could somehow be named or have a syntax that doesn't require those names.</p>
<p>The array would look like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">case</span> <span class="o">...</span>
<span class="k">in</span> <span class="p">[</span><span class="nb">name</span><span class="p">],</span> <span class="p">{},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="nb">name</span>
<span class="k">in</span> <span class="p">[</span><span class="n">first_name</span><span class="p">,</span> <span class="n">last_name</span><span class="p">],</span> <span class="p">{},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="s2">"Hi there </span><span class="si">#{</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">last_name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">in</span> <span class="p">[],</span> <span class="p">{</span><span class="n">greeting</span><span class="p">:},</span> <span class="kp">nil</span>
<span class="nb">puts</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="n">greeting</span><span class="si">}</span><span class="s2">"</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"No match: </span><span class="si">#{</span><span class="n">args</span><span class="si">}</span><span class="s2">, </span><span class="si">#{</span><span class="n">kwargs</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">bar</span> <span class="s2">"Howdy"</span>
<span class="n">bar</span> <span class="s2">"Bradley"</span><span class="p">,</span> <span class="s2">"Gessler"</span>
<span class="n">bar</span> <span class="ss">greeting: </span><span class="s2">"Bradley"</span>
</code></pre> Ruby master - Feature #20317 (Open): Removing the `allocate` method should cause `new` to failhttps://bugs.ruby-lang.org/issues/203172024-03-01T00:18:16Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>When you remove the <code>allocate</code> method from a class the you can't allocate the class via the <code>allocate</code> method. However, you <em>can</em> allocate the class via the <code>new</code> method:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Foo</span><span class="p">;</span> <span class="k">end</span>
<span class="no">Foo</span><span class="p">.</span><span class="nf">singleton_class</span><span class="p">.</span><span class="nf">undef_method</span><span class="p">(</span><span class="ss">:allocate</span><span class="p">)</span>
<span class="k">begin</span>
<span class="no">Foo</span><span class="p">.</span><span class="nf">allocate</span> <span class="c1"># doesn't work, of course</span>
<span class="k">rescue</span> <span class="no">NoMethodError</span>
<span class="k">end</span>
<span class="k">begin</span>
<span class="no">Class</span><span class="p">.</span><span class="nf">instance_method</span><span class="p">(</span><span class="ss">:allocate</span><span class="p">).</span><span class="nf">bind_call</span><span class="p">(</span><span class="no">Foo</span><span class="p">)</span> <span class="c1"># also doesn't work</span>
<span class="k">rescue</span> <span class="no">TypeError</span>
<span class="k">end</span>
<span class="no">Foo</span><span class="p">.</span><span class="nf">new</span> <span class="c1"># works?</span>
</code></pre>
<p>I think that when we remove the <code>allocate</code> method, the <code>new</code> method should also fail as there is no <code>allocate</code> method for <code>new</code> to call.</p> Ruby master - Bug #20316 (Open): Regexp quantifier behavior changes in different syntactic context.https://bugs.ruby-lang.org/issues/203162024-02-29T17:21:18Zjirkamarsik (Jirka Marsik)
<p>In the example below, adding a vertical bar to the end of a regular expression changes what is being matched by the preceding regular expression.</p>
<pre><code>irb(main):001:0> /(|a){3}b/.match("aab")
=> #<MatchData "aab" 1:"">
irb(main):002:0> /(|a){3}b|/.match("aab")
=> #<MatchData "aab" 1:"a">
</code></pre>
<p>This is because the <code>{3}</code> quantifier is compiled into a <code>repeat</code> loop which uses the <code>OP_NULL_CHECK_END_MEMST</code> operation to perform a capture-group sensitive null-check after every loop iteration. The logic behind the <code>OP_NULL_CHECK_END_MEMST</code> operation is implemented using the <code>STACK_NULL_CHECK_MEMST</code> macro in <code>regexec.c</code>. The <code>STACK_NULL_CHECK_MEMST</code> macro checks whether any capture groups have been updated inside the last loop iteration and it does so by searching the stack for <code>STK_MEM_START</code> entries. However, such entries are not used for all capture groups. They are only used by capture groups which are listed in <code>bt_mem_start</code>. A capture group is marked as needing such bookkeeping only when it is either referenced by a back-reference or it appears in certain syntactic contexts (see e.g. around line 4096 of <code>regcomp.c</code>). This looks like an optimization that tries to avoid polluting the stack with <code>STK_MEM_START</code> entries in cases in which they are not needed. However, in this case, not putting <code>STK_MEM_START</code> entries on the stack leads to a different match result.</p>
<p>In the example above, by adding a vertical bar to the end of the regexp, we have placed the group <code>(|a)</code> inside an alternation. This means that a different operation for tracking the state of the capture group is emitted in the compiled bytecode and this leads to a different result. Incidentally, this result should be the correct result, as the null-check ends up respecting the state of capture groups, as it tries to do in Ruby.</p>
<p>This is the compilation and execution of <code>/(|a){3}b/.match("aab")</code> with ONIG_DEBUG_PARSE_TREE, ONIG_DEBUG_COMPILE and ONIG_DEBUG_MATCH. Note that <code>mem-start:1</code> is used for tracking the state of capture group 1.</p>
<pre><code>PATTERN: /(|a){3}b/ (US-ASCII)
<list:55db929991f0>
<quantifier:55db92999230>{3,3}
<enclose:55db92999330> memory:1
<alt:55db929991b0>
<string:55db929992f0>
<string:55db929992b0>a
<string:55db929993b0>b
optimize: EXACT
anchor: []
sub anchor: []
exact: [b]: length: 1
code length: 37
0:[repeat:0:27] 7:[null-check-start:0] 10:[mem-start:1] 13:[push:(+5)] 18:[jump:(+2)]
23:[exact1:a] 25:[mem-end:1] 28:[null-check-end-memst:0] 31:[repeat-inc:0] 34:[exact1:b]
36:[end]
match_at: str: 139809364021904 (0x7f27e77a9290), end: 139809364021906 (0x7f27e77a9292), start: 139809364021904 (0x7f27e77a9290), sprev: 0 ((nil))
size: 2, start offset: 0
ofs> str stk:type addr:opcode
0> "ab" 0:Alt 0:[repeat:0:27]
0> "ab" 1:Rep 7:[null-check-start:0]
0> "ab" 2:NulChS 10:[mem-start:1]
0> "ab" 2:NulChS 13:[push:(+5)]
0> "ab" 3:Alt 18:[jump:(+2)]
0> "ab" 3:Alt 25:[mem-end:1]
0> "ab" 3:Alt 28:[null-check-end-memst:0]
NULL_CHECK_END_MEMST: skip id:0, s:139809364021904 (0x7f27e77a9290)
0> "ab" 3:Alt 34:[exact1:b]
0> "ab" 2:NulChS 23:[exact1:a]
1> "b" 2:NulChS 25:[mem-end:1]
1> "b" 2:NulChS 28:[null-check-end-memst:0]
1> "b" 2:NulChS 31:[repeat-inc:0]
1> "b" 3:RepInc 7:[null-check-start:0]
1> "b" 4:NulChS 10:[mem-start:1]
1> "b" 4:NulChS 13:[push:(+5)]
1> "b" 5:Alt 18:[jump:(+2)]
1> "b" 5:Alt 25:[mem-end:1]
1> "b" 5:Alt 28:[null-check-end-memst:0]
NULL_CHECK_END_MEMST: skip id:0, s:139809364021905 (0x7f27e77a9291)
1> "b" 5:Alt 34:[exact1:b]
2> "" 5:Alt 36:[end]
</code></pre>
<p>This is the compilation and execution of <code>/(|a){3}b|/.match("aab")</code> (where the group <code>(|a)</code> appears inside an alternation) with ONIG_DEBUG_PARSE_TREE, ONIG_DEBUG_COMPILE and ONIG_DEBUG_MATCH. Note that <code>mem-start-push:1</code> is used for tracking the state of capture group 1, not <code>mem-start:1</code>.</p>
<pre><code>PATTERN: /(|a){3}b|/ (US-ASCII)
<alt:55d9a91cc3c0>
<list:55d9a91cc200>
<quantifier:55d9a91cc240>{3,3}
<enclose:55d9a91cc340> memory:1
<alt:55d9a91cc1c0>
<string:55d9a91cc300>
<string:55d9a91cc2c0>a
<string:55d9a91cc480>b
<string:55d9a91cc400>
optimize: NONE
anchor: []
code length: 47
0:[push:(+41)] 5:[repeat:0:27] 12:[null-check-start:0] 15:[mem-start-push:1] 18:[push:(+5)]
23:[jump:(+2)] 28:[exact1:a] 30:[mem-end:1] 33:[null-check-end-memst:0] 36:[repeat-inc:0]
39:[exact1:b] 41:[jump:(+0)] 46:[end]
match_at: str: 140072854131304 (0x7f6540b69268), end: 140072854131306 (0x7f6540b6926a), start: 140072854131304 (0x7f6540b69268), sprev: 0 ((nil))
size: 2, start offset: 0
ofs> str stk:type addr:opcode
0> "ab" 0:Alt 0:[push:(+41)]
0> "ab" 1:Alt 5:[repeat:0:27]
0> "ab" 2:Rep 12:[null-check-start:0]
0> "ab" 3:NulChS 15:[mem-start-push:1]
0> "ab" 4:MemS 18:[push:(+5)]
0> "ab" 5:Alt 23:[jump:(+2)]
0> "ab" 5:Alt 30:[mem-end:1]
0> "ab" 5:Alt 33:[null-check-end-memst:0]
0> "ab" 5:Alt 36:[repeat-inc:0]
0> "ab" 6:RepInc 12:[null-check-start:0]
0> "ab" 7:NulChS 15:[mem-start-push:1]
0> "ab" 8:MemS 18:[push:(+5)]
0> "ab" 9:Alt 23:[jump:(+2)]
0> "ab" 9:Alt 30:[mem-end:1]
0> "ab" 9:Alt 33:[null-check-end-memst:0]
NULL_CHECK_END_MEMST: skip id:0, s:140072854131304 (0x7f6540b69268)
0> "ab" 9:Alt 39:[exact1:b]
0> "ab" 8:MemS 28:[exact1:a]
1> "b" 8:MemS 30:[mem-end:1]
1> "b" 8:MemS 33:[null-check-end-memst:0]
1> "b" 8:MemS 36:[repeat-inc:0]
1> "b" 9:RepInc 12:[null-check-start:0]
1> "b" 10:NulChS 15:[mem-start-push:1]
1> "b" 11:MemS 18:[push:(+5)]
1> "b" 12:Alt 23:[jump:(+2)]
1> "b" 12:Alt 30:[mem-end:1]
1> "b" 12:Alt 33:[null-check-end-memst:0]
1> "b" 12:Alt 36:[repeat-inc:0]
1> "b" 13:RepInc 39:[exact1:b]
2> "" 13:RepInc 41:[jump:(+0)]
2> "" 13:RepInc 46:[end]
</code></pre> Ruby master - Bug #20315 (Open): Quantifier expansion leads to different results in Regexp.https://bugs.ruby-lang.org/issues/203152024-02-29T16:59:34Zjirkamarsik (Jirka Marsik)
<p>Consider the following series of regular expression matches:</p>
<pre><code>irb(main):001:0> /(|a)(|a)(|a)(|a)(|a)b/.match("aaaab")
=> #<MatchData "aaaab" 1:"" 2:"a" 3:"a" 4:"a" 5:"a">
irb(main):002:0> /(|a)(|a)(|a)(|a)b/.match("aaab")
=> #<MatchData "aaab" 1:"" 2:"a" 3:"a" 4:"a">
irb(main):003:0> /(|a)(|a)(|a)b/.match("aab")
=> #<MatchData "aab" 1:"" 2:"a" 3:"a">
irb(main):004:0> /(|a)(|a)b/.match("ab")
=> #<MatchData "ab" 1:"" 2:"a">
</code></pre>
<p>Let <code>X^{N}</code> mean <code>N</code> concatenated repetitions of <code>X</code>. When matching the pattern <code>/(|a)^{N}b/</code> against <code>a^{N-1}b</code>, the first group will match the empty string and the last <code>N-1</code> groups will match <code>a</code>.</p>
<p>Now, let's look at this series of similar expressions, in which <code>(|a)^{N}</code> is replaced with <code>(|a){N}</code>, i.e. a counted quantifier.</p>
<pre><code>irb(main):001:0> /(|a){5}b/.match("aaaab")
=> #<MatchData "aaaab" 1:"">
irb(main):002:0> /(|a){4}b/.match("aaab")
=> #<MatchData "aaab" 1:"">
irb(main):003:0> /(|a){3}b/.match("aab")
=> #<MatchData "aab" 1:"">
irb(main):004:0> /(|a){2}b/.match("ab")
=> #<MatchData "ab" 1:"a">
</code></pre>
<p>When matching the pattern <code>/(|a){N}b/</code> against <code>a^{N-1}b</code>, the first <code>N-1</code> iterations will match <code>a</code> and the <code>N</code>-th iteration will match the empty string (compare this with the behavior of the first series of expressions). However, something strange happens when <code>N</code> is 2. We end up getting a result which is not consistent with this series, but looks like a result that belongs to the first series discussed above.</p>
<p>This is due to quantifier expansion done by the regexp compiler (see usages of <code>QUANTIFIER_EXPAND_LIMIT_SIZE</code> in <code>regcomp.c</code>). This is an optimization that tries to remove the overhead of managing a counted repetition during regex execution at the cost of increasing the size of the compiled regex bytecode. The source of the inconsistency is caused by the fact that this optimization can actually change the semantics of the regular expression, because as we have seen above, <code>X^{N}</code> (<code>X</code> repeated <code>N</code> times) can have different semantics from <code>X{N}</code> (a single <code>X</code> with an <code>{N}</code> quantifier).</p>
<p>Compilation and execution of <code>/(|a){3}b/.match("aab")</code> with <code>ONIG_DEBUG_PARSE_TREE</code>, <code>ONIG_DEBUG_COMPILE</code> and <code>ONIG_DEBUG_MATCH</code>:</p>
<pre><code>PATTERN: /(|a){3}b/ (US-ASCII)
<list:556161bb11f0>
<quantifier:556161bb1230>{3,3}
<enclose:556161bb1330> memory:1
<alt:556161bb11b0>
<string:556161bb12f0>
<string:556161bb12b0>a
<string:556161bb13b0>b
optimize: EXACT
anchor: []
sub anchor: []
exact: [b]: length: 1
code length: 37
0:[repeat:0:27] 7:[null-check-start:0] 10:[mem-start:1] 13:[push:(+5)] 18:[jump:(+2)]
23:[exact1:a] 25:[mem-end:1] 28:[null-check-end-memst:0] 31:[repeat-inc:0] 34:[exact1:b]
36:[end]
match_at: str: 140607416406704 (0x7fe1b71b92b0), end: 140607416406706 (0x7fe1b71b92b2), start: 140607416406704 (0x7fe1b71b92b0), sprev: 0 ((nil))
size: 2, start offset: 0
ofs> str stk:type addr:opcode
0> "ab" 0:Alt 0:[repeat:0:27]
0> "ab" 1:Rep 7:[null-check-start:0]
0> "ab" 2:NulChS 10:[mem-start:1]
0> "ab" 2:NulChS 13:[push:(+5)]
0> "ab" 3:Alt 18:[jump:(+2)]
0> "ab" 3:Alt 25:[mem-end:1]
0> "ab" 3:Alt 28:[null-check-end-memst:0]
NULL_CHECK_END_MEMST: skip id:0, s:140607416406704 (0x7fe1b71b92b0)
0> "ab" 3:Alt 34:[exact1:b]
0> "ab" 2:NulChS 23:[exact1:a]
1> "b" 2:NulChS 25:[mem-end:1]
1> "b" 2:NulChS 28:[null-check-end-memst:0]
1> "b" 2:NulChS 31:[repeat-inc:0]
1> "b" 3:RepInc 7:[null-check-start:0]
1> "b" 4:NulChS 10:[mem-start:1]
1> "b" 4:NulChS 13:[push:(+5)]
1> "b" 5:Alt 18:[jump:(+2)]
1> "b" 5:Alt 25:[mem-end:1]
1> "b" 5:Alt 28:[null-check-end-memst:0]
NULL_CHECK_END_MEMST: skip id:0, s:140607416406705 (0x7fe1b71b92b1)
1> "b" 5:Alt 34:[exact1:b]
2> "" 5:Alt 36:[end]
</code></pre>
<p>Compilation and execution of <code>/(|a){2}b/.match("ab")</code> with <code>ONIG_DEBUG_PARSE_TREE</code>, <code>ONIG_DEBUG_COMPILE</code> and <code>ONIG_DEBUG_MATCH</code>:</p>
<pre><code>PATTERN: /(|a){2}b/ (US-ASCII)
<list:55bbc826c1f0>
<quantifier:55bbc826c230>{2,2}
<enclose:55bbc826c330> memory:1
<alt:55bbc826c1b0>
<string:55bbc826c2f0>
<string:55bbc826c2b0>a
<string:55bbc826c3b0>b
optimize: EXACT
anchor: []
sub anchor: []
exact: [b]: length: 1
code length: 39
0:[mem-start:1] 3:[push:(+5)] 8:[jump:(+2)] 13:[exact1:a] 15:[mem-end:1]
18:[mem-start:1] 21:[push:(+5)] 26:[jump:(+2)] 31:[exact1:a] 33:[mem-end:1]
36:[exact1:b] 38:[end]
match_at: str: 140139875963504 (0x7f74db869270), end: 140139875963506 (0x7f74db869272), start: 140139875963504 (0x7f74db869270), sprev: 0 ((nil))
size: 2, start offset: 0
ofs> str stk:type addr:opcode
0> "ab" 0:Alt 0:[mem-start:1]
0> "ab" 0:Alt 3:[push:(+5)]
0> "ab" 1:Alt 8:[jump:(+2)]
0> "ab" 1:Alt 15:[mem-end:1]
0> "ab" 1:Alt 18:[mem-start:1]
0> "ab" 1:Alt 21:[push:(+5)]
0> "ab" 2:Alt 26:[jump:(+2)]
0> "ab" 2:Alt 33:[mem-end:1]
0> "ab" 2:Alt 36:[exact1:b]
0> "ab" 1:Alt 31:[exact1:a]
1> "b" 1:Alt 33:[mem-end:1]
1> "b" 1:Alt 36:[exact1:b]
2> "" 1:Alt 38:[end]
</code></pre> Ruby master - Bug #20314 (Open): Simultaneous Timeout expires may raise an exception after the blockhttps://bugs.ruby-lang.org/issues/203142024-02-29T06:25:26Zmame (Yusuke Endoh)mame@ruby-lang.org
<p>Launchable reports <code>TestTimeout#test_nested_timeout</code> as a flaky test, and I reproduced it as follows.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"timeout"</span>
<span class="k">class</span> <span class="nc">A</span> <span class="o"><</span> <span class="no">Exception</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">B</span> <span class="o"><</span> <span class="no">Exception</span>
<span class="k">end</span>
<span class="k">begin</span>
<span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">A</span><span class="p">)</span> <span class="k">do</span>
<span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">B</span><span class="p">)</span> <span class="k">do</span>
<span class="kp">nil</span> <span class="k">while</span> <span class="kp">true</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">rescue</span> <span class="no">A</span><span class="p">,</span> <span class="no">B</span>
<span class="nb">p</span> <span class="vg">$!</span> <span class="c1">#=> #<A: execution expired></span>
<span class="c1"># Exception B is raised after the above call returns</span>
<span class="c1">#=> test.rb:16:in `p': execution expired (B)</span>
<span class="nb">p</span> <span class="ss">:end</span> <span class="c1"># not reach</span>
<span class="k">end</span>
</code></pre>
<p>This is because the timer thread performs two consecutive <code>Thread#raise</code> to the target thread.</p>
<p>I have discussed this with <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/17">@ko1 (Koichi Sasada)</a> and have come up with three solutions.</p>
<a name="Solution-1"></a>
<h3 >Solution 1<a href="#Solution-1" class="wiki-anchor">¶</a></h3>
<p>When multiple nested Timeouts expire simultaneously, raise an exception for the outer-most Timeout and let the inner Timeouts expire without throwing an exception. In the above example, it would only raise A.</p>
<p>The problem with this approach is that if you are rescuing A in the inner block, it may never ends:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">A</span><span class="p">)</span> <span class="k">do</span>
<span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">B</span><span class="p">)</span> <span class="k">do</span>
<span class="k">begin</span>
<span class="nb">sleep</span>
<span class="k">rescue</span> <span class="no">A</span>
<span class="nb">sleep</span> <span class="c1"># The exception A is caught. The inner Timeout is already expired, so the code (may) never end.</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Note that, if A and B did not occur at the same time, it would raise B. This is a race condition.</p>
<a name="Solution-2"></a>
<h3 >Solution 2<a href="#Solution-2" class="wiki-anchor">¶</a></h3>
<p>When multiple nested Timeouts expire simultaneously, raise an exception for the inner-most Timeout and let the outer Timeouts wait until the inner-most Timeout returns. In the above example, it would raise either A or B, not both.</p>
<p>The problem with this approach is that if you are rescuing B in the inner block, it never ends:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">A</span><span class="p">)</span> <span class="k">do</span>
<span class="no">Timeout</span><span class="p">.</span><span class="nf">timeout</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span> <span class="no">B</span><span class="p">)</span> <span class="k">do</span>
<span class="k">begin</span>
<span class="nb">sleep</span>
<span class="k">rescue</span> <span class="no">B</span>
<span class="nb">sleep</span> <span class="c1"># The outer Timeout waits for the inner timeout, and the inner Timeout never return. So this code never ends.</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<a name="Solution-3"></a>
<h3 >Solution 3<a href="#Solution-3" class="wiki-anchor">¶</a></h3>
<p>Make thread interrupt queue one length. If the target thread has already been <code>Thread#raise(A)</code>, the new <code>Thread#raise(B)</code> blocks until the target thread processes A.</p>
<p>Since there will be no more simultaneous Thread#raise, there will be no more exceptions after the end of the block. The timeout timer thread should be changed in consideration that <code>Thread#raise</code> may block.</p> Ruby master - Feature #20309 (Assigned): Bundled gems for Ruby 3.5https://bugs.ruby-lang.org/issues/203092024-02-27T22:16:20Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I propose migrate the following default gems to bundled gems at Ruby 3.5. So, It means users will get warnings if users try to load them.</p>
<p>(Update with 2024/03/14)</p>
<ul>
<li>ostruct
<ul>
<li>I make ostruct as optional on json at <a href="https://github.com/flori/json/pull/565" class="external">https://github.com/flori/json/pull/565</a>
</li>
</ul>
</li>
<li>logger
<ul>
<li>activesupport needs to add logger to its dependency same as bigdecimal, drb or etc.</li>
</ul>
</li>
<li>fiddle</li>
<li>pstore</li>
<li>win32ole</li>
</ul>
<p>I have a plan to migrate the following default gems too. But I need to more feedback from other committers about them.</p>
<ul>
<li>irb
<ul>
<li>We need to consider how works <code>binding.irb</code> after Ruby 3.5.</li>
<li>I consider to use <code>irb</code> without Gemfile.</li>
</ul>
</li>
<li>reline</li>
<li>readline (wrapper file for readline-ext and reline)</li>
<li>io-console
<ul>
<li>rubygems uses that. Should we make optional that?</li>
</ul>
</li>
<li>open-uri</li>
<li>yaml (wrapper file for psych)
<ul>
<li>syck is retired today. I'm not sure what people uses <code>psych</code> directly, not <code>yaml</code>.</li>
</ul>
</li>
<li>rdoc
<ul>
<li>We need to change build task like download rdoc gem before document generation.
<ul>
<li>extract <code>make doc</code> from <code>make all</code> and invoke <code>make doc</code> before <code>make install</code>.</li>
</ul>
</li>
<li>or We make document generation is optional from Ruby 3.5
<ul>
<li>We explicitly separate <code>make install</code> and <code>make install-doc</code>
</li>
</ul>
</li>
</ul>
</li>
<li>un
<ul>
<li>
<code>ruby -run</code> is one of cool feature of Ruby. Should we avoid uninstalling <code>un</code> gem?</li>
<li>mkmf uses <code>ruby -run</code> for that. I need to investigate that.</li>
</ul>
</li>
<li>singleton
<ul>
<li>This is famous design pattern. Should we enforce users add them to their Gemfile?</li>
</ul>
</li>
<li>forwadable
<ul>
<li>
<code>reline</code> needs to add forwardable their <code>runtime_dependency</code> after migration.</li>
</ul>
</li>
<li>weakref
<ul>
<li>I'm not sure how impact after migrating bundled gems.</li>
</ul>
</li>
<li>fcntl
<ul>
<li>Should we integrate these constants into ruby core?</li>
</ul>
</li>
</ul>
<p>I would like to migrate <code>ipaddr</code> and <code>uri</code> too. But these are used by webrick that is mock server for our test suite. We need to rewrite <code>webrick</code> with <code>TCPSocker</code> or extract <code>ipaddr</code> and <code>uri</code> dependency from <code>webrick</code></p>
<p>Other default gems depend on our build process or other libraries deeply. I will update this proposal if I could extract them from default gems.</p> Ruby master - Bug #20301 (Open): `Set#add?` does two hash look-upshttps://bugs.ruby-lang.org/issues/203012024-02-26T02:42:35ZAMomchilov (Alexander Momchilov)
<p>A common usage of <code>Set</code>s is to keep track of seen objects, and do something different whenever an object is seen for the first time, e.g.:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">SEEN_VALUES</span> <span class="o">=</span> <span class="no">Set</span><span class="p">.</span><span class="nf">new</span>
<span class="k">def</span> <span class="nf">receive_value</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">if</span> <span class="no">SEEN_VALUES</span><span class="p">.</span><span class="nf">add?</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Saw </span><span class="si">#{</span><span class="n">value</span><span class="si">}</span><span class="s2"> for the first time."</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"Already seen </span><span class="si">#{</span><span class="n">value</span><span class="si">}</span><span class="s2">, ignoring."</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">receive_value</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Saw 1 for the first time.</span>
<span class="n">receive_value</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="c1"># Saw 2 for the first time.</span>
<span class="n">receive_value</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># Saw 3 for the first time.</span>
<span class="n">receive_value</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Already seen 1, ignoring.</span>
</code></pre>
<p>Readers might reasonably assume that <code>add?</code> is only looking up into the set a single time, but it's actually doing two separate look-ups! (<a href="https://github.com/ruby/ruby/blob/c976cb5/lib/set.rb#L517-L525" class="external">source</a>)</p>
<pre><code class="rb syntaxhl" data-language="rb"><span class="k">class</span> <span class="nc">Set</span>
<span class="k">def</span> <span class="nf">add?</span><span class="p">(</span><span class="n">o</span>
<span class="c1"># 1. `include?(o)` looks up into `@hash`</span>
<span class="c1"># 2. if the value isn't there, `add(o)` does a second look-up into `@hash`</span>
<span class="n">add</span><span class="p">(</span><span class="n">o</span><span class="p">)</span> <span class="k">unless</span> <span class="kp">include</span><span class="p">?(</span><span class="n">o</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>This gets especially expensive if the values are large hash/arrays/objects, whose <code>#hash</code> is expensive to compute.</p>
<p>We can optimize this if it was possible to set a value in hash, <em>and</em> retrieve the value that was already there, in a single go. I propose adding <code>Hash#exchange_value</code> to do exactly that. If that existed, we can re-implement <code>#add?</code> as:</p>
<pre><code class="rb syntaxhl" data-language="rb"><span class="k">class</span> <span class="nc">Set</span>
<span class="k">def</span> <span class="nf">add?</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
<span class="c1"># Only requires a single look-up into `@hash`!</span>
<span class="nb">self</span> <span class="k">unless</span> <span class="vi">@hash</span><span class="p">.</span><span class="nf">exchange_value</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<p>Here's a proof-of-concept implementation: <a href="https://github.com/ruby/ruby/pull/10093" class="external">https://github.com/ruby/ruby/pull/10093</a></p>
<a name="Theory"></a>
<h1 >Theory<a href="#Theory" class="wiki-anchor">¶</a></h1>
<p>How much of a benefit this has depends on 2 factors:</p>
<ol>
<li>How much <code>#hash</code> is called, which depends on how many <strong>new</strong> objects are added to the set.
<ul>
<li>If every object is new, then <code>#hash</code> used to be called twice on every <code>#add?</code>.
<ul>
<li>This is where this improvement makes the biggest (2x!) change.</li>
</ul>
</li>
<li>If every object has already been seen, then <code>#hash</code> was never being called twice before anyway, so there would be no improvement.
<ul>
<li>It's important to not regress in this case, because many use cases of sets don't deal with many distinct objects, but just need to do quick checks against an existing set.</li>
</ul>
</li>
<li>Every other case lies somewhere in between those two, depending on the % of objects which are new.</li>
</ul>
</li>
<li>How slow <code>#hash</code> is to compute for the key
<ul>
<li>If the hash is slow to compute, this change will make a bigger improvement</li>
<li>If the hash value is fast to compute, then it won't matter as much. Even if we called it half as much, it's a minority of the total time, so it won't have much net impact.</li>
</ul>
</li>
</ol>
<a name="Benchmark-summary"></a>
<h1 >Benchmark summary<a href="#Benchmark-summary" class="wiki-anchor">¶</a></h1>
<table>
<thead>
<tr>
<th></th>
<th align="right">All objects are new</th>
<th align="right">All objects are preexisting</th>
</tr>
</thead>
<tbody>
<tr>
<td>objects with slow <code>#hash</code>
</td>
<td align="right">100.0%</td>
<td align="right">~0.0%</td>
</tr>
<tr>
<td>objects with fast <code>#hash</code>
</td>
<td align="right">24.5%</td>
<td align="right">4.6%</td>
</tr>
</tbody>
</table>
<p>As we see, this change makes a huge improvement the cases where it helps, and crucially, doesn't slow down the cases where it can't.</p>
<p>For the complete benchmark source code and results, see the PR: <a href="https://github.com/ruby/ruby/pull/10093" class="external">https://github.com/ruby/ruby/pull/10093</a></p> Ruby master - Feature #20300 (Open): Hash: set value and get pre-existing value in one callhttps://bugs.ruby-lang.org/issues/203002024-02-26T02:42:29ZAMomchilov (Alexander Momchilov)
<p>When using a Hash, sometimes you want to set a new value, <strong>and</strong> see what was already there. Today, you <strong>have</strong> to do this in two steps:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">k: </span><span class="s2">"old value"</span> <span class="p">}</span>
<span class="c1"># 1. Do a look-up for `:k`.</span>
<span class="n">old_value</span> <span class="o">=</span> <span class="n">h</span><span class="p">[</span><span class="ss">:k</span><span class="p">]</span>
<span class="c1"># 2. Do another look-up for `:k`, even though we just did that!</span>
<span class="n">h</span><span class="p">[</span><span class="ss">:k</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"new value"</span>
<span class="n">use</span><span class="p">(</span><span class="n">old_value</span><span class="p">)</span>
</code></pre>
<p>This requires two separate <code>Hash</code> look-ups for <code>:k</code>. This is fine for symbols, but is expensive if computing <code>#hash</code> or <code>#eql?</code> is expensive for the key. It's impossible to work around this today from pure Ruby code.</p>
<p>One example use case is <code>Set#add?</code>. See <a href="https://bugs.ruby-lang.org/issues/20301" class="external">https://bugs.ruby-lang.org/issues/20301</a> for more details.</p>
<p>I propose adding <code>Hash#exchange_value</code>, which has semantics are similar to this Ruby snippet:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Hash</span>
<span class="c1"># Exact method name TBD.</span>
<span class="k">def</span> <span class="nf">exchange_value</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">new_value</span><span class="p">)</span>
<span class="n">old_value</span> <span class="o">=</span> <span class="nb">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
<span class="nb">self</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_value</span>
<span class="n">old_value</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>... except it'll be implemented in C, with modifications to <code>tbl_update</code> that achieves this with a hash-lookup.</p>
<p>I'm opening to alternative name suggestions. <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/4">@nobu (Nobuyoshi Nakada)</a> came up with <code>exchange_value</code>, which I think is great.</p>
<p>Here's a PR with a PoC implementation: <a href="https://github.com/ruby/ruby/pull/10092" class="external">https://github.com/ruby/ruby/pull/10092</a></p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">h</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">k: </span><span class="s2">"old value"</span> <span class="p">}</span>
<span class="c1"># Does only a single hash look-up</span>
<span class="n">old_value</span> <span class="o">=</span> <span class="n">h</span><span class="p">.</span><span class="nf">exchange_value</span><span class="p">(</span><span class="ss">:k</span><span class="p">,</span> <span class="s2">"new value"</span><span class="p">)</span>
<span class="n">use</span><span class="p">(</span><span class="n">old_value</span><span class="p">)</span>
</code></pre> Ruby master - Bug #20299 (Open): Tracepoint staying enable after a disablehttps://bugs.ruby-lang.org/issues/202992024-02-26T01:06:28ZMaxLap (Maxime Lapointe)hunter_spawn@hotmail.com
<p>Problem is present in Ruby 3.2.2, 3.2.3, 3.3.0. Didn't check before.</p>
<p>It seems that TracePoint can sometime be "stuck" enabled after using disabled once on it.</p>
<p>Here is a reproduction step using a "check speed" method that just does some work and print out how long it takes. This makes it pretty clear when TracePoint was on.</p>
<p>Put this in a Ruby file:</p>
<pre><code>def check_speed(msg)
t1 = Time.now.to_f
a = 0
1000000.times { |i|
a += 10
}
t2 = Time.now.to_f
puts "#{t2-t1} - #{msg}"
end
check_speed("before") # fast
trace = TracePoint.new(:line) {}
trace.enable
check_speed("after enable") # slow
trace.enable {
check_speed("in block enable") # slow
}
check_speed("after block enable") # slow
trace.disable
check_speed("after disable") # slow !!!!
trace.disable
check_speed("after disable again") # fast !!!!
# And yet, using enable multiple time doesn't have a "counter" or similar
trace.enable
trace.enable
trace.enable
check_speed("after triple enable") # slow
trace.disable
check_speed("after single disable") # fast
</code></pre>
<p>Running the file, we get this:</p>
<pre><code>$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
$ ruby local.rb
0.03473854064941406 - before
0.18935227394104004 - after enable
0.17757630348205566 - in block enable
0.18320131301879883 - after block enable
0.1818866729736328 - after disable
0.03412747383117676 - after disable again
0.18405628204345703 - after triple enable
0.033496856689453125 - after single disable
</code></pre>
<p>The first "after disable" should probably have been fast. If it's possible to have multiple nested enable/disable, then one would instead assume that after the last "single disable", things would still be slow.</p>
<p>Note: This code patterns comes directly for a ruby/spec: ctrl+f for "enables trace object on calling with a block if it was already enabled"</p>
<p>I note that in Ruby 3.2, the timing are a lot less similar. I don't know why. It would seem like TracePoint got slower in Ruby 3.3.0. Is that worth checking out / making a distincct bug for?</p>
<pre><code>$ rvm use 3.2.3
Using /home/max/.rvm/gems/ruby-3.2.3
$ ruby local.rb
0.03246927261352539 - before
0.07910513877868652 - after enable
0.10309600830078125 - in block enable
0.12397646903991699 - after block enable
0.07114601135253906 - after disable
0.028218746185302734 - after disable again
0.12534689903259277 - after triple enable
0.02810525894165039 - after single disable
</code></pre> Ruby master - Feature #20298 (Open): Introduce `Time()` type-cast / constructor.https://bugs.ruby-lang.org/issues/202982024-02-26T00:34:27Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>Many Ruby primitive types have constructors, e.g. <code>Integer(...)</code>, <code>String(...)</code>, <code>Float(...)</code>, etc. These usually convert from some subset of types, e.g. <code>Float(1) -> 1.0</code> will convert an Integer to a Float, and <code>Float("1") -> 1.0</code> will parse a String to a Float, and similar for other type casts/constructors.</p>
<p>I'd like to propose we introduce something similar for <code>Time</code> (and possibly this extends to <code>Date</code>/<code>DateTime</code> in a follow up proposal).</p>
<p>Suggested implementation could look something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">Time</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">case</span> <span class="n">value</span>
<span class="k">when</span> <span class="no">Time</span>
<span class="n">value</span>
<span class="k">when</span> <span class="no">Integer</span>
<span class="no">Time</span><span class="p">.</span><span class="nf">at</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">when</span> <span class="no">String</span> <span class="c1"># The format is assumed to be the result of `Time#to_s`.</span>
<span class="no">Time</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">value</span><span class="p">.</span><span class="nf">to_time</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>Alternatively, we might like to be a little more specific with the <code>else</code> clause/error handling.</p>
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>In a project, I need to support multiple serialization formats/coders, including MessagePack, Marshal and JSON.</p>
<p>While Marshal and MessagePack are capable of serializing <code>Time</code> instances, <code>JSON</code> is not.</p>
<p>The code looks a bit like this:</p>
<pre><code>data = fetch_job_data
job = @coder.load(data)
scheduled_at = Time(job[:scheduled_at]) # Hypothetical type-cast as outlined above
</code></pre>
<a name="Additional-Observations"></a>
<h2 >Additional Observations<a href="#Additional-Observations" class="wiki-anchor">¶</a></h2>
<p>While some primitive data types accept themselves as arguments and construct by copy, e.g. <code>Array.new(Array.new)</code>, others do not, e.g. <code>Hash</code> and <code>Time</code>. Perhaps <code>Time.new(Time.new)</code> should behave similarly to <code>Array.new(Array.new)</code> - the outer instance is a copy of the inner.</p> Ruby master - Bug #20294 (Open): Parser no longer warns on some duplicated keyshttps://bugs.ruby-lang.org/issues/202942024-02-22T14:09:39Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>Previously, the parser would warn on all duplicated keys. Now some cases are not handled:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="p">{</span> <span class="mf">100.0</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="mf">1e2</span> <span class="o">=></span> <span class="mi">1</span> <span class="p">}</span>
<span class="p">{</span> <span class="mf">100.0</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="mf">1E2</span> <span class="o">=></span> <span class="mi">1</span> <span class="p">}</span>
<span class="p">{</span> <span class="mf">100.0</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="mf">100.00</span> <span class="o">=></span> <span class="mi">1</span> <span class="p">}</span>
<span class="p">{</span> <span class="mf">100.0</span><span class="n">r</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="mf">100.00</span><span class="n">r</span> <span class="o">=></span> <span class="mi">1</span> <span class="p">}</span>
<span class="p">{</span> <span class="mf">100.0</span><span class="n">i</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="mf">100.00</span><span class="n">i</span> <span class="o">=></span> <span class="mi">1</span> <span class="p">}</span>
</code></pre> Ruby master - Feature #20291 (Open): Add --warning=category option the same as -W:categoryhttps://bugs.ruby-lang.org/issues/202912024-02-22T11:56:09Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>I propose a <code>--warning</code> option that corresponds to the <code>-W</code> option, like the <code>--encoding</code> option to the <code>-E</code> option.<br>
The argument after <code>--warning=</code> is same as <code>-W:</code>.</p>
<p><a href="https://github.com/ruby/ruby/pull/4113" class="external">https://github.com/ruby/ruby/pull/4113</a></p> Ruby master - Misc #20287 (Open): DevMeeting before or after RubyKaigihttps://bugs.ruby-lang.org/issues/202872024-02-21T08:29:56Zduerst (Martin Dürst)duerst@it.aoyama.ac.jp
<p>RubyKaigi itself runs from May 15-17 (Wed-Fri) in Naha.</p>
<p>It would be nice to have a DevMeeting before or afterwards. We should try to plan ahead, so that people can make the right flight and hotel reservations early.</p>
<p>I have never been to Okinawa before and don't know any facilities that would be available.</p> Ruby master - Bug #20285 (Assigned): Stale inline method caches when refinement modules are reopenedhttps://bugs.ruby-lang.org/issues/202852024-02-21T02:44:55Zjhawthorn (John Hawthorn)
<p>This is essentially the same issue as <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: refinement (Closed)" href="https://bugs.ruby-lang.org/issues/11672">#11672</a>, but for inline method caches rather than class caches.</p>
<p>In Ruby 3.3 we started using inline caches for refinements. However, we weren't clearing inline caches when defined on a reopened refinement module.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">C</span>
<span class="k">end</span>
<span class="k">module</span> <span class="nn">R</span>
<span class="n">refine</span> <span class="no">C</span> <span class="k">do</span>
<span class="k">def</span> <span class="nf">m</span>
<span class="ss">:foo</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">using</span> <span class="no">R</span>
<span class="k">def</span> <span class="nf">m</span>
<span class="no">C</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">m</span>
<span class="k">end</span>
<span class="k">raise</span> <span class="k">unless</span> <span class="ss">:foo</span> <span class="o">==</span> <span class="n">m</span><span class="p">()</span>
<span class="k">module</span> <span class="nn">R</span>
<span class="n">refine</span> <span class="no">C</span> <span class="k">do</span>
<span class="k">alias</span> <span class="n">m</span> <span class="n">m</span>
<span class="k">def</span> <span class="nf">m</span>
<span class="ss">:bar</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">m</span><span class="p">()</span>
<span class="k">raise</span> <span class="s2">"expected :bar, got </span><span class="si">#{</span><span class="n">v</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span> <span class="k">unless</span> <span class="ss">:bar</span> <span class="o">==</span> <span class="n">v</span>
</code></pre>
<p>This will raise in Ruby 3.3 as the inline cache finds a stale refinement, but passes in previous versions.</p> Ruby master - Bug #20283 (Open): Build failed since Ruby 3.2.3 if Xcode.app was renamed to space ...https://bugs.ruby-lang.org/issues/202832024-02-20T06:41:28Zwatson1978 (Shizuo Fujita)watson1978@gmail.com
<p>When I renamed Xcode.app to space contained name (like <code>Xcode 15.2.0.app</code>), then I met build error with Ruby 3.2.3 and Ruby 3.3.0.<br>
(Ruby 3.2.2 can be built with successfully.)</p>
<a name="How-to-reproduce"></a>
<h2 >How to reproduce<a href="#How-to-reproduce" class="wiki-anchor">¶</a></h2>
<pre><code>$ sudo mv /Applications/Xcode.app '/Applications/Xcode 15.2.app'
$ sudo xcode-select --switch '/Applications/Xcode 15.2.app'
$ tar xzf ruby-3.2.3.tar.xz
$ cd ruby-3.2.3
$ ./configure
$ make V=1
:
clang -fdeclspec -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wextra-tokens -Wdeprecated-declarations -Wdivision-by-zero -Wdiv-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wshorten-64-to-32 -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-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wundef -pipe -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fno-strict-overflow -fvisibility=hidden -DRUBY_EXPORT -fPIE -I. -I.ext/include/arm64-darwin23 -I./include -I. -I./enc/unicode/15.0.0 -I/opt/homebrew/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -o dmyenc.o -c dmyenc.c
rustc --crate-name=yjit --crate-type=staticlib --edition=2021 -g -C opt-level=3 -C overflow-checks=on '--out-dir=/Users/watson/prj/ruby-3.2.3/yjit/target/release/' ./yjit/src/lib.rs
touch yjit/target/release/libyjit.a
clang -fdeclspec -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wextra-tokens -Wdeprecated-declarations -Wdivision-by-zero -Wdiv-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wshorten-64-to-32 -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-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wundef -pipe -L. -L/opt/homebrew/lib -fstack-protector-strong -fstack-protector-strong -Wl,-pie -framework CoreFoundation main.o dmydln.o miniinit.o dmyext.o array.o ast.o bignum.o class.o compar.o compile.o complex.o cont.o debug.o debug_counter.o dir.o dln_find.o encoding.o enum.o enumerator.o error.o eval.o file.o gc.o hash.o inits.o io.o io_buffer.o iseq.o load.o marshal.o math.o memory_view.o mjit.o mjit_c.o node.o numeric.o object.o pack.o parse.o proc.o process.o ractor.o random.o range.o rational.o re.o regcomp.o regenc.o regerror.o regexec.o regparse.o regsyntax.o ruby.o scheduler.o shape.o signal.o sprintf.o st.o strftime.o string.o struct.o symbol.o thread.o time.o transcode.o transient_heap.o util.o variable.o version.o vm.o vm_backtrace.o vm_dump.o vm_sync.o vm_trace.o yjit.o coroutine/arm64/Context.o enc/ascii.o enc/us_ascii.o enc/unicode.o enc/utf_8.o enc/trans/newline.o explicit_bzero.o setproctitle.o addr2line.o yjit/target/release/libyjit.a -lgmp -ldl -lobjc -lpthread -lpthread -o miniruby
ld: warning: ignoring duplicate libraries: '-lpthread'
ld: Undefined symbols:
_coroutine_transfer, referenced from:
_fiber_setcontext in cont.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
</code></pre>
<a name="Environment"></a>
<h2 >Environment<a href="#Environment" class="wiki-anchor">¶</a></h2>
<ul>
<li>Apple M1 Max</li>
<li>macOS 14.3.1</li>
<li>clang 15.0.0 (clang-1500.1.0.2.5)</li>
<li>rustc 1.75.0</li>
</ul>
<a name="Note"></a>
<h2 >Note<a href="#Note" class="wiki-anchor">¶</a></h2>
<p>This problem occurs on Intel Mac and Apple M1 Mac both.</p> Ruby master - Feature #20282 (Open): Enhancing Ruby's Coverage with Per-Test Coverage Reportshttps://bugs.ruby-lang.org/issues/202822024-02-19T22:51:10Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>As Ruby applications grow in complexity, the need for more sophisticated testing and coverage analysis tools becomes paramount. Current coverage tools in Ruby offer a good starting point but fall short in delivering the granularity and flexibility required by modern development practices. Specifically, there is a significant gap in "per-test coverage" reporting, which limits developers' ability to pinpoint exactly which tests exercise which lines of code. This proposal seeks to initiate a discussion around improving Ruby's coverage module to address this gap.</p>
<a name="Objectives"></a>
<h2 >Objectives<a href="#Objectives" class="wiki-anchor">¶</a></h2>
<p>The primary goal of this initiative is to introduce support for per-test coverage reports within Ruby, focusing on three key areas:</p>
<ol>
<li>
<p>Scoped Coverage Data Capture: Implementing the capability to capture coverage data within user-defined scopes, such as global, thread, or fiber scopes. This would allow for more granular control over the coverage analysis process.</p>
</li>
<li>
<p>Efficient Data Capture Controls: Developing mechanisms to efficiently control the capture of coverage data. This includes the ability to exclude specific files, include/ignore/merge eval'd code, to ensure that the coverage data is both relevant and manageable.</p>
</li>
<li>
<p>Compatibility and Consistency: Ensuring that the coverage data is exposed in a manner that is consistent with existing coverage tools and standards. This compatibility is crucial for integrating with a wide array of tooling and for facilitating a seamless developer experience.</p>
</li>
</ol>
<a name="Proposed-Solutions"></a>
<h2 >Proposed Solutions<a href="#Proposed-Solutions" class="wiki-anchor">¶</a></h2>
<p>The heart of this proposal lies in the introduction of a new subclassable component within the Coverage module, tentatively named <code>Coverage::Capture</code>. This component would allow users to define custom coverage capture behaviors tailored to their specific needs. Below is a hypothetical interface for such a mechanism:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">Coverage::Capture</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">start</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">new</span><span class="p">.</span><span class="nf">tap</span><span class="p">(</span><span class="o">&</span><span class="ss">:start</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Start receiving coverage callbacks.</span>
<span class="k">def</span> <span class="nf">start</span>
<span class="k">end</span>
<span class="c1"># Stop receiving coverage callbacks.</span>
<span class="k">def</span> <span class="nf">stop</span>
<span class="k">end</span>
<span class="c1"># User-overridable statement coverage callback.</span>
<span class="k">def</span> <span class="nf">statement</span><span class="p">(</span><span class="n">iseq</span><span class="p">,</span> <span class="n">location</span><span class="p">)</span>
<span class="n">fetch</span><span class="p">(</span><span class="n">iseq</span><span class="p">)</span><span class="o">&</span><span class="p">.</span><span class="nf">statement_coverage</span><span class="p">.</span><span class="nf">increment</span><span class="p">(</span><span class="n">location</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Additional methods for branch/declaration coverage would follow a similar pattern.</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">MyCoverageCapture</span> <span class="o"><</span> <span class="no">Coverage</span><span class="o">::</span><span class="no">Capture</span>
<span class="c1"># Provides efficient data capture controls - can return nil if skipping coverage for this iseq, or can store coverage data per-thread, per-fiber, etc.</span>
<span class="k">def</span> <span class="nf">fetch</span><span class="p">(</span><span class="n">iseq</span><span class="p">)</span>
<span class="vi">@coverage</span><span class="p">[</span><span class="n">iseq</span><span class="p">]</span> <span class="o">||=</span> <span class="no">Coverage</span><span class="p">.</span><span class="nf">default_coverage</span><span class="p">(</span><span class="n">iseq</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Usage example:</span>
<span class="n">my_coverage_capture</span> <span class="o">=</span> <span class="no">MyCoverageCapture</span><span class="p">.</span><span class="nf">start</span>
<span class="c1"># Execute test suite or specific tests</span>
<span class="n">my_coverage_capture</span><span class="p">.</span><span class="nf">stop</span>
<span class="c1"># Access detailed coverage data</span>
<span class="nb">puts</span> <span class="n">my_coverage_capture</span><span class="p">.</span><span class="nf">coverage</span><span class="p">.</span><span class="nf">statement_coverage</span>
</code></pre>
<p>In addition, we'd need a well defined interface for <code>Coverage.default_coverage</code>, which includes line, branch and declaration coverage statistics. I suggest we take inspiration from the proposed interface defined by the vscode text editor: <a href="https://github.com/microsoft/vscode/blob/b44593a612337289c079425a5b2cc7010216eef4/src/vscode-dts/vscode.proposed.testCoverage.d.ts" class="external">https://github.com/microsoft/vscode/blob/b44593a612337289c079425a5b2cc7010216eef4/src/vscode-dts/vscode.proposed.testCoverage.d.ts</a> - this interface was designed to be compatible with a wide range of coverage libraries, so represents the intersection of that functionality.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Hypothetical interface (mostly copied from vscode's proposed interface):</span>
<span class="k">module</span> <span class="nn">Coverage</span>
<span class="c1"># Contains coverage metadata for a file</span>
<span class="k">class</span> <span class="nc">Target</span>
<span class="nb">attr_reader</span> <span class="ss">:instruction_sequence</span>
<span class="nb">attr_accessor</span> <span class="ss">:statement_coverage</span><span class="p">,</span> <span class="ss">:branch_coverage</span><span class="p">,</span> <span class="ss">:declaration_coverage</span><span class="p">,</span> <span class="ss">:detailed_coverage</span>
<span class="c1"># @param statement_coverage [Hash(Location, StatementCoverage)] A hash table of statement coverage instances keyed on location.</span>
<span class="c1"># Similar structures for other coverage data.</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">instruction_sequence</span><span class="p">,</span> <span class="n">statement_coverage</span><span class="p">,</span> <span class="n">branch_coverage</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span> <span class="n">declaration_coverage</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
<span class="vi">@instruction_sequence</span> <span class="o">=</span> <span class="n">instruction_sequence</span>
<span class="vi">@statement_coverage</span> <span class="o">=</span> <span class="n">statement_coverage</span>
<span class="vi">@branch_coverage</span> <span class="o">=</span> <span class="n">branch_coverage</span>
<span class="vi">@declaration_coverage</span> <span class="o">=</span> <span class="n">declaration_coverage</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Coverage information for a single statement or line.</span>
<span class="k">class</span> <span class="nc">StatementCoverage</span>
<span class="c1"># The number of times this statement was executed, or a boolean indicating</span>
<span class="c1"># whether it was executed if the exact count is unknown. If zero or false,</span>
<span class="c1"># the statement will be marked as un-covered.</span>
<span class="nb">attr_accessor</span> <span class="ss">:executed</span>
<span class="c1"># Statement location (line number? or range? or position? AST?)</span>
<span class="nb">attr_accessor</span> <span class="ss">:location</span>
<span class="c1"># Coverage from branches of this line or statement. If it's not a</span>
<span class="c1"># conditional, this will be empty.</span>
<span class="nb">attr_accessor</span> <span class="ss">:branches</span>
<span class="c1"># Initializes a new instance of the StatementCoverage class.</span>
<span class="c1">#</span>
<span class="c1"># @parameter executed [Number, Boolean] The number of times this statement was executed, or a</span>
<span class="c1"># boolean indicating whether it was executed if the exact count is unknown. If zero or false,</span>
<span class="c1"># the statement will be marked as un-covered.</span>
<span class="c1">#</span>
<span class="c1"># @parameter location [Position, Range] The statement position.</span>
<span class="c1">#</span>
<span class="c1"># @parameter branches [Array(BranchCoverage)] Coverage from branches of this line.</span>
<span class="c1"># If it's not a conditional, this should be omitted.</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">executed</span><span class="p">,</span> <span class="n">location</span><span class="p">,</span> <span class="n">branches</span><span class="o">=</span><span class="p">[])</span>
<span class="vi">@executed</span> <span class="o">=</span> <span class="n">executed</span>
<span class="vi">@location</span> <span class="o">=</span> <span class="n">location</span>
<span class="vi">@branches</span> <span class="o">=</span> <span class="n">branches</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Coverage information for a branch</span>
<span class="k">class</span> <span class="nc">BranchCoverage</span>
<span class="c1"># The number of times this branch was executed, or a boolean indicating</span>
<span class="c1"># whether it was executed if the exact count is unknown. If zero or false,</span>
<span class="c1"># the branch will be marked as un-covered.</span>
<span class="nb">attr_accessor</span> <span class="ss">:executed</span>
<span class="c1"># Branch location.</span>
<span class="nb">attr_accessor</span> <span class="ss">:location</span>
<span class="c1"># Label for the branch, used in the context of "the ${label} branch was</span>
<span class="c1"># not taken," for example.</span>
<span class="nb">attr_accessor</span> <span class="ss">:label</span>
<span class="c1"># Initializes a new instance of the BranchCoverage class.</span>
<span class="c1">#</span>
<span class="c1"># @param executed [Number, Boolean] The number of times this branch was executed, or a</span>
<span class="c1"># boolean indicating whether it was executed if the exact count is unknown. If zero or false,</span>
<span class="c1"># the branch will be marked as un-covered.</span>
<span class="c1">#</span>
<span class="c1"># @param location [Position, Range] (optional) The branch position.</span>
<span class="c1">#</span>
<span class="c1"># @param label [String] (optional) Label for the branch, used in the context of</span>
<span class="c1"># "the ${label} branch was not taken," for example.</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">executed</span><span class="p">,</span> <span class="n">location</span><span class="o">=</span><span class="kp">nil</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
<span class="vi">@executed</span> <span class="o">=</span> <span class="n">executed</span>
<span class="vi">@location</span> <span class="o">=</span> <span class="n">location</span>
<span class="vi">@label</span> <span class="o">=</span> <span class="n">label</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1"># Coverage information for a declaration</span>
<span class="k">class</span> <span class="nc">DeclarationCoverage</span>
<span class="c1"># Name of the declaration. Depending on the reporter and language, this</span>
<span class="c1"># may be types such as functions, methods, or namespaces.</span>
<span class="nb">attr_accessor</span> <span class="ss">:name</span>
<span class="c1"># The number of times this declaration was executed, or a boolean</span>
<span class="c1"># indicating whether it was executed if the exact count is unknown. If</span>
<span class="c1"># zero or false, the declaration will be marked as un-covered.</span>
<span class="nb">attr_accessor</span> <span class="ss">:executed</span>
<span class="c1"># Declaration location.</span>
<span class="nb">attr_accessor</span> <span class="ss">:location</span>
<span class="c1"># Initializes a new instance of the DeclarationCoverage class.</span>
<span class="c1">#</span>
<span class="c1"># @param name [String] Name of the declaration.</span>
<span class="c1">#</span>
<span class="c1"># @param executed [Number, Boolean] The number of times this declaration was executed, or a</span>
<span class="c1"># boolean indicating whether it was executed if the exact count is unknown. If zero or false,</span>
<span class="c1"># the declaration will be marked as un-covered.</span>
<span class="c1">#</span>
<span class="c1"># @param location [Position, Range] The declaration position.</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="n">executed</span><span class="p">,</span> <span class="n">location</span><span class="p">)</span>
<span class="vi">@name</span> <span class="o">=</span> <span class="nb">name</span>
<span class="vi">@executed</span> <span class="o">=</span> <span class="n">executed</span>
<span class="vi">@location</span> <span class="o">=</span> <span class="n">location</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>By following this format, we will be compatible with a wide range of external tools.</p> Ruby master - Feature #20278 (Open): syntax error, unexpected local variable or method, expecting...https://bugs.ruby-lang.org/issues/202782024-02-18T22:32:05ZrubyFeedback (robert heiler)
<p>So this is not quite a bug, but I thought it may fit better here, as it is neither a feature, and also not quite fitting under misc.</p>
<p>Before I will explain the issue, let me copy/paste the code I use so that others can reproduce what I mean:</p>
<pre><code>class Foobar
def foo1
var1 = 1
var2 = 2
Foobar.some_method(
var1
var2
)
end
def self.some_method(a, b)
puts a
end
end
Foobar.new
</code></pre>
<p>If it helps, the faulty lines are those between line 7 and 8, where I passed two variables var1 and var2, but I forgot a ',' between these two.</p>
<p>I actually had this happen just now in another (real) code, and the error message confused me.</p>
<p>Anyway, there are two things I want to report here. First, the smaller issue - the description show on the commandline is strange:</p>
<pre><code>expected a `)` to close the argumentsexpected a newline or semicolon after the statementcannot parse the expression
</code></pre>
<p>Normally it should read "to close the arguments expected". It seems the ' ' space character between "arguments expected" is swallowed; same with the "statementcannot". But that is just description - I report it in the event someone else also finds it strange. I actually did not see it at first as I always look at the bottom first, so I tend to miss what appears on top. Anyway.</p>
<p>The second one, and reason why I wrote this issue here, is that the error shown is a bit confusing:</p>
<pre><code>ack.rb:8: syntax error, unexpected local variable or method, expecting ')' (SyntaxError)
var2
</code></pre>
<p>So ruby indicates that there is an issue with var2 and a ')' was expecting. But I think ruby should instead have<br>
expected a ','. I don't know whether ruby can distinguish between this; both var1 and var2 were already defined prior, so I think in theory the ruby parser could find out that there are two separate variables, and assume that a ',' could also be missing. I don't know if this is always the case, but at the least I think in the example code I showed, ruby saying that a ')' was expected, was wrong, in my opinion.</p>
<p>Again, perhaps ruby has no way to distinguish, but as ruby gives a specific suggestion that there is a missing ')', when in reality I was missing the ',', is in my opinion incorrect. Perhaps it is not worth to fix it, but being able to distinguish at the least between two local variables (as in var1 and var2) should be possible, and perhaps the overall message shown could be improved a bit. For instance, the line " the argumentsexpected" could perhaps not only NOT swallow the ' ' but also be displayed on two lines. I am not sure if this makes it better or worse, since people's preferences are different. Either way I wanted to bring this to attention here.</p> Ruby master - Misc #20272 (Open): Ambiguity around Ractor message sending FIFO semanticshttps://bugs.ruby-lang.org/issues/202722024-02-16T18:26:09Zforthoney (Seong-Heon Jung)castlehoneyjung@gmail.com
<p>The docs should explicitly state the semantics/properties of Ractor message, especially when it comes to FIFO.<br>
For example, assume I have two Ractors, Ractor A and Ractor B. Ractor A sends two messages <code>"hello"</code> and <code>"world"</code> in this order to Ractor B.<br>
If I call <code>Ractor.receive</code> on Ractor B, am I guaranteed to see <code>"hello"</code> and then <code>"world"</code> or is it possible the messages are delivered out of order?</p> Ruby master - Bug #20271 (Open): Issue with moving embedded string across ractorshttps://bugs.ruby-lang.org/issues/202712024-02-16T16:29:35Zluke-gru (Luke Gruber)luke.gru@gmail.com
<p>When embedded strings are moved, not all the embedded bytes are copied over to the new embedded string. This shows itself when<br>
an embedded string has more than 16 characters.</p>
<p>For example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="n">foo</span> <span class="o">=</span> <span class="n">receive</span>
<span class="nb">puts</span> <span class="n">foo</span>
<span class="n">foo</span>
<span class="p">}</span>
<span class="n">obj</span> <span class="o">=</span> <span class="s2">"12345678"</span> <span class="o">*</span> <span class="mi">3</span>
<span class="nb">puts</span> <span class="n">obj</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<pre><code>123456781234567812345678
1234567812345678
</code></pre> Ruby master - Bug #20269 (Open): bignum too big to convert into `long' when running String#bytesl...https://bugs.ruby-lang.org/issues/202692024-02-15T16:22:39Zsimpliandy (Andy Pfister)andy.pfister@simplificator.com
<p>Running <code>String#byteslice</code> on Ruby 3.3 on Windows results in an error when using any number bigger than 32 bits:</p>
<pre><code>"".byteslice(0, 2547483647)
(irb):1:in `byteslice': bignum too big to convert into `long' (RangeError)
from (irb):1:in `<main>'
from <internal:kernel>:187:in `loop'
from C:/Ruby33-x64/lib/ruby/gems/3.3.0/gems/irb-1.11.0/exe/irb:9:in `<top (required)>'
from C:/Ruby33-x64/bin/irb:33:in `load'
from C:/Ruby33-x64/bin/irb:33:in `<main>'
</code></pre>
<p>It works fine on MacOS:</p>
<pre><code>irb(main):001> "".byteslice(0, 2547483647)
=> ""
irb(main):002> exit
Andys-MBP:project apf$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin23]
</code></pre> Ruby master - Bug #20267 (Open): Hashes that use ar_table aren't moved properly across ractorshttps://bugs.ruby-lang.org/issues/202672024-02-15T15:56:49Zluke-gru (Luke Gruber)luke.gru@gmail.com
<p>This crashes in debug build and gives weird results in non debug build, because the ar_table values aren't copied over to the new "embedded" hash during a move across ractors.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="nb">hash</span> <span class="o">=</span> <span class="n">receive</span>
<span class="nb">puts</span> <span class="nb">hash</span>
<span class="p">}</span>
<span class="n">obj</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"1"</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">"2"</span> <span class="o">=></span> <span class="mi">2</span><span class="p">,</span>
<span class="s2">"3"</span> <span class="o">=></span> <span class="mi">3</span><span class="p">,</span>
<span class="p">}</span>
<span class="nb">puts</span> <span class="n">obj</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>Crash log:</p>
<pre><code>/home/lukeg/workspace/ruby-build/miniruby(sigsegv+0x4d) [0x5641e67d105d] ../ruby/signal.c:926
/lib/x86_64-linux-gnu/libc.so.6(0x7fb4baa42520) [0x7fb4baa42520]
/home/lukeg/workspace/ruby-build/miniruby(RB_BUILTIN_TYPE+0x0) [0x5641e6778db0] ../ruby/ractor.c:3128
/home/lukeg/workspace/ruby-build/miniruby(rbimpl_RB_TYPE_P_fastpath) ../ruby/include/ruby/internal/value_type.h:351
/home/lukeg/workspace/ruby-build/miniruby(RB_TYPE_P) ../ruby/include/ruby/internal/value_type.h:378
/home/lukeg/workspace/ruby-build/miniruby(RB_FL_ABLE) ../ruby/include/ruby/internal/fl_type.h:449
/home/lukeg/workspace/ruby-build/miniruby(RB_FL_TEST_RAW) ../ruby/include/ruby/internal/fl_type.h:471
/home/lukeg/workspace/ruby-build/miniruby(rb_ractor_shareable_p) ../ruby/include/ruby/ractor.h:256
/home/lukeg/workspace/ruby-build/miniruby(reset_belonging_enter) ../ruby/ractor.c:3121
</code></pre> Ruby master - Feature #20266 (Open): New syntax to escape embed strings in Regexp literalhttps://bugs.ruby-lang.org/issues/202662024-02-15T08:45:41Zusa (Usaku NAKAMURA)usa@garbagecollect.jp
<a name="Premise"></a>
<h1 >Premise<a href="#Premise" class="wiki-anchor">¶</a></h1>
<p>When using embed strings in Regexp literal, it is interpreted as a part of the Regexp.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">foo</span> <span class="o">=</span> <span class="s2">"[a-z]"</span>
<span class="nb">p</span> <span class="sr">/</span><span class="si">#{</span><span class="n">foo</span><span class="si">}</span><span class="sr">/</span> <span class="c1">#=> /[a-z]/</span>
</code></pre>
<p>So, currently we often have to escape the embed strings.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">foo</span> <span class="o">=</span> <span class="s2">"[a-z]"</span>
<span class="nb">p</span> <span class="sr">/</span><span class="si">#{</span><span class="no">Regexp</span><span class="p">.</span><span class="nf">quote</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span><span class="si">}</span><span class="sr">/</span> <span class="c1">#=> /\[a\-z\]/</span>
</code></pre>
<p>This is very long and painful to write every time.<br>
So, I propose new syntax to escape embed strings automatically.</p>
<a name="Proposal"></a>
<h1 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h1>
<p>Adding new token <code>#{=</code> in Regexp literal:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">foo</span> <span class="o">=</span> <span class="s2">"[a-z]"</span>
<span class="nb">p</span> <span class="sr">/</span><span class="si">#{</span><span class="o">=</span><span class="n">foo</span><span class="si">}</span><span class="sr">/</span> <span class="c1">#=> /\[a\-z\]/</span>
</code></pre>
<p>When <code>#{=</code> is used instead of <code>#{</code>, ruby calls <code>Regexp.quote</code> internally.</p>
<a name="Compatibility"></a>
<h1 >Compatibility<a href="#Compatibility" class="wiki-anchor">¶</a></h1>
<p>Current ruby causes syntax error when using <code>#{=</code>, then there is no incompatibilty.</p>
<a name="Out-of-scope-of-this-proposal"></a>
<h1 >Out of scope of this proposal<a href="#Out-of-scope-of-this-proposal" class="wiki-anchor">¶</a></h1>
<p>I do not propose about <code>#{=</code> in another literals. They are out of scope of this proposal.</p> Ruby master - Bug #20262 (Open): Regex mismatch between Ruby 3.2.2 and 3.3.0https://bugs.ruby-lang.org/issues/202622024-02-13T06:28:11Zweilandia (Nick Weiland)
<p>This might be a duplicate of <a href="https://bugs.ruby-lang.org/issues/20098" class="external">https://bugs.ruby-lang.org/issues/20098</a>, but I cannot make it match with the backref so maybe not.</p>
<p>Below example matches in 3.2.2 but not in 3.3.0</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">str</span> <span class="o">=</span> <span class="s2">"------------abcdefg------------#3895912"</span>
<span class="n">re</span> <span class="o">=</span> <span class="sr">/()\1\b\w*[a-zA-Z-]*\d+[\w-]{3,}\w+\b/</span>
<span class="n">re</span><span class="p">.</span><span class="nf">match?</span><span class="p">(</span><span class="n">str</span><span class="p">)</span>
</code></pre> Ruby master - Feature #20261 (Open): Add symbol synonyms for '' and nil for IO method line separa...https://bugs.ruby-lang.org/issues/202612024-02-12T20:34:51Zburdettelamar (Burdette Lamar)
<p>[Feature 20261] For IO's line-oriented read methods, there are two special values for the line-separator argument <code>sep</code>; I'm proposing to add (user-friendlier) symbol synonyms for those values:</p>
<ul>
<li>
<code>:paragraph</code> as synonym for <code>''</code> (read paragraphs).</li>
<li>
<code>:slurp</code> as synonym for <code>nil</code> (read all).</li>
</ul>
<p>Details (code, documentation, tests) may be seen at <a href="https://github.com/ruby/ruby/pull/9921" class="external">https://github.com/ruby/ruby/pull/9921</a>.</p> Ruby master - Misc #20259 (Open): Proposal to add "ruby --irb" and / or "ruby --start-irb" to sta...https://bugs.ruby-lang.org/issues/202592024-02-12T18:48:24ZrubyFeedback (robert heiler)
<p>This issue proposes to add:</p>
<p>a) a commandline flag to bin/ruby that allows the user to start irb,</p>
<p>and</p>
<p>b) allow the user to make use of ruby to start irb, via the commandline (thus, the<br>
proposal's a) and b) are naturally connected to one another, meaning that we would<br>
have a commandline flag for the binary "ruby", and this flag, when invoked, will<br>
start irb, in the current terminal, just as if we would have typed "irb")</p>
<p>Background to this proposal, including prior proposals:</p>
<p>I believe there are prior proposals that are related, such as this one here from<br>
~3 years ago:</p>
<p><a href="https://bugs.ruby-lang.org/issues/17859" class="external">https://bugs.ruby-lang.org/issues/17859</a></p>
<p>by deivid.</p>
<p>Note that my proposal is a bit different: I don't propose that "ruby" would behave<br>
like python here, but instead I would propose that bin/ruby gets a specific flag<br>
such as "--irb" and/or "--start-irb" (the latter is a bit longer to type, so the<br>
former is more convenient, but I also like that the latter, aka --start-irb is more<br>
specific, showing the intent more clearly; and we can add both flags anyway, so<br>
people can just pick what they prefer. I would probably just make an alias such<br>
as "rirb" for "ruby --start-irb" on my local system).</p>
<p>The way I came yesterday to a somewhat similar conclusion as deivid did, shall be<br>
explained next, even though my path is an indirect one.</p>
<p>As some may know, Tim (and others) are creating natalie, a ruby "dialect" (well,<br>
it'll be ruby in the end I believe but right now it does not satisfy the full<br>
ruby specification):</p>
<p><a href="https://github.com/natalie-lang/natalie" class="external">https://github.com/natalie-lang/natalie</a></p>
<p>Although there are some issues natalie currently has (it's a bit slow right now, for<br>
instance), they did invest quite a lot of time into it and it is slowly shaping up -<br>
at the least presently. More work to be done on satisfying ruby's specification.</p>
<p>Yesterday I compiled natalie from a git checkout and it compiled and installed fine.<br>
I was confused that under bin/ there was only "natalie", but no irb. I may be wrong<br>
but I think in the past I had bin/irb there too. Anyway, that then got me thinking<br>
that I may have made a mistake - but, also, why can't we just use ruby to start<br>
irb, as-is? That is, the executable called "ruby", under bin/ruby.</p>
<p>Yes, this is natalie, not ruby, I understand that. I also fully understand that MRI<br>
ruby having --irb and --start-irb does not change the situation for natalie, jruby,<br>
truffleruby - you name it. I get that, although I should like to point out that they<br>
may often follow suit what MRI ruby decides, so if they have a variant of irb, it<br>
may be likely that they would add the same or similar commandline flags to support<br>
changes in MRI, even if it may take a while (see jruby issue tracker having tons<br>
of todo-entries on github, to keep track of new ruby releases and what changed<br>
between version).</p>
<p>But I was then also wondering why ruby itself would not allow us to start irb in such<br>
a way, via "ruby". I understand that we have bin/irb, so this is not a real problem -<br>
people can just start "irb" normally. And I think we can require irb from a ruby .rb<br>
file just fine, as well, and use irb that way, all fine too. But even then I still<br>
wondered why we can not run irb via "ruby". Is there any reason that speaks against<br>
"ruby --start-irb" starting irb? I don't think the stdlib idea for ruby was to prevent<br>
ruby itself from providing convenience to the user. I also don't propose other gems<br>
to be started like that either, supporting many different commandline flags or<br>
--start=name_of_gem_here; irb is more important, in my opinion, than many other<br>
gems. The key idea for irb is to have "interactive ruby". pry pushed that idea<br>
further, and I think the recent irb releases included some ideas from pry too. ALL<br>
of these focus on an "interactive ruby", no matter the real name (be it irb,<br>
pry or anything else) - just as "python" without arguments focuses on "interactive<br>
python".</p>
<p>If we look at python, python kind of provides two ways to run things: "python foobar.py",<br>
and without argument, the interactive python. Again, I am not proposing to join that<br>
together, different to deivid's proposal, but indeed, it made me question ruby's current<br>
behaviour.</p>
<p>I think python's behaviour to be able to select either way, via "python" itself, is better;<br>
that we are unable to select which behaviour to use via commandline flag, in python, is a<br>
drawback, as jeremy pointed out since he prefers the current ruby heaviour, but via an<br>
additional commandline flag I think we can at the least get python's interactive behaviour<br>
into ruby (that is, IRB; although it should be mentioned that the new IRB is a bit different<br>
to the older IRB, but I leave it at that, since the proposal here is about starting IRB,<br>
not about IRB's behaviour - the latter is for the github project of IRB, rather than MRI's<br>
issue tracker here).</p>
<p>deivid reasoned that python's behaviour is useful for newbies, which I do not doubt. jeremy<br>
said that he prefers the current behaviour of ruby, which is also fine. An explicit commandline<br>
flag for starting irb may be a compromise, but I should like to say that my rationale today<br>
was different from deivid's one, in that I actually really want bin/ruby to give us a SIMPLE<br>
means to start irb, rather than merely "ruby" showing the same behaviour as "python" does,<br>
in regarsd to starting its interactive variant.</p>
<p>Again, I can work around this just fine, using a .rb file to start IRB and so forth, but I<br>
really think having this supported via a simple commandline flag may be more convenient. Of<br>
course, a secondary proposal to this may then be to add another commandline flag to get<br>
to support deivid's suggestion :) - but that would also be for another issue request on the<br>
bugtracker here. For this proposal, I really merely suggest to add --irb and/or --start-irb<br>
(or any other variant that may be more fitting, perhaps --interactive; the name is not so<br>
important, although it should be a convenient name and ideally short. The functionality is<br>
more important than the name.)</p>
<p>Implementation details:</p>
<p>Let's for a moment assume people may find this useful. Then the question is, which irb should<br>
be started when using "ruby --irb"?</p>
<p>Probably the most sensible default option here is to simply use whatever irb version has been<br>
installed on the target computer. Hiroshi Shibata and others worked towards gemifying ruby's<br>
stdlib, so it makes sense that "ruby --start-irb" would use the currently installed irb version,<br>
whatever that is. For most ruby users this is probably the one that came distributed with<br>
whatever ruby version they are using, at the least for modern ruby versions.</p>
<p>Otherwise they may just install a new irb version from e. g.</p>
<pre><code>https://github.com/ruby/irb
</code></pre>
<p>or whatever:</p>
<pre><code>gem install irb
</code></pre>
<p>installs. And this is then started when they do "ruby --start-irb". So, "ruby --start-irb"<br>
would be exactly the same as the user typing "irb" on the commandline, without any further<br>
arguments.</p>
<p>Of course the user can also start irb via "irb", as-is. So they'd only get an additional<br>
way to start irb. They can continue to use "irb" just fine. All that would change is that<br>
"ruby" itself would get an additional commandline argument, one that starts its "interactive<br>
part".</p>
<p>Anyway - I have no idea how much support the above would find; perhaps if jeremy is active<br>
he could compare it towards deivid's suggestion and comment on it too. I thought about<br>
appending to deivid's suggestion, but the suggestion here is a bit different, so I think<br>
it may be better to propose it as a separate one, even though it is somewhat close to his<br>
proposal, even though it is unrelated (see how I reached that conclusion, which I think is<br>
different than deivid's proposal).</p>
<p>I am not sure if there are even older proposals or not, but there may be. It's also fine<br>
to close this issue here, by the way, to keep the issue tracker list shorter (and perhaps<br>
link it towards deivid's above issue too, if this is closed, which is fine). I kind of<br>
wanted to contribute a bit to the discussion from a different point of view. Perhaps to<br>
avoid having too many open issues, this issue here could be left open for a month or<br>
two, to allow for a bit of more discussion, then it can be closed and e. g. referred to<br>
deivids' issue; and if deivid has time he may comment on the one here or his older<br>
proposal. At any rate, thank you for reading this proposal.</p>
<p>(PS: I filed it under Misc because it did not seem to necessarily be a Feature of the<br>
ruby language itself. Of course it could also fit under Feature, so I was not sure<br>
where to categorize it.)</p> Ruby master - Bug #20255 (Open): Embedded arrays aren't moved correctly across ractorshttps://bugs.ruby-lang.org/issues/202552024-02-10T17:31:30Zluke-gru (Luke Gruber)luke.gru@gmail.com
<p><code>ractor.send(ary, move: true)</code> works incorrectly because if <code>ary</code> is embedded, the new moved object doesn't populate its own embedded space, it uses the MovedObject's embedded space.</p>
<p>example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span>
<span class="n">inner_ary</span> <span class="o">=</span> <span class="n">receive</span>
<span class="n">values</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">values</span><span class="p">[</span><span class="ss">:equal</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">inner_ary</span> <span class="o">==</span> <span class="p">[</span><span class="s2">""</span><span class="p">,{},</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">])</span>
<span class="n">values</span><span class="p">[</span><span class="ss">:string</span><span class="p">]</span> <span class="o">=</span> <span class="n">inner_ary</span><span class="p">.</span><span class="nf">to_s</span>
<span class="n">values</span>
<span class="p">}</span>
<span class="n">ary</span> <span class="o">=</span> <span class="p">[</span><span class="no">String</span><span class="p">.</span><span class="nf">new</span><span class="p">,</span><span class="no">Hash</span><span class="p">.</span><span class="nf">new</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">]</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">ary</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">r_values</span> <span class="o">=</span> <span class="n">r</span><span class="p">.</span><span class="nf">take</span>
<span class="nb">p</span> <span class="n">r_values</span><span class="p">[</span><span class="ss">:equal</span><span class="p">]</span>
<span class="nb">p</span> <span class="n">r_values</span><span class="p">[</span><span class="ss">:string</span><span class="p">]</span>
<span class="c1"># => false</span>
<span class="c1"># => "[\"\", {}, 2, 2.0, 21747991570, String, 3]"</span>
</code></pre> Ruby master - Feature #20249 (Open): Introduce a backtrace-only mode for rb_bug()https://bugs.ruby-lang.org/issues/202492024-02-09T06:37:45Zosyoyu (Daisuke Aritomo)
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>When a segfault or some unexpected situation occurs, <code>rb_bug()</code> is called and prints some few hundred to thousands of lines.</p>
<p>The most helpful parts are (arguably) "Ruby level backtrace information" and "C-level backtrace information", but those parts are buried in the very lengthy report.<br>
In particular, the "Other runtime information" which contains the list of loaded features (scripts?) and the process memory map could be extremely long despite it does not come very useful, at least when developing C extensions.</p>
<p>Even a minimal report from a simple script would consist of 250 lines and require 7 PgUps on my MacBook Air (13 inch) to reach the backtrace part, which contains all the information I need.</p>
<a name="Proposal"></a>
<h2 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h2>
<p>My proposal is to default to a "minimal report" mode with a limited set of sections, perhaps only "Ruby level backtrace information" and "C level backtrace information" only</p>
<p>When a full report is desired (i.e. for bug reports), the user could re-run the script with an special environment variable, such as <code>RUBY_FULL_CRASH_REPORT=1</code>.<br>
Rust implmements a similar pattern. It doesn't print the full backtrace on panics by default; instead, it guides the user to re-run the program with <code>RUST_BACKTRACE=1</code>.</p>
<p>It might be hard to reproduce some crashes and segfaults, especially in long-running daemons. It might be nice to default to the "full" mode when stdout is not a tty, since daemons tend to run in non-tty environments.</p>
<a name="Appendix"></a>
<h2 >Appendix<a href="#Appendix" class="wiki-anchor">¶</a></h2>
<p>A typical crash report would look like this:</p>
<pre><code>../../example.rb: [BUG]
ruby 3.4.0dev (2024-01-20T15:27:19Z master 366b14c0cd) [arm64-darwin23]
-- Crash Report log information --------------------------------------------
(5 lines)
-- Control frame information -----------------------------------------------
(~50 lines)
-- Ruby level backtrace information ----------------------------------------
(depends on program; typically ~50 lines in Rails)
-- C level backtrace information -------------------------------------------
(50+-ish lines, depends on program)
-- Machine register context ------------------------------------------------
(~10 lines)
-- Threading information ---------------------------------------------------
(2 lines)
-- Other runtime information -----------------------------------------------
* Loaded script (1 line)
* Loaded features (depends on program; 800+ lines in Rails)
* Process memory map (depends on environment; around 200 lines?)
</code></pre> Ruby master - Bug #20243 (Open): M:N threading VM_ASSERT failure in rb_current_execution_context ...https://bugs.ruby-lang.org/issues/202432024-02-07T09:18:09Zkjtsanaktsidis (KJ Tsanaktsidis)kjtsanaktsidis@gmail.com
<p>When building with Clang 17 and <code>-DVM_CHECK_MODE=1</code> (with the following configure)</p>
<pre><code>optflags="-ggdb3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -O3" cflags="-DVM_CHECK_MODE=1" CC=clang ../configure --prefix=/home/kj/ruby/installed --enable-yjit=dev --disable-install-doc
</code></pre>
<p>And then running the following script with the built <code>./miniruby</code> (which is actually from <code>bootstraptest/test_ractor.rb</code>):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">counts</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">counts</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span>
<span class="n">ractors</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="o">..</span><span class="mi">3</span><span class="p">).</span><span class="nf">map</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">receive</span> <span class="p">}</span> <span class="p">}</span>
<span class="n">counts</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span>
<span class="n">ractors</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">send</span><span class="p">(</span><span class="s1">'End 0'</span><span class="p">).</span><span class="nf">take</span>
<span class="nb">sleep</span> <span class="mf">0.1</span> <span class="k">until</span> <span class="n">ractors</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">inspect</span> <span class="o">=~</span> <span class="sr">/terminated/</span>
<span class="n">counts</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span>
<span class="n">ractors</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nf">send</span><span class="p">(</span><span class="s1">'End 1'</span><span class="p">).</span><span class="nf">take</span>
<span class="nb">sleep</span> <span class="mf">0.1</span> <span class="k">until</span> <span class="n">ractors</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="nf">inspect</span> <span class="o">=~</span> <span class="sr">/terminated/</span>
<span class="n">counts</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span>
<span class="n">ractors</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nf">send</span><span class="p">(</span><span class="s1">'End 2'</span><span class="p">).</span><span class="nf">take</span>
<span class="nb">sleep</span> <span class="mf">0.1</span> <span class="k">until</span> <span class="n">ractors</span><span class="p">[</span><span class="mi">2</span><span class="p">].</span><span class="nf">inspect</span> <span class="o">=~</span> <span class="sr">/terminated/</span>
<span class="n">counts</span> <span class="o"><<</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">count</span>
<span class="n">counts</span><span class="p">.</span><span class="nf">inspect</span>
</code></pre>
<p>I get the following crash:</p>
<pre><code>Assertion Failed: ../vm_core.h:1957:rb_current_execution_context:ec == rb_current_ec_noinline()
ruby 3.4.0dev (2024-02-07T07:52:06Z ktsanaktsidis/igno.. 5cc6d944c2) [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0003 p:0003 s:0010 e:000009 METHOD <internal:ractor>:431
c:0002 p:0004 s:0006 e:000005 BLOCK ractor_crash.rb:3 [FINISH]
c:0001 p:---- s:0003 e:000002 DUMMY [FINISH]
-- Ruby level backtrace information ----------------------------------------
ractor_crash.rb:3:in `block (2 levels) in <main>'
<internal:ractor>:431:in `receive'
-- Threading information ---------------------------------------------------
Total ractor count: 2
Ruby thread count for this ractor: 1
-- C level backtrace information -------------------------------------------
/home/kj/ruby/build/miniruby(rb_print_backtrace+0x14) [0x55faa97a4ebd] ../vm_dump.c:820
/home/kj/ruby/build/miniruby(rb_vm_bugreport) ../vm_dump.c:1151
/home/kj/ruby/build/miniruby(rb_assert_failure+0x81) [0x55faa94d2719] ../error.c:1131
./miniruby(thread_sched_wait_running_turn+0x2e9) [0x55faa9726f59]
/home/kj/ruby/build/miniruby(rb_ractor_sched_sleep+0x10b) [0x55faa972687b] ../thread_pthread.c:1348
/home/kj/ruby/build/miniruby(ractor_check_ints+0x0) [0x55faa968b328] ../ractor.c:683
/home/kj/ruby/build/miniruby(ractor_sleep_with_cleanup) ../ractor.c:684
/home/kj/ruby/build/miniruby(ractor_sleep+0x15) [0x55faa968adf4] ../ractor.c:701
/home/kj/ruby/build/miniruby(ractor_wait_receive) ../ractor.c:748
/home/kj/ruby/build/miniruby(ractor_receive+0x1f) [0x55faa968768e] ../ractor.c:762
/home/kj/ruby/build/miniruby(builtin_inline_class_431) ../ractor.rb:432
/home/kj/ruby/build/miniruby(builtin_invoker0+0x6) [0x55faa978fc66] ../vm_insnhelper.c:6746
/home/kj/ruby/build/miniruby(invoke_bf+0x39) [0x55faa979816e] ../vm_insnhelper.c:6886
/home/kj/ruby/build/miniruby(vm_invoke_builtin_delegate) ../vm_insnhelper.c:6909
/home/kj/ruby/build/miniruby(rb_vm_check_ints+0x0) [0x55faa9771fac] ../insns.def:1533
/home/kj/ruby/build/miniruby(vm_pop_frame) ../vm_insnhelper.c:419
/home/kj/ruby/build/miniruby(vm_exec_core) ../insns.def:1537
/home/kj/ruby/build/miniruby(vm_exec_loop+0x0) [0x55faa9767f02] ../vm.c:2489
/home/kj/ruby/build/miniruby(rb_vm_exec) ../vm.c:2492
/home/kj/ruby/build/miniruby(invoke_block+0x6f) [0x55faa9781a58] ../vm.c:1512
/home/kj/ruby/build/miniruby(invoke_iseq_block_from_c) ../vm.c:1582
/home/kj/ruby/build/miniruby(invoke_block_from_c_proc) ../vm.c:1680
/home/kj/ruby/build/miniruby(vm_invoke_proc) ../vm.c:1710
/home/kj/ruby/build/miniruby(rb_vm_invoke_proc_with_self+0x5a) [0x55faa9781eaa] ../vm.c:1745
/home/kj/ruby/build/miniruby(thread_do_start_proc+0x199) [0x55faa9739e19] ../thread.c:574
/home/kj/ruby/build/miniruby(thread_do_start+0x6c) [0x55faa973933f] ../thread.c:618
/home/kj/ruby/build/miniruby(thread_start_func_2) ../thread.c:668
/home/kj/ruby/build/miniruby(rb_native_mutex_lock+0x0) [0x55faa973a141] ../thread_pthread.c:2234
/home/kj/ruby/build/miniruby(thread_sched_lock_) ../thread_pthread.c:387
/home/kj/ruby/build/miniruby(call_thread_start_func_2) ../thread_pthread_mn.c:436
/home/kj/ruby/build/miniruby(co_start) ../thread_pthread_mn.c:434
</code></pre>
<p>The failing assertion is this one in vm_core.h: <a href="https://github.com/ruby/ruby/blob/42c36269403baac67b0d5dc1d6d6e31168cf6a1f/vm_core.h#L1957" class="external">https://github.com/ruby/ruby/blob/42c36269403baac67b0d5dc1d6d6e31168cf6a1f/vm_core.h#L1957</a>. It actually has a very helpful comment.</p>
<pre><code> /* On the shared objects, `__tls_get_addr()` is used to access the TLS
* and the address of the `ruby_current_ec` can be stored on a function
* frame. However, this address can be mis-used after native thread
* migration of a coroutine.
* 1) Get `ptr =&ruby_current_ec` op NT1 and store it on the frame.
* 2) Context switch and resume it on the NT2.
* 3) `ptr` is used on NT2 but it accesses to the TLS on NT1.
* This assertion checks such misusage.
*
* To avoid accidents, `GET_EC()` should be called once on the frame.
* Note that inlining can produce the problem.
*/
VM_ASSERT(ec == rb_current_ec_noinline());
</code></pre>
<p>What seems to be happening is exactly that. This is a disassembly of the relevant bits of <code>thread_sched_wait_running_turn</code>:</p>
<pre><code>........
# This is the only bits of the entire function which access the TLS base register %fs.
# It seems to have spilled the value of ruby_current_ec into %r13.
0x000055603d2e1cf8 <+136>: mov $0xffffffffffffff90,%rax
0x000055603d2e1cff <+143>: mov %fs:0x0,%r12
0x000055603d2e1d08 <+152>: add %rax,%r12
0x000055603d2e1d0b <+155>: mov %fs:(%rax),%r13
........
# There's a call to coroutine_transfer, so after this point we're returned to on a
# different thread
0x000055603d2e1e90 <+544>: call 0x55603d7fce84 <coroutine_transfer>
# But nothing ever loads the address of ruby_current_ec from %fs again (i didn't trace
# exactly the data flow from %r13 at 0x000055603d2e1d0b to here, but i assume it spilled
# somewhere and now got loaded back into %r15 here). In any case, that means %r15 here
# contains the value of ruby_current_ec from the _old_ thread, not the current one.
0x000055603d2e1e95 <+549>: mov %rbx,0x28(%r14)
0x000055603d2e1e99 <+553>: mov (%r12),%r15
0x000055603d2e1e9d <+557>: call 0x55603d33a010 <rb_current_ec_noinline>
0x000055603d2e1ea2 <+562>: cmp %rax,%r15
=> 0x000055603d2e1ea5 <+565>: jne 0x55603d2e1f3a <thread_sched_wait_running_turn+714>
........
# assertion failure code path.
0x000055603d2e1f3a <+714>: lea 0x542c0c(%rip),%rdi # 0x55603d824b4d
0x000055603d2e1f41 <+721>: lea 0x542c12(%rip),%rdx # 0x55603d824b5a
0x000055603d2e1f48 <+728>: lea 0x542c28(%rip),%rcx # 0x55603d824b77
0x000055603d2e1f4f <+735>: mov $0x7a5,%esi
0x000055603d2e1f54 <+740>: call 0x55603d08d698 <rb_assert_failure>
</code></pre>
<p>if we look at the register values from <code>0x000055603d2e1ea2</code>:</p>
<pre><code>(rr) print/x $rax
$2 = 0x55603e159ad0
(rr) print/x $r15
$3 = 0x0
</code></pre>
<p>So the value from <code>%rax</code> which came from <code>ruby_current_ec_noinline</code> is correctly the value of <code>ruby_current_ec</code> for this thread, and <code>%r15</code> contains a stale value from a previous thread.</p>
<ul>
<li>
</ul>
<p>Now, what can we <em>do</em> about this, is a different question :/ There's a really good stackoverflow answer about it here: <a href="https://stackoverflow.com/questions/75592038/how-to-disable-clang-expression-elimination-for-thread-local-variable" class="external">https://stackoverflow.com/questions/75592038/how-to-disable-clang-expression-elimination-for-thread-local-variable</a>, but to summarise</p>
<ul>
<li>longstanding GCC and Clang bugs for this exist and have been marked as WONTFIX (<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26461" class="external">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=26461</a>, <a href="https://github.com/llvm/llvm-project/issues/19551" class="external">https://github.com/llvm/llvm-project/issues/19551</a>)</li>
<li>It's even worse than this EC problem - things like <code>errno</code> also might be incorrectly persisted across coroutine switches (so e.g. an inlined C library function could in theory set <code>errno</code> in another thread, for example)</li>
<li>C++ actually has coroutines now, so this <em>must</em> work for those. Clang at least has fixed some TLS problems in their C++ coroutine implementation (<a href="https://github.com/llvm/llvm-project/issues/47179" class="external">https://github.com/llvm/llvm-project/issues/47179</a>)</li>
</ul>
<p>Other than reimplementing all of our coroutine stuff on top of C++ coroutines, I'm not sure what else we can do. AFAICT there's no way to tell the compiler that we clobbered the <code>%fs</code> register because that's just not a thing in its model (<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66631" class="external">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66631</a>, but i assume clang is similar).</p>
<p>Thoughts? For now I think my workaround is to disable M:N at build time when building with ASAN (or turn optimizations down). At least this isn't a problem with <code>Fiber</code> because we never move them across threads (probably for this reason in part).</p> Ruby master - Misc #20240 (Open): Unable to build ruby 3.1.0 on macOS when shared due to dylibs (...https://bugs.ruby-lang.org/issues/202402024-02-06T10:53:26Zjmarrec (Julien Marrec)
<p>I am trying to develop a conan (the C/C++ package manager) recipe for Ruby. The recipe would allow downstream users to 1) get a runnable ruby executable, and 2) be able to link to ruby, or embbed it in a C/C++ program if built statically, in an easy way.</p>
<p>Currently there is an existing ruby 3.1.0 recipe that I'm trying to adapt, so I have to support this version.</p>
<p>First off, let me say that I can succesfully build with 3.3.0, so I know something has changed for the better since then. I'm just at a lost when figuring out what I need to backport to make 3.1.0 work.</p>
<p>The original issue is that it appears miniruby is looking for some dylibs and not finding them. Even if I do define <code>LD_LIBRARY_PATH</code>, <code>DYLD_LIBRARY_PATH</code> or <code>DYLD_FALLBACK_LIBRARY_PATH</code> (any combinations of these three) in my env.</p>
<pre><code class="shell syntaxhl" data-language="shell">dsymutil exe/ruby<span class="p">;</span> <span class="o">{</span> <span class="nb">test</span> <span class="nt">-z</span> <span class="s1">''</span> <span class="o">||</span> codesign <span class="nt">-s</span> <span class="s1">''</span> <span class="nt">-f</span> exe/ruby<span class="p">;</span> <span class="o">}</span>
./miniruby <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">'prog, dest, inst = ARGV; dest += "/ruby"'</span> <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">'exit unless prog==inst'</span> <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">'unless prog=="ruby"'</span> <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">' begin File.unlink(dest); rescue Errno::ENOENT; end'</span> <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">' File.symlink(prog, dest)'</span> <span class="se">\</span>
<span class="nt">-e</span> <span class="s1">'end'</span> <span class="se">\</span>
ruby exe ruby
dyld[59344]: Library not loaded: @rpath/libgmp.10.dylib
Referenced from: <356E0011-6223-321A-9179-D55618D248D0> /Users/julien/.conan2/p/b/ruby9cafa28a7060d/b/build-release/miniruby
Reason: no LC_RPATH<span class="s1">'s found
make: *** [exe/ruby] Abort trap: 6
make: *** Deleting file `exe/ruby'</span>
</code></pre>
<p>It seems that something is unsetting the variables, because this for eg works fine</p>
<pre><code class="shell syntaxhl" data-language="shell"><span class="nv">DYLD_LIBRARY_PATH</span><span class="o">=</span>/Users/julien/.conan2/p/b/zlib1f8e7d96319f0/p/lib:/Users/julien/.conan2/p/b/opense854e464e8ff6/p/lib:/Users/julien/.conan2/p/b/libyae2f0aa15c9e92/p/lib:/Users/julien/.conan2/p/b/libff05fe9d5b96f79/p/lib:/Users/julien/.conan2/p/b/readl0d0041a63fa03/p/lib:/Users/julien/.conan2/p/b/termc22b5bb1515971/p/lib:/Users/julien/.conan2/p/b/gmp676fa41eaa3d6/p/lib: /Users/julien/.conan2/p/b/ruby9cafa28a7060d/b/build-release/miniruby <span class="nt">-e</span> <span class="s2">"puts 'Hello, world'"</span>
</code></pre>
<p>My configure call is like this:</p>
<pre><code class="shell syntaxhl" data-language="shell">./configure <span class="nt">--enable-shared</span> <span class="nt">--disable-static</span> <span class="nt">--prefix</span><span class="o">=</span>/ <span class="s1">'--bindir=${prefix}/bin'</span> <span class="s1">'--sbindir=${prefix}/bin'</span> <span class="s1">'--libdir=${prefix}/lib'</span> <span class="s1">'--includedir=${prefix}/include'</span> <span class="s1">'--oldincludedir=${prefix}/include'</span> <span class="nt">--disable-install-doc</span> <span class="nt">--enable-load-relative</span> <span class="nt">--with-zlib-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/zlib1f8e7d96319f0/p <span class="nt">--with-openssl-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/opense854e464e8ff6/p <span class="nt">--with-libffi-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/libff05fe9d5b96f79/p <span class="nt">--with-libyaml-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/libyae2f0aa15c9e92/p <span class="nt">--with-readline-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/readl0d0041a63fa03/p <span class="nt">--with-gmp-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/gmp676fa41eaa3d6/p <span class="nt">--with-opt-dir</span><span class="o">=</span>/Users/julien/.conan2/p/b/opense854e464e8ff6/p:/Users/julien/.conan2/p/b/libff05fe9d5b96f79/p:/Users/julien/.conan2/p/b/libyae2f0aa15c9e92/p:/Users/julien/.conan2/p/b/readl0d0041a63fa03/p:/Users/julien/.conan2/p/b/gmp676fa41eaa3d6/p <span class="nt">--disable-jit-support</span>
</code></pre>
<p>I have tried to backport <a href="https://github.com/ruby/ruby/pull/6296/files" class="external">https://github.com/ruby/ruby/pull/6296/files</a> and <a href="https://github.com/ruby/ruby/commit/48644e71096c70132be9dfdcbfb414ec2e68d18b" class="external">https://github.com/ruby/ruby/commit/48644e71096c70132be9dfdcbfb414ec2e68d18b</a> and <a href="https://github.com/ruby/ruby/pull/8730" class="external">https://github.com/ruby/ruby/pull/8730</a> amongst other things but I can't make it work. (I even tried a more brute force approach patching a lot of files by diffing 3.3.0 with 3.1.0, but please note I don't know what I'm doing... and I can get to the install step but then I get some errors about Psych / libymal and undefined Gem::Install:Zlib).</p>
<p>I would <strong>greatly</strong> appreciate if someone can spare some time to help me wrap this up (I've been trying to make the recipe work for so long that I'm about to give up...)</p> Ruby master - Misc #20238 (Open): Use prism for mk_builtin_loader.rbhttps://bugs.ruby-lang.org/issues/202382024-02-05T20:52:02Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>I would like to propose that we use prism for mk_builtin_loader.rb.</p>
<p>Right now the Ruby syntax that you can use in builtin classes is restricted to the base Ruby version (2.7). This means you can't use a lot of the nicer syntax that Ruby has shipped in the last couple of years.</p>
<p>If we switch to using prism to parse the builtin files instead of using ripper, then we can always use the latest version of Ruby syntax. A pull request for this is here: <a href="https://github.com/kddnewton/ruby/pull/65" class="external">https://github.com/kddnewton/ruby/pull/65</a>. The approach for the PR is taken from how RJIT bindgen works.</p> Ruby master - Bug #20237 (Assigned): Unable to unshare(CLONE_NEWUSER) in Linux because of timer t...https://bugs.ruby-lang.org/issues/202372024-02-05T04:59:20Zhanazuki (Kasumi Hanazuki)
<a name="Backgrounds"></a>
<h2 >Backgrounds<a href="#Backgrounds" class="wiki-anchor">¶</a></h2>
<p><a href="https://man7.org/linux/man-pages/man2/unshare.2.html" class="external">unshare(2)</a> is a syscall in Linux to move the calling process into a fresh execution context. With <code>unshare(CLONE_NEWUSER)</code> you can move a process into a new <a href="https://man7.org/linux/man-pages/man7/user_namespaces.7.html" class="external">user_namespace(7)</a>, where the process gains the full capability on the resources within the namespace. This is fundamental for Linux containers to achieve privilege separation. <code>unshare(CLONE_NEWUSER)</code> requires the calling process to be single-threaded (or no background threads are running). So, it is often invoked after <code>fork(2)</code> as forking propagates only the calling thread to the child process.</p>
<a name="Problem"></a>
<h2 >Problem<a href="#Problem" class="wiki-anchor">¶</a></h2>
<p>It becomes a problem that Ruby 3.3 on Linux uses timer threads even for a single-<code>Thread</code>ed application. Because <code>Kernel#fork</code> spawns a thread in the child process before the control returns to the user code, there is no chance to call <code>unshare(CLONE_NEWUSER)</code> in Ruby.</p>
<p>The following snippet is a reproducer of this problem. This program first forks and then shows the user namespace to which the process belongs before and after calling unshare(2). It also shows the threads of the child process after forking.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">p</span><span class="p">(</span><span class="no">RUBY_DESCRIPTION</span><span class="p">:)</span>
<span class="nb">require</span> <span class="s1">'fiddle/import'</span>
<span class="k">module</span> <span class="nn">C</span>
<span class="kp">extend</span> <span class="no">Fiddle</span><span class="o">::</span><span class="no">Importer</span>
<span class="n">dlload</span> <span class="s1">'libc.so.6'</span>
<span class="n">extern</span> <span class="s1">'int unshare(int flags)'</span>
<span class="no">CLONE_NEWUSER</span> <span class="o">=</span> <span class="mh">0x10000000</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">raise_system_call_error</span>
<span class="k">raise</span> <span class="no">SystemCallError</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Fiddle</span><span class="p">.</span><span class="nf">last_error</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">pid</span> <span class="o">=</span> <span class="nb">fork</span> <span class="k">do</span>
<span class="nb">system</span><span class="p">(</span><span class="s2">"ps -O tid -T -p #$$"</span><span class="p">)</span>
<span class="nb">system</span><span class="p">(</span><span class="s2">"ls -l /proc/self/ns/user"</span><span class="p">)</span>
<span class="k">if</span> <span class="no">C</span><span class="p">.</span><span class="nf">unshare</span><span class="p">(</span><span class="no">C</span><span class="o">::</span><span class="no">CLONE_NEWUSER</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span>
<span class="no">C</span><span class="p">.</span><span class="nf">raise_system_call_error</span> <span class="c1"># => EINVAL with Ruby 3.3</span>
<span class="k">end</span>
<span class="nb">system</span><span class="p">(</span><span class="s2">"ls -l /proc/self/ns/user"</span><span class="p">)</span>
<span class="k">end</span>
<span class="nb">p</span> <span class="no">Process</span><span class="p">.</span><span class="nf">wait2</span><span class="p">(</span><span class="n">pid</span><span class="p">)</span>
</code></pre>
<p>The program successfully changes the user namespace with Ruby 3.2, but it raises EINVAL with Ruby 3.3. You can see Ruby 3.3 has two threads running after forking.</p>
<pre><code>% rbenv shell 3.2 && ruby ./test.rb
{:RUBY_DESCRIPTION=>"ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux]"}
PID TID S TTY TIME COMMAND
1585787 1585787 S pts/12 00:00:00 ruby ./test.rb
lrwxrwxrwx 1 kasumi kasumi 0 Feb 5 02:25 /proc/self/ns/user -> 'user:[4026531837]'
lrwxrwxrwx 1 nobody nogroup 0 Feb 5 02:25 /proc/self/ns/user -> 'user:[4026532675]'
[1585787, #<Process::Status: pid 1585787 exit 0>]
% rbenv shell 3.3 && ruby ./test.rb
{:RUBY_DESCRIPTION=>"ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]"}
PID TID S TTY TIME COMMAND
1585849 1585849 S pts/12 00:00:00 ruby ./test.rb
1585849 1585851 S pts/12 00:00:00 ruby ./test.rb
lrwxrwxrwx 1 kasumi kasumi 0 Feb 5 02:25 /proc/self/ns/user -> 'user:[4026531837]'
./test.rb:10:in `raise_system_call_error': Invalid argument (Errno::EINVAL)
from ./test.rb:24:in `block in <main>'
from ./test.rb:19:in `fork'
from ./test.rb:19:in `<main>'
[1585849, #<Process::Status: pid 1585849 exit 1>]
% rbenv shell master && ruby ./test.rb
{:RUBY_DESCRIPTION=>"ruby 3.4.0dev (2024-02-04T16:05:02Z master 8bc6fff322) [x86_64-linux]"}
PID TID S TTY TIME COMMAND
1585965 1585965 S pts/12 00:00:00 ruby ./test.rb
1585965 1585967 S pts/12 00:00:00 ruby ./test.rb
lrwxrwxrwx 1 kasumi kasumi 0 Feb 5 02:25 /proc/self/ns/user -> 'user:[4026531837]'
./test.rb:10:in `raise_system_call_error': Invalid argument (Errno::EINVAL)
from ./test.rb:24:in `block in <main>'
from ./test.rb:19:in `fork'
from ./test.rb:19:in `<main>'
[1585965, #<Process::Status: pid 1585965 exit 1>]
</code></pre>
<a name="Workaround"></a>
<h2 >Workaround<a href="#Workaround" class="wiki-anchor">¶</a></h2>
<p>My workaround is to rebuild ruby with <code>rb_thread_stop_timer_thread</code> and <code>rb_thread_start_timer_thread</code> exported, and use a C-ext that stops the timer thread before calling <code>unshare</code>. This seems not robust because the process cannot know when the terminated thread is reclaimed by the kernel, after which the process is considered single-threaded.</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cp">#define _GNU_SOURCE 1
#include</span> <span class="cpf"><sched.h></span><span class="cp">
#include</span> <span class="cpf"><ruby/ruby.h></span><span class="cp">
</span>
<span class="k">static</span> <span class="n">VALUE</span> <span class="nf">Unshare_s_unshare</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">_self</span><span class="p">,</span> <span class="n">VALUE</span> <span class="n">rflags</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="k">const</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">NUM2INT</span><span class="p">(</span><span class="n">rflags</span><span class="p">);</span>
<span class="n">rb_thread_stop_timer_thread</span><span class="p">();</span>
<span class="n">usleep</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span> <span class="c1">// FIXME: It takes some time for the kernel to remove the stopped thread?</span>
<span class="kt">int</span> <span class="k">const</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">unshare</span><span class="p">(</span><span class="n">flags</span><span class="p">);</span>
<span class="n">rb_thread_start_timer_thread</span><span class="p">();</span>
<span class="k">if</span><span class="p">(</span><span class="n">ret</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="n">rb_sys_fail_str</span><span class="p">(</span><span class="n">rb_sprintf</span><span class="p">(</span><span class="s">"unshare(%#x)"</span><span class="p">,</span> <span class="n">flags</span><span class="p">));</span>
<span class="k">return</span> <span class="n">Qnil</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">RUBY_FUNC_EXPORTED</span> <span class="kt">void</span>
<span class="nf">Init_unshare</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="n">VALUE</span> <span class="n">rb_mUnshare</span> <span class="o">=</span> <span class="n">rb_define_module</span><span class="p">(</span><span class="s">"Unshare"</span><span class="p">);</span>
<span class="n">rb_define_singleton_method</span><span class="p">(</span><span class="n">rb_mUnshare</span><span class="p">,</span> <span class="s">"unshare"</span><span class="p">,</span> <span class="n">Unshare_s_unshare</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">rb_define_const</span><span class="p">(</span><span class="n">rb_mUnshare</span><span class="p">,</span> <span class="s">"CLONE_NEWUSER"</span><span class="p">,</span> <span class="n">INT2FIX</span><span class="p">(</span><span class="n">CLONE_NEWUSER</span><span class="p">));</span>
<span class="p">}</span>
</code></pre>
<a name="Questions"></a>
<h2 >Questions<a href="#Questions" class="wiki-anchor">¶</a></h2>
<ul>
<li>Is this a limitation of Ruby?</li>
<li>Is it safe (or even possible) to stop the timer thread during execution?
<ul>
<li>If so, can we export it as the public API?</li>
<li>But it may not so useful for this problem as explained in the workaround.</li>
</ul>
</li>
<li>Is it guaranteed that no other threads are running after forks?</li>
<li>Are there any better ways to solve this issue?
<ul>
<li>Can we somehow delay the start of the timer thread after forking, or hook into <code>fork</code> to run some code in the child process immediately after it spawns.</li>
<li>Can they be Ruby API instead of C API?</li>
</ul>
</li>
</ul> Ruby master - Feature #20235 (Open): Deprecate CHAR syntaxhttps://bugs.ruby-lang.org/issues/202352024-02-03T16:53:15ZDan0042 (Daniel DeLorme)
<p>I propose deprecating the <code>?c</code> syntax. It served a purpose in ruby <= 1.8, but no longer.</p>
<p>The reason I'm proposing this is because today I ran into this error:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">p</span> <span class="vg">$stdin</span><span class="p">.</span><span class="nf">closed?</span><span class="o">=></span><span class="kp">true</span> <span class="c1"># comparison of String with true failed (ArgumentError)</span>
</code></pre>
<p>I was completed mystified, and had to resort to Ripper to figure out what's going on</p>
<pre><code>p *Ripper.lex("p $stdin.closed?=>true")
[[1, 0], :on_ident, "p", CMDARG]
[[1, 1], :on_sp, " ", CMDARG]
[[1, 2], :on_gvar, "$stdin", END]
[[1, 8], :on_period, ".", DOT]
[[1, 9], :on_ident, "closed", ARG]
[[1, 15], :on_CHAR, "?=", END] #OOOOHH!!!!!
[[1, 17], :on_op, ">", BEG]
[[1, 18], :on_kw, "true", END]
</code></pre>
<p>We don't have to commit to a removal schedule right now, but I think it would at least be good to print a deprecation message if $VERBOSE.</p> Ruby master - Feature #20233 (Open): pkg-config not working on MSVChttps://bugs.ruby-lang.org/issues/202332024-02-02T08:48:23Zjmarrec (Julien Marrec)
<p>The PKG_CONFIG variable is not respected in win32/Makefile.sub</p>
<p>Also, need to ideally use the <code>--msvc-syntax</code> flag (pkgconf 1.4.0, released 7 years ago, adds it).</p>
<p>But mostly, I realized that the <code>try_ldflags</code> in <code>lib/mkmf.rb</code> actually passes these ldflags as the <code>opt</code> parameter to the <code>link_command</code> function, and not as <code>ldflags</code>. While the UNIX systems are forgiving, the MSVC compiler is not, and because the flags are passed before the <code>-link</code>, MSVC complains that it ignores it and therefore cannot find the requested library.</p> Ruby master - Misc #20232 (Open): Document Kernel#require and Module#autoload concurrency guaranteeshttps://bugs.ruby-lang.org/issues/202322024-02-01T05:20:04Zfxn (Xavier Noria)fxn@hashref.com
<p>I'd like to document <code>Kernel#require</code> and <code>Module#autoload</code> concurrency guarantees.</p>
<p>In the case of multiple threads loading the same file concurrently, <code>Kernel#require</code> will succeed in just one of them and the rest will wait and return false. If a constant that has an autoload is concurrently referenced, the same can be said. Assuming no errors, only one thread will succeed, and the rest wait. There will be no context switching in the middle of an autoload that will result in a <code>NameError</code> in other threads waiting for that constant.</p>
<p>Now, I'd like to have a discussion about those guarantees with fibers.</p>
<p>In the case of manually managed fibers, users can enter a deadlock by hand:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># This produces a deadlock.</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'/tmp/bar.rb'</span><span class="p">,</span> <span class="o"><<~</span><span class="no">RUBY</span><span class="p">)</span><span class="sh">
Fiber.yield
</span><span class="no">RUBY</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">require</span> <span class="s1">'/tmp/bar.rb'</span> <span class="p">}.</span><span class="nf">resume</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="nb">require</span> <span class="s1">'/tmp/bar.rb'</span> <span class="p">}.</span><span class="nf">resume</span>
</code></pre>
<p>If this is expected, I guess users should be told this is a possibility in the API dosc? Because from a user perspective, you don't really have elements to anticipate a deadlock there if the docs don't warn you.</p>
<p>A similar deadlock can be triggered with an <code>autoload</code> instead of a <code>require</code>:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># This produces a deadlock.</span>
<span class="no">File</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s1">'/tmp/bar.rb'</span><span class="p">,</span> <span class="o"><<~</span><span class="no">RUBY</span><span class="p">)</span><span class="sh">
Fiber.yield
Bar = 1
</span><span class="no">RUBY</span>
<span class="nb">autoload</span> <span class="ss">:Bar</span><span class="p">,</span> <span class="s1">'/tmp/bar.rb'</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Bar</span> <span class="p">}.</span><span class="nf">resume</span>
<span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="p">{</span> <span class="no">Bar</span> <span class="p">}.</span><span class="nf">resume</span>
</code></pre>
<p>A different matter is fibers managed by fiber schedulers. I have not been able to enter a deadlock with the fiber schedulers I have tried, but from the point of view of the user, doing something like I/O or sleeping at the top-level is not unlike that manual <code>Fiber.yield</code> above. The contract for fiber schedulers is mostly an interface, but it does not address this, at least in an explicit way. Do fiber schedulers guarantee anything about this with the current contract?</p>
<p>I'd be glad to volunteer docs with the conclusions of this thread.</p> Ruby master - Bug #20225 (Open): Inconsistent behavior of regex matching for a regex has a null loophttps://bugs.ruby-lang.org/issues/202252024-01-30T02:53:03Zmake_now_just (Hiroya Fujinami)make.just.on@gmail.com
<p>Usually, in Ruby (Onigmo), when a null loop (a loop consuming no characters) occurs on regex matching, this loop is terminated. But, if a loop has a capture and some complex condition is satisfied, this causes backtracking. This behavior invokes unexpected results, for example,</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">p</span> <span class="sr">/(?:.B.(?<a>(?:[C-Z]|.)*)+){2}/</span> <span class="o">=~</span> <span class="s2">"ABCABC"</span> <span class="c1"># => nil</span>
<span class="nb">p</span> <span class="sr">/(?:.B.(?:(?:[C-Z]|.)*)+){2}/</span> <span class="o">=~</span> <span class="s2">"ABCABC"</span> <span class="c1"># => 0</span>
</code></pre>
<p>Because the above regex has a capture and the below does not, different matching results are returned. It is not very intuitive that the presence of a capture changes the matching result.</p>
<p>The detailed condition for changing the null-loop behavior is 1) a previous capture in this loop holds the empty string, and 2) this capture's position is different from the current matching position. This condition is checked in <code>STACK_NULL_CHECK_MEMST</code> (<a href="https://github.com/ruby/ruby/blob/bbb7ab906ec64b963bd4b5d37e47b14796d64371/regexec.c#L1766-L1778" class="external">https://github.com/ruby/ruby/blob/bbb7ab906ec64b963bd4b5d37e47b14796d64371/regexec.c#L1766-L1778</a>).</p>
<p>Perhaps, you cannot understand what this condition means. Don't worry, I also cannot understand. This condition has been introduced for at least 20 years, and no one may remember the reason for this necessity. (If you know, please tell me!) Even if there is a reason, I believe that there is no reasonable authority for allowing counter-intuitive behavior, such as the above example.</p>
<p>This behavior can also cause memoization to be buggy. Memoization relies on the fact that backtracking only depends on positions and states (byte-code offsets of a regex). However, this condition additionally refers to captures, and the memoization is broken.</p>
<p>My proposal is to <strong>correct this inconsistent behavior</strong>. Specifically, a null loop should be determined solely on the basis of whether the matching position has changed, without referring to captures.</p>
<p>This fix changes the behavior of regex matching, but I believe that the probability that this will actually cause backward compatibility problems is remarkably low. This is because I have never seen any mention of this puzzling behavior before.</p> Ruby master - Bug #20216 (Open): Circular parameter reference not checked for assignmenthttps://bugs.ruby-lang.org/issues/202162024-01-26T18:25:53Zkddnewton (Kevin Newton)kddnewton@gmail.com
<p>I wanted to check if this was a bug or desired.</p>
<p>Usually when you reference a parameter within its own default value (optional positional or optional keyword) it raises a syntax error. This is unless you use it in an assignment, in which case it is not checked. Is this desired? Here's an example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">bar</span> <span class="o">=</span> <span class="n">bar</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="ss">bar: </span><span class="n">bar</span> <span class="o">=</span> <span class="mi">1</span><span class="p">);</span> <span class="k">end</span>
</code></pre>
<p>I'm not sure what this code is supposed to be doing. I expected it to raise a syntax error.</p> Ruby master - Feature #20215 (Open): Introduce `IO#readable?`https://bugs.ruby-lang.org/issues/202152024-01-26T05:19:16Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>There are some cases where, as an optimisation, it's useful to know whether more data is potentially available.</p>
<p>We already have <code>IO#eof?</code> but the problem with using <code>IO#eof?</code> is that it can block indefinitely for sockets.</p>
<p>Therefore, code which uses <code>IO#eof?</code> to determine if there is potentially more data, may hang.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">make_request</span><span class="p">(</span><span class="n">path</span> <span class="o">=</span> <span class="s2">"/"</span><span class="p">)</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">connect_remote_host</span>
<span class="c1"># HTTP/1.0 request:</span>
<span class="n">client</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s2">"GET </span><span class="si">#{</span><span class="n">path</span><span class="si">}</span><span class="s2"> HTTP/1.0</span><span class="se">\r\n\r\n</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># Read response</span>
<span class="n">client</span><span class="p">.</span><span class="nf">gets</span><span class="p">(</span><span class="s2">"</span><span class="se">\r\n</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># => "HTTP/1.0 200 OK\r\n"</span>
<span class="c1"># Assuming connection close, there are two things the server can do:</span>
<span class="c1"># 1. peer.close</span>
<span class="c1"># 2. peer.write(...); peer.close</span>
<span class="k">if</span> <span class="n">client</span><span class="p">.</span><span class="nf">eof?</span> <span class="c1"># <--- Can hang here!</span>
<span class="nb">puts</span> <span class="s2">"Connection closed"</span>
<span class="c1"># Avoid yielding as we know there definitely won't be any data.</span>
<span class="k">else</span>
<span class="nb">puts</span> <span class="s2">"Connection open, data may be available..."</span>
<span class="c1"># There might be data available, so yield.</span>
<span class="k">yield</span><span class="p">(</span><span class="n">client</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">ensure</span>
<span class="n">client</span><span class="o">&</span><span class="p">.</span><span class="nf">close</span>
<span class="k">end</span>
<span class="n">make_request</span> <span class="k">do</span> <span class="o">|</span><span class="n">client</span><span class="o">|</span>
<span class="nb">puts</span> <span class="n">client</span><span class="p">.</span><span class="nf">read</span> <span class="c1"># <--- Prefer to wait here.</span>
<span class="k">end</span>
</code></pre>
<p>The proposed <code>IO#readable?</code> is similar to <code>IO#eof?</code> but rather than blocking, would simply return false. The expectation is the user will subsequently call <code>read</code> which may then wait.</p>
<p>The proposed implementation would look something like this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">IO</span>
<span class="k">def</span> <span class="nf">readable?</span>
<span class="o">!</span><span class="nb">self</span><span class="p">.</span><span class="nf">closed?</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">BasicSocket</span>
<span class="c1"># Is it likely that the socket is still connected?</span>
<span class="c1"># May return false positive, but won't return false negative.</span>
<span class="k">def</span> <span class="nf">readable?</span>
<span class="k">return</span> <span class="kp">false</span> <span class="k">unless</span> <span class="k">super</span>
<span class="c1"># If we can wait for the socket to become readable, we know that the socket may still be open.</span>
<span class="n">result</span> <span class="o">=</span> <span class="nb">self</span><span class="p">.</span><span class="nf">recv_nonblock</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="no">MSG_PEEK</span><span class="p">,</span> <span class="ss">exception: </span><span class="kp">false</span><span class="p">)</span>
<span class="c1"># No data was available - newer Ruby can return nil instead of empty string:</span>
<span class="k">return</span> <span class="kp">false</span> <span class="k">if</span> <span class="n">result</span><span class="p">.</span><span class="nf">nil?</span>
<span class="c1"># Either there was some data available, or we can wait to see if there is data avaialble.</span>
<span class="k">return</span> <span class="o">!</span><span class="n">result</span><span class="p">.</span><span class="nf">empty?</span> <span class="o">||</span> <span class="n">result</span> <span class="o">==</span> <span class="ss">:wait_readable</span>
<span class="k">rescue</span> <span class="no">Errno</span><span class="o">::</span><span class="no">ECONNRESET</span>
<span class="c1"># This might be thrown by recv_nonblock.</span>
<span class="k">return</span> <span class="kp">false</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<p>For <code>IO</code> itself, when there is buffered data, <code>readable?</code> would also return true immediately, similar to <code>eof?</code>. This is not shown in the above implementation as I'm not sure if there is any Ruby method which exposes "there is buffered data".</p> Ruby master - Feature #20211 (Open): Consider re-adding 3.2-style support of Anonymous Args/Blockshttps://bugs.ruby-lang.org/issues/202112024-01-25T05:00:13Zjohnnyshields (Johnny Shields)
<p>(My sincere apologies if this issue has already been raised, I didn't see it in Ruby 3.4 backlog.)</p>
<p>As per <a href="https://bugs.ruby-lang.org/issues/19370" class="external">https://bugs.ruby-lang.org/issues/19370</a>, Ruby 3.3 no longer allows the following:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">each</span> <span class="p">{</span> <span class="o">|*|</span> <span class="nb">p</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">m</span><span class="p">(</span><span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">)</span>
<span class="c1">#=> Ruby 3.2: p(*) uses args from m(*) #=> test, test, test</span>
<span class="c1">#=> Ruby 3.3: raises SyntaxError: anonymous rest parameter is also used within block</span>
</code></pre>
<p>I am concerned because Rubocop auto-corrects Ruby 3.1+ code to syntax which is no longer supported in Ruby 3.3. There may be quite a bit of Ruby code in the wild which breaks on 3.3 (my own app broke in about 50 places).</p>
<ul>
<li><a href="https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Naming/BlockForwarding" class="external">Ruby 3.1+: Naming/BlockForwarding (default true)</a></li>
<li><a href="https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/ArgumentsForwarding" class="external">Ruby 3.2+: Style/ArgumentsForwarding with UseAnonymousForwarding (default true)</a></li>
</ul>
<p>It would be nice if the Ruby 3.4 syntax could allow the old nested syntax, supporting arg shadowing with different behavior between implicit and explicit |*| usage.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">each</span> <span class="p">{</span> <span class="nb">p</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">m</span><span class="p">(</span><span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">)</span>
<span class="c1">#=> Ruby 3.2: p(*) uses args from m(*) #=> test, test, test</span>
<span class="c1">#=> Ruby 3.4: p(*) uses args from m(*) #=> test, test, test</span>
<span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="o">*</span><span class="p">)</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">].</span><span class="nf">each</span> <span class="p">{</span> <span class="o">|*|</span> <span class="nb">p</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="p">}</span>
<span class="k">end</span>
<span class="n">m</span><span class="p">(</span><span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">,</span> <span class="s1">'test'</span><span class="p">)</span>
<span class="c1">#=> Ruby 3.2: p(*) uses args from m(*) #=> test, test, test</span>
<span class="c1">#=> Ruby 3.4: p(*) uses args from each #=> 1, 2, 3</span>
</code></pre>
<p>The same would also apply to anonymous blocks.</p> Ruby master - Bug #20203 (Open): `TestEnumerable` test failures with GCC 14https://bugs.ruby-lang.org/issues/202032024-01-22T17:10:42Zvo.x (Vit Ondruch)v.ondruch@tiscali.cz
<p>There is ongoing mass rebuild in Fedora and that is first time GCC 14 is used and we observe test failures in <code>TestEnumerable</code>. Here are a few examples:</p>
<pre><code>[ 3000/26419] TestEnumerable#test_transient_heap_sort_bymalloc_consolidate(): unaligned fastbin chunk detected
</code></pre>
<pre><code>[ 2455/26535] TestEnumerable#test_transient_heap_sort_bycorrupted size vs. prev_size in fastbins
</code></pre>
<pre><code>[ 9716/26532] TestEnumerable#test_any_with_unused_blockdouble free or corruption (fasttop)
</code></pre>
<p>The full logs are accessible <a href="https://koji.fedoraproject.org/koji/taskinfo?taskID=112176941" class="external">here</a>. Please drill through <code>Descendants</code> and <code>build.log</code></p> Ruby master - Feature #20196 (Open): Proposal: Binary data literalhttps://bugs.ruby-lang.org/issues/201962024-01-20T02:59:58Zziggythehamster (Keith Gable)
<p>I sometimes find myself needing to write some bytes in a Ruby string literal, and this experience leaves a lot to be desired:</p>
<ul>
<li>Bare strings don't work (potential for encoding corruption unless you remember to <code>.force_encoding</code> and never copy-paste just the literal into somewhere else) and are not particularly pleasant given all of the backslashes</li>
<li>Wrapping this in <code>String.new("\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00</code>\x00\x00\x00<code>\b\x06\x00\x00\x00\xE2\x98w8\x00\x000%IDAT", encoding: 'BINARY')</code> is better, but many tools explode with this because they expect all strings to be valid UTF-8 even if they're an argument to String.new, and it still doesn't have the "beauty" one might expect from Ruby (also it's not frozen unless you also freeze it)</li>
<li>
<code>["9805e474d0a0a1a0000000d094844425000000060000000680600000002e8977830000035294441445"].pack("h*")</code> parses in all tools and is less harsh to look at, but if you're writing binary data, you probably want to annotate it</li>
</ul>
<p>Here's my basic syntax proposal:</p>
<pre><code>%b[
89504e470d0a1a0a # PNG header
0000000d # Length = 13 bytes
49484452 # IHDR chunk
00000060 # Width = 96px
00000060 # Height = 96px
08 06 # 8bpp RGBA
00 00 00 # deflate / no filter / non-interlaced
]
# => "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00`\x00\x00\x00`\b\x06\x00\x00\x00"
</code></pre>
<p>More formally:</p>
<ul>
<li>To match the nibble ordering of a regular string escape, the hex characters are high nibble first (the same as the <code>H</code> unpack character).</li>
<li>It follows the same rules as other percent literals, and I am flexible on what character is used. I chose <code>b</code> because <code>h</code> could be confusing paired with the <code>h</code>/<code>H</code> unpack characters and the inverted meaning.</li>
<li>We could say that high-nibble-first is capitalized and the lower-case version is low-nibble-first, but I imagine most people will want high-nibble-first. We could also say that <code>%b[]</code> returns a <code>String</code> but <code>%B[]</code> returns an <code>IO::Buffer</code>, which has greater utility than having the capability of writing low-nibble-first literals</li>
<li>Whitespace is ignored</li>
<li>Comments are allowed</li>
<li>The encoding is always <code>Encoding::BINARY</code>
</li>
<li>The resulting string is always frozen (and if <code>%B[]</code> means buffer then that is read-only as well)</li>
<li>a-f can also be written A-F</li>
</ul>
<p>Things to consider:</p>
<ul>
<li>Interpolation could be allowed like normal strings</li>
<li>Embedding strings could be allowed (example below)</li>
<li>
<code>?</code> literals (characters) should be handled identically to how other kinds of strings are embedded if that is allowed</li>
<li>If interpolation is allowed and you interpolate a number, this should either interpolate <code>.to_s</code> as you would expect in a string or raise an error, because there is no unsurprising way to take a number and convert it to one or more bytes</li>
<li>Strings encoded as <code>Encoding::BINARY</code> could have their <code>.inspect</code> output use this literal</li>
<li>When dealing with bitmasks, it's often convenient to write them out in binary instead of hex so the on bits are easier to identify, but there is no syntax for that here that I am fond of... but someone might have an idea. I thought about <code>.00001111</code> or <code>!00001111</code> with mandatory whitespace before resuming hex characters, but those didn't feel right to me</li>
</ul>
<p>Example with embedded strings:</p>
<pre><code>%b[
89 "PNG" 0d0a1a0a # PNG header
0000000d # Length = 13 bytes
"IHDR" # IHDR chunk
00000060 # Width = 96px
00000060 # Height = 96px
08 06 # 8bpp RGBA
00 00 00 # deflate / no filter / non-interlaced
]
</code></pre>
<p>Example with interpolation:</p>
<pre><code>%b[
#{png_header}
#{ihdr = chunk(:ihdr, width: 96, height: 96, bpp: 8, format: :rgba)}
#{png_crc(ihdr)} # I didn't include this in the other examples but I needed something to demonstrate here
]
</code></pre>
<p>Other possible alternatives:</p>
<ul>
<li>A library (possibly standard library/gem) could have a function like <code>binary</code> take a string (potentially a heredoc) and parse it according to the same rules I wrote above. You would have to make the parser strip whitespace and comments, and only hex bytes could be interpolated.</li>
<li>A new pack/unpack symbol could be created that does the same thing as above, so you could <code>["hex #comments\netc"].pack("...")</code>
</li>
<li>You could probably do a lot of this with an array of hex strings and <code>pack</code> but it doesn't allow for freeform whitespace and the way you do it is not obvious without reading the docs for <code>pack</code> ... and also you allocate a bunch of strings you don't need</li>
<li>A <code>Data</code>-like object more closely related to <code>IO::Buffer</code> could be defined that declares the size of things contained within a buffer and then a constant could be written to create an instance of the Data-subclass containing the actual data you want to write out ... but this is a lot of work</li>
</ul>
<p>Potential users:</p>
<ul>
<li>People writing protocol code in Ruby</li>
<li>People who need to write out magic constants (in my case: the RDB encoding of a Redis value)</li>
<li>People using something like Metasploit Framework to reverse engineer something</li>
<li>Tools could e.g. disassemble x86 into a literal with comments showing the assembly mnemonics</li>
</ul> Ruby master - Bug #20189 (Open): `rb_str_resize` does not clear coderange when expandinghttps://bugs.ruby-lang.org/issues/201892024-01-16T12:56:47Ztompng (tomoya ishida)tomoyapenguin@gmail.com
<p>Expanding string in some encoding (utf16 utf32) can change coderange to either valid or broken, but rb_str_resize does not clear coderange.</p>
<p>This will cause a bug in c-extension libraries that use rb_str_resize.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1"># Example for stringio</span>
<span class="n">s</span> <span class="o">=</span> <span class="no">StringIO</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="s2">"</span><span class="se">\0</span><span class="s2">"</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="s1">'UTF-16LE'</span><span class="p">))</span>
<span class="n">s</span><span class="p">.</span><span class="nf">truncate</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">s</span><span class="p">.</span><span class="nf">truncate</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="n">s</span><span class="p">.</span><span class="nf">string</span><span class="p">.</span><span class="nf">valid_encoding?</span>
<span class="c1">#=> true</span>
<span class="n">s</span><span class="p">.</span><span class="nf">truncate</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span> <span class="n">s</span><span class="p">.</span><span class="nf">string</span><span class="p">.</span><span class="nf">valid_encoding?</span><span class="p">;</span> <span class="n">s</span><span class="p">.</span><span class="nf">truncate</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span> <span class="n">s</span><span class="p">.</span><span class="nf">string</span><span class="p">.</span><span class="nf">valid_encoding?</span>
<span class="c1">#=> false (expect to be true)</span>
</code></pre> Ruby master - Bug #20186 (Open): Ripper does not generate AST for some keywords in Ruby 3.3https://bugs.ruby-lang.org/issues/201862024-01-16T06:39:52Zkzkn (Kazuki Nishikawa)
<p>Ripper does not generate AST for the below keyword:</p>
<ul>
<li>break</li>
<li>next</li>
<li>redo</li>
<li>retry</li>
<li>yield</li>
</ul>
<p>Ruby 3.2</p>
<pre><code>$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
$ ruby -rripper -e "p Ripper.sexp('break')"
[:program, [[:break, []]]]
$ ruby -rripper -e "p Ripper.sexp('next')"
[:program, [[:next, []]]]
$ ruby -rripper -e "p Ripper.sexp('redo')"
[:program, [[:redo]]]
$ ruby -rripper -e "p Ripper.sexp('retry')"
[:program, [[:retry]]]
$ ruby -rripper -e "p Ripper.sexp('yield')"
[:program, [[:yield0]]]
</code></pre>
<p>Ruby 3.3</p>
<pre><code>$ ruby -v
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
$ ruby -rripper -e "p Ripper.sexp('break')"
nil
$ ruby -rripper -e "p Ripper.sexp('next')"
nil
$ ruby -rripper -e "p Ripper.sexp('redo')"
nil
$ ruby -rripper -e "p Ripper.sexp('retry')"
nil
$ ruby -rripper -e "p Ripper.sexp('yield')"
nil
</code></pre>
<p>EDIT)<br>
Here is a case of real-world problem: <a href="https://github.com/ruby-formatter/rufo/issues/319" class="external">https://github.com/ruby-formatter/rufo/issues/319</a></p> Ruby master - Bug #20168 (Open): Process won't exit when Ractor.select waiting a Ractorhttps://bugs.ruby-lang.org/issues/201682024-01-09T09:29:43Zshia (Sangyong Sim)
<a name="Reproduction-code"></a>
<h2 >Reproduction code<a href="#Reproduction-code" class="wiki-anchor">¶</a></h2>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">trap</span><span class="p">(</span><span class="ss">:INT</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">puts</span> <span class="s2">"SIGINT"</span>
<span class="nb">exit</span>
<span class="k">end</span>
<span class="nb">trap</span><span class="p">(</span><span class="ss">:TERM</span><span class="p">)</span> <span class="k">do</span>
<span class="nb">puts</span> <span class="s2">"SIGTERM"</span>
<span class="nb">exit</span>
<span class="k">end</span>
<span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="kp">loop</span> <span class="k">do</span>
<span class="nb">sleep</span> <span class="mi">1</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="no">Ractor</span><span class="p">.</span><span class="nf">select</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="c1"># stucked.</span>
<span class="c1"># SIGINT/SIGTERM sent to Ruby process(confirmed by trap),</span>
<span class="c1"># but process won't exit.</span>
</code></pre>
<a name="Expected-behavior"></a>
<h2 >Expected behavior<a href="#Expected-behavior" class="wiki-anchor">¶</a></h2>
<p>Process killed successfully with exit code 0.</p>
<a name="Affected-Ruby-version"></a>
<h2 >Affected Ruby version<a href="#Affected-Ruby-version" class="wiki-anchor">¶</a></h2>
<p>3.3.0<br>
3.2.x works as expected.</p> Ruby master - Bug #20155 (Assigned): Using value of rb_fiber_scheduler_current() crashes Rubyhttps://bugs.ruby-lang.org/issues/201552024-01-05T22:14:24Zpaddor (Patrik Wenger)paddor@gmail.com
<p>While trying to manually block/unblock fibers from an extension using the Fiber Scheduler,<br>
I noticed that using the return value of <code>rb_fiber_scheduler_current()</code> crashes Ruby.</p>
<p>I've created a minimal extension gem called "fiber_blocker". Its test suite shows the behavior. See <a href="https://github.com/paddor/fiber_blocker" class="external">https://github.com/paddor/fiber_blocker</a>, especially the lines containing <code>FIXME</code>.</p>
<p>Passing <code>Fiber.scheduler</code> to the extension functions works. But letting it get the current scheduler itself does not seem to work.</p>
<p>Is <code>rb_fiber_scheduler_current()</code>(within a non-blocking Fiber) not the equivalent to <code>Fiber.scheduler</code>?<br>
Even just printing the its return value with <code>#p</code> will crash Ruby.</p>
<p>Ruby either crashes like this:</p>
<pre><code># Running:
T1 BEGIN
T2 BEGIN
T1 END
..T1 BEGIN
ext: blocking fiber
passed scheduler = #<Scheduler:0x00007fc5f22d39e8 @readable={}, @writable={}, @waiting={}, @closed=false, @lock=#<Thread::Mutex:0x00007fc5f22ec8d0>, @blocking={}, @ready=[], @urgent=[#<IO:fd 5>, #<IO:fd 6>]>
T2 BEGIN
ext: unblocking fiber
T1 END
.E
Finished in 1.007014s, 3.9721 runs/s, 2.9791 assertions/s.
1) Error:
TestFiberBlocker#test_fiber_blocker_current_fiber:
fatal: machine stack overflow in critical region
No backtrace
</code></pre>
<p>Or with a segfault:</p>
<pre><code># Running:
FiberBlocker.test works.
.T1 BEGIN
T2 BEGIN
T1 END
.T1 BEGIN
ext: blocking fiber
/home/user/dev/oss/async_ruby_test/rbnng/fiber_blocker/test/test_fiber_blocker.rb:40: [BUG] Segmentation fault at 0x00000000390d8f98
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
-- Control frame information -----------------------------------------------
c:0003 p:---- s:0012 e:000011 CFUNC :block_fiber
c:0002 p:0014 s:0006 e:000005 BLOCK /home/user/dev/oss/async_ruby_test/rbnng/fiber_blocker/test/test_fiber_blocker.rb:40 [FINISH]
c:0001 p:---- s:0003 e:000002 DUMMY [FINISH]
-- Ruby level backtrace information ----------------------------------------
/home/user/dev/oss/async_ruby_test/rbnng/fiber_blocker/test/test_fiber_blocker.rb:40:in `block in test_fiber_blocking_in_ext'
/home/user/dev/oss/async_ruby_test/rbnng/fiber_blocker/test/test_fiber_blocker.rb:40:in `block_fiber'
-- Threading information ---------------------------------------------------
Total ractor count: 1
Ruby thread count for this ractor: 4
-- Machine register context ------------------------------------------------
RIP: 0x00007f1554f17ad8 RBP: 0x00000000390d8f90 RSP: 0x00007f153a79e280
RAX: 0x00007f1554addba8 RBX: 0x00007f153a79eab0 RCX: 0x0000000000000000
RDX: 0x00007f1554ade600 RDI: 0x00007f15551e8788 RSI: 0x0000000000000ae1
R8: 0x000000000000002b R9: 0x00007f153a79f038 R10: 0x00007f1554c0b9b0
R11: 0x00007f153a79e490 R12: 0x0000000000000ae1 R13: 0x0000000000000000
R14: 0x0000000000000000 R15: 0x000055ab732d7df0 EFL: 0x0000000000010206
-- C level backtrace information -------------------------------------------
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_print_backtrace+0x14) [0x7f1554f24961] /home/user/src/ruby-3.3.0/vm_dump.c:820
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_vm_bugreport) /home/user/src/ruby-3.3.0/vm_dump.c:1151
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_bug_for_fatal_signal+0x104) [0x7f1554d1c214] /home/user/src/ruby-3.3.0/error.c:1065
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(sigsegv+0x4f) [0x7f1554e700df] /home/user/src/ruby-3.3.0/signal.c:926
/lib/x86_64-linux-gnu/libc.so.6(0x7f1554842520) [0x7f1554842520]
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(RBASIC_CLASS+0x0) [0x7f1554f17ad8] ./include/ruby/internal/globals.h:178
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(gccct_method_search) /home/user/src/ruby-3.3.0/vm_eval.c:475
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_funcallv_scope) /home/user/src/ruby-3.3.0/vm_eval.c:1063
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_funcallv) /home/user/src/ruby-3.3.0/vm_eval.c:1084
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_inspect+0x19) [0x7f1554dc1569] /home/user/src/ruby-3.3.0/object.c:697
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(ruby__sfvextra+0x11a) [0x7f1554e7223a] /home/user/src/ruby-3.3.0/sprintf.c:1119
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(BSD_vfprintf+0xa69) [0x7f1554e73059] /home/user/src/ruby-3.3.0/vsnprintf.c:830
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(RBASIC_SET_CLASS_RAW+0x0) [0x7f1554e75b56] /home/user/src/ruby-3.3.0/sprintf.c:1168
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(ruby_vsprintf0) /home/user/src/ruby-3.3.0/sprintf.c:1169
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_enc_vsprintf+0x5d) [0x7f1554e75ecd] /home/user/src/ruby-3.3.0/sprintf.c:1195
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_sprintf+0x9d) [0x7f1554e7607d] /home/user/src/ruby-3.3.0/sprintf.c:1225
/home/user/dev/oss/async_ruby_test/rbnng/fiber_blocker/lib/fiber_blocker/fiber_blocker.so(block_fiber+0x4a) [0x7f1554ad430a] ../../../../ext/fiber_blocker/fiber_blocker.c:29
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_cfp_consistent_p+0x0) [0x7f1554ef64b4] /home/user/src/ruby-3.3.0/vm_insnhelper.c:3490
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_call_cfunc_with_frame_) /home/user/src/ruby-3.3.0/vm_insnhelper.c:3492
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_call_cfunc_with_frame) /home/user/src/ruby-3.3.0/vm_insnhelper.c:3518
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_call_cfunc_other) /home/user/src/ruby-3.3.0/vm_insnhelper.c:3544
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_sendish+0x9e) [0x7f1554f06f87] /home/user/src/ruby-3.3.0/vm_insnhelper.c:5581
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(vm_exec_core) /home/user/src/ruby-3.3.0/insns.def:834
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_vm_exec+0x19a) [0x7f1554f0d1fa] /home/user/src/ruby-3.3.0/vm.c:2486
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_vm_invoke_proc+0x5f) [0x7f1554f12e0f] /home/user/src/ruby-3.3.0/vm.c:1728
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_fiber_start+0x1ba) [0x7f1554cf098a] /home/user/src/ruby-3.3.0/cont.c:2536
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(fiber_entry+0x20) [0x7f1554cf0d00] /home/user/src/ruby-3.3.0/cont.c:847
/home/user/.rubies/ruby-3.3.0/lib/libruby.so.3.3(rb_threadptr_root_fiber_setup) (null):0
</code></pre>
<p>This happens with the Async scheduler as well as with Ruby’s test scheduler. My minimal extension uses Ruby’s.</p>
<p>I hope I'm not missing something obvious. My C isn't very good.</p> Ruby master - Feature #20152 (Open): mkmf / extconf: Add a proper way to not compile the extensionhttps://bugs.ruby-lang.org/issues/201522024-01-05T10:53:40Zbyroot (Jean Boussier)byroot@ruby-lang.org
<a name="Context"></a>
<h3 >Context<a href="#Context" class="wiki-anchor">¶</a></h3>
<p>There are various gems that ship with a native extension as a way to speedup part of the gem, but also ship with a pure Ruby version of these methods as a fallback. So they only want to compile the extension if the platform supports it, and if not, just fallback to the slightly slower Ruby version.</p>
<p>Right now users rely on one of two hacks to do this. Either they create an empty Makefile, but then still depend on <code>make</code> being available, or publish platform specific packages without any extension in them.</p>
<p>Examples:</p>
<ul>
<li><a href="https://github.com/Shopify/bootsnap/blob/070151f1305f23102365d6b4476a91c02dead35a/ext/bootsnap/extconf.rb" class="external"><code>bootsnap</code> skip compilation if not on MRI or TruffleRuby</a></li>
<li><a href="https://github.com/ruby/erb/issues/52" class="external"><code>erb</code> has an extension for MRI but then need to publish a <code>java</code> version of the gem that doesn't actually contain Java code, just to skip compilation on JRuby</a></li>
<li><a href="https://github.com/redis-rb/redis-client/blob/1ab081c1d0e47df5d55e011c9390c70b2eef6731/hiredis-client/ext/redis_client/hiredis/extconf.rb#L10-L17" class="external"><code>hiredis-client</code> skips the compilation for Windows and non-MRI rubies</a></li>
</ul>
<a name="Feature"></a>
<h3 >Feature<a href="#Feature" class="wiki-anchor">¶</a></h3>
<p>It would be very useful to have some proper first class API to skip compiling the extension.</p>
<p>Something like:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"mkmf"</span>
<span class="k">if</span> <span class="no">RUBY_ENGINE</span> <span class="o">!=</span> <span class="s2">"ruby"</span> <span class="o">||</span> <span class="no">RUBY_PLATFORM</span><span class="p">.</span><span class="nf">match?</span><span class="p">(</span><span class="sr">/mswin/</span><span class="p">)</span>
<span class="n">skip_compilation</span>
<span class="k">else</span>
<span class="c1"># ...</span>
<span class="k">end</span>
</code></pre>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/10073">@k0kubun (Takashi Kokubun)</a> <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/286">@headius (Charles Nutter)</a></p> Ruby master - Bug #20151 (Open): Can't build Ruby 3.1 on FreeBSD 14.0https://bugs.ruby-lang.org/issues/201512024-01-05T03:14:58Zhsbt (Hiroshi SHIBATA)hsbt@ruby-lang.org
<p>I couldn't install Ruby 3.1.3 on FreeBSD 14.0.</p>
<pre><code>compiling util.c
util.c:255:1: error: expected identifier or '('
ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void *d)
^
./include/ruby/util.h:124:21: note: expanded from macro 'ruby_qsort'
# define ruby_qsort qsort_r
^
/usr/include/stdlib.h:356:5: note: expanded from macro 'qsort_r'
__generic(arg5, int (*)(void *, const void *, const void *), \
^
/usr/include/sys/cdefs.h:322:2: note: expanded from macro '__generic'
_Generic(expr, t: yes, default: no)
^
1 error generated.
*** Error code 1
Stop.
</code></pre>
<p>Compiler version is here:</p>
<pre><code>FreeBSD clang version 16.0.6 (https://github.com/llvm/llvm-project.git llvmorg-16.0.6-0-g7cbf1a259152)
</code></pre>
<p>I could install Ruby 3.2.2.</p> Ruby master - Bug #20147 (Open): FreeBSD libyamlhttps://bugs.ruby-lang.org/issues/201472024-01-04T13:09:45Zkaiquekandykoga (Kaíque Koga)
<p>I use ruby-install to manage multiple Ruby versions. Some time ago I had issues installing Ruby 3.2.2 <a href="https://github.com/postmodern/ruby-install/issues/463" class="external">https://github.com/postmodern/ruby-install/issues/463</a>, and the same issue was open for ruby-build in <a href="https://github.com/rbenv/ruby-build/issues/2184" class="external">https://github.com/rbenv/ruby-build/issues/2184</a>. I am trying to install Ruby 3.3.0 using ruby-install, and the same behaviour is occurring. Please, take a look in the links I have provided for detailed information.</p>
<pre><code class="shell syntaxhl" data-language="shell">/usr/home/kandy/src/ruby-3.3.0/lib/yaml.rb:3: warning: It seems your ruby installation is missing psych <span class="o">(</span><span class="k">for </span>YAML output<span class="o">)</span><span class="nb">.</span>
To eliminate this warning, please <span class="nb">install </span>libyaml and reinstall your ruby.
uh-oh! RDoc had a problem:
cannot load such file <span class="nt">--</span> psych
run with <span class="nt">--debug</span> <span class="k">for </span>full backtrace
<span class="k">***</span> Error code 1
Stop.
make: stopped <span class="k">in</span> /usr/home/kandy/src/ruby-3.3.0
<span class="o">!!!</span> Compiling ruby 3.3.0 failed!
</code></pre>
<p>Thank you.</p> Ruby master - Feature #20102 (Open): Introduce `Fiber#resuming?`https://bugs.ruby-lang.org/issues/201022023-12-28T07:25:59Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>There are some tricky edge cases when using <code>Fibre#raise</code> and <code>Fiber#kill</code>, e.g.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">fiber</span> <span class="o">=</span> <span class="kp">nil</span>
<span class="n">killer</span> <span class="o">=</span> <span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">fiber</span><span class="p">.</span><span class="nf">raise</span><span class="p">(</span><span class="s2">"Stop"</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">fiber</span> <span class="o">=</span> <span class="no">Fiber</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">killer</span><span class="p">.</span><span class="nf">resume</span>
<span class="k">end</span>
<span class="n">fiber</span><span class="p">.</span><span class="nf">resume</span>
<span class="c1"># 4:in `raise': attempt to raise a resuming fiber (FiberError)</span>
<span class="c1"># 4:in `block in <main>'</span>
</code></pre>
<p>Async has to deal with this edge case explicitly by rescuing the exception:</p>
<p><a href="https://github.com/socketry/async/blob/ffd019d9c1d547926a28fe8f36bf7bfe91d8a168/lib/async/task.rb#L226-L233" class="external">https://github.com/socketry/async/blob/ffd019d9c1d547926a28fe8f36bf7bfe91d8a168/lib/async/task.rb#L226-L233</a></p>
<p>I'd like to avoid doing that and instead just ask "Can I kill/raise on this fiber right now?" which is determined by whether the fiber itself can be resumed or transferred to.</p>
<p>To address this, I'd like to introduce <code>Fiber#resuming?</code>:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cm">/*
* call-seq: fiber.resumed? -> true or false
*
* Whether the fiber is currently resumed.
*/</span>
<span class="n">VALUE</span>
<span class="nf">rb_fiber_resuming_p</span><span class="p">(</span><span class="n">VALUE</span> <span class="n">fiber_value</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">struct</span> <span class="n">rb_fiber_struct</span> <span class="o">*</span><span class="n">fiber</span> <span class="o">=</span> <span class="n">fiber_ptr</span><span class="p">(</span><span class="n">fiber_value</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">FIBER_TERMINATED_P</span><span class="p">(</span><span class="n">fiber</span><span class="p">))</span> <span class="k">return</span> <span class="n">RUBY_Qfalse</span><span class="p">;</span>
<span class="k">return</span> <span class="n">RBOOL</span><span class="p">(</span><span class="n">fiber</span><span class="o">-></span><span class="n">resuming_fiber</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>See the PR: <a href="https://github.com/ruby/ruby/pull/9382" class="external">https://github.com/ruby/ruby/pull/9382</a></p> Ruby master - Bug #20043 (Open): `defined?` checks for method existence but only sometimeshttps://bugs.ruby-lang.org/issues/200432023-12-05T22:17:59Ztenderlovemaking (Aaron Patterson)tenderlove@ruby-lang.org
<p>When an expression is passed to <code>defined?</code>, it will <em>sometimes</em> check if a method in a sub-expression is defined and sometimes it won't.</p>
<p>For example:</p>
<pre><code>$ ./miniruby -e'p defined?(a)'
nil
$ ./miniruby -e'p defined?([a])'
nil
</code></pre>
<p>In the above case, Ruby will check whether or not the method <code>a</code> is defined, and it returns <code>nil</code>. However, if you use a splat, it will not check:</p>
<pre><code>$ ./miniruby -e'p defined?([*a])'
"expression"
</code></pre>
<p>The same thing seems to happen with method parameters:</p>
<pre><code>$ ./miniruby -e'p defined?(itself)'
"method"
$ ./miniruby -e'p defined?(itself(a))'
nil
$ ./miniruby -e'p defined?(itself(*a))'
"method"
</code></pre>
<p>Oddly, <code>defined?</code> will check contents of arrays, but <em>won't</em> check contents of hashes:</p>
<pre><code>$ ./miniruby -e'p defined?([[[[a]]]])'
nil
$ ./miniruby -e'p defined?({ a => a })'
"expression"
</code></pre>
<p>I think all of the cases that refer to <code>a</code> should check whether or not <code>a</code> is defined regardless of splats or hashes.</p> Ruby master - Misc #20013 (Open): Travis CI statushttps://bugs.ruby-lang.org/issues/200132023-11-21T14:10:56Zjaruga (Jun Aruga)
<p>I would like to use this ticket to manage our activities to report Travis CI status.</p>
<p>Because there is Travis CI status page provided by Travis CI. However, even when the page shows ok, I actually see infra issues.<br>
<a href="https://www.traviscistatus.com/" class="external">https://www.traviscistatus.com/</a></p>
<p>I would share my activities and report the Travis CI status on the ticket.<br>
The ticket's status is not closed until we stop using Travis CI.</p>
<p>The easiest option to fix the Travis infra issue is to email Travis CI support <code>support _AT_ travis-ci.com</code>.</p>
<p>You can check <a href="https://github.com/ruby/ruby/wiki/CI-Servers#travis-ci" class="external">this ruby/ruby Travis CI wiki page</a> for details.</p> Ruby master - Feature #19979 (Open): Allow methods to declare that they don't accept a block via ...https://bugs.ruby-lang.org/issues/199792023-10-29T12:09:14Zufuk (Ufuk Kayserilioglu)
<a name="Abstract"></a>
<h2 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h2>
<p>This feature proposes new syntax to allow methods to explicitly declare that they don't accept blocks, and makes passing of a block to such methods an error.</p>
<a name="Background"></a>
<h2 >Background<a href="#Background" class="wiki-anchor">¶</a></h2>
<p>In <a class="issue tracker-2 status-1 priority-4 priority-default" title="Feature: warn/error passing a block to a method which never use a block (Open)" href="https://bugs.ruby-lang.org/issues/15554">#15554</a>, it was proposed to automatically detect methods that do not use the block passed to them, and to error if a block was passed to such methods. As far as I can tell, it was later on closed since <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Eliminate implicit magic in Proc.new and Kernel#proc (Closed)" href="https://bugs.ruby-lang.org/issues/10499">#10499</a> solved a large part of the problem.</p>
<p>That proposal has, as part of <a href="https://github.com/ruby/dev-meeting-log/blob/b4357853c03dfe71b6eab320d5642d463854f50f/2019/DevMeeting-2019-01-10.md?plain=1#L110-L120" class="external">a dev meeting discussion</a>, a proposal from <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/13">@matz (Yukihiro Matsumoto)</a> to allow methods to use <code>&nil</code> to explicitly declare that they don't accept a block. At the time, the proposal was trying to solve a bigger problem, so this sub-proposal was never considered seriously. However, notes in the proposal say:</p>
<blockquote>
<p>It is explicit, but it is tough to add this <code>&nil</code> parameter declaration to all of methods (do you want to add it to <code>def []=(i, e, &nil)</code>?). (I agree <code>&nil</code> is valuable on some situations)</p>
</blockquote>
<p>This proposal extracts that sub-proposal to make this a new language feature.</p>
<a name="Proposal"></a>
<h2 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h2>
<p>In Ruby, it is always valid for the caller to pass a block to a method call, even if the callee is not expecting a block to be passed. This leads to subtle user errors, where the author of some code assumes a method call uses a block, but the block passed to the method call is silently ignored.</p>
<p>The proposal is to introduce <code>&nil</code> at method declaration sites to mean "This method does not accept a block". This is symmetric to the ability to pass <code>&nil</code> at call sites to mean "I am not passing a block to this method call", which is sometimes useful when making <code>super</code> calls (since blocks are always implicitly passed).</p>
<p>Explicitly, the proposal is to make the following behaviour be a part of Ruby:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">find</span><span class="p">(</span><span class="n">item</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">,</span> <span class="o">&</span><span class="kp">nil</span><span class="p">)</span>
<span class="c1"># some implementation that doesn't call `yield` or `block_given?`</span>
<span class="k">end</span>
<span class="n">find</span> <span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="n">i</span> <span class="o">==</span> <span class="mi">42</span> <span class="p">}</span>
<span class="c1"># => ArgumentError: passing block to the method `find' that does not accept a block.</span>
</code></pre>
<a name="Implementation"></a>
<h2 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h2>
<p>I assume the implementation would be a grammar change to make <code>&nil</code> valid at method declaration sites, as well as raising an <code>ArgumentError</code> for methods that are called with a block but are declared with <code>&nil</code>.</p>
<a name="Evaluation"></a>
<h2 >Evaluation<a href="#Evaluation" class="wiki-anchor">¶</a></h2>
<p>Since I don't have an implementation, I can't make a proper evaluation of the feature proposal. However, I would expect the language changes to be minimal with no runtime costs for methods that don't use the <code>&nil</code> syntax.</p>
<a name="Discussion"></a>
<h2 >Discussion<a href="#Discussion" class="wiki-anchor">¶</a></h2>
<p>This proposal has much smaller scope than <a class="issue tracker-2 status-1 priority-4 priority-default" title="Feature: warn/error passing a block to a method which never use a block (Open)" href="https://bugs.ruby-lang.org/issues/15554">#15554</a> so that the Ruby language can start giving library authors the ability to explicitly mark their methods as not accepting a block. This is fully backward compatible, since it is an opt-in behaviour and not an opt-out one.</p>
<p>Future directions after this feature proposal could be a way to signal to the VM that any method in a file that doesn't explicitly use <code>yield</code>/<code>block_given?</code> or explicitly declared a block parameter should be treated as not accepting a block. This can be done via some kind of pragma similar to <code>frozen_string_literal</code>, or through other means. However, such future directions are beyond the scope of this proposal.</p>
<a name="Summary"></a>
<h2 >Summary<a href="#Summary" class="wiki-anchor">¶</a></h2>
<p>Adding the ability for methods to declare that they don't accept a block will make writing code against such methods safer and more resilient, and will prevent silently ignored behaviour that is often hard to catch or troubleshoot.</p> Ruby master - Bug #19970 (Open): Eval leaks callcache and callinfo objects on arm32 (linux)https://bugs.ruby-lang.org/issues/199702023-10-24T12:56:58Zlarsin (Lars Ingjer)
<p>The following script demonstrates a memory leak on arm 32 (linux):</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">gcdiff</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="no">GC</span><span class="p">.</span><span class="nf">start</span>
<span class="k">if</span> <span class="vi">@last_gc_stat</span>
<span class="nb">puts</span> <span class="s2">"GC.stat </span><span class="si">#{</span><span class="n">n</span><span class="si">}</span><span class="s2"> diff old_objects: </span><span class="si">#{</span><span class="no">GC</span><span class="p">.</span><span class="nf">stat</span><span class="p">(</span><span class="ss">:old_objects</span><span class="p">)</span> <span class="o">-</span> <span class="vi">@last_gc_stat</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="vi">@last_gc_stat</span> <span class="o">=</span> <span class="no">GC</span><span class="p">.</span><span class="nf">stat</span><span class="p">(</span><span class="ss">:old_objects</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">foo</span>
<span class="k">end</span>
<span class="mi">10</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span>
<span class="mi">10_000</span><span class="p">.</span><span class="nf">times</span> <span class="k">do</span>
<span class="nb">eval</span> <span class="s1">'foo'</span>
<span class="k">end</span>
<span class="n">gcdiff</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Number of live objects: </span><span class="si">#{</span><span class="no">GC</span><span class="p">.</span><span class="nf">stat</span><span class="p">(</span><span class="ss">:heap_live_slots</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span> <span class="s2">"Memory usage: </span><span class="si">#{</span><span class="sb">`ps -o rss= -p </span><span class="si">#{</span><span class="vg">$$</span><span class="si">}</span><span class="sb">`</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">puts</span>
<span class="k">end</span>
</code></pre>
<p>Output:</p>
<pre><code>Number of live objects: 41303
Memory usage: 11900
GC.stat 1 diff old_objects: 20037
Number of live objects: 61317
Memory usage: 13604
GC.stat 2 diff old_objects: 20001
Number of live objects: 81317
Memory usage: 14880
GC.stat 3 diff old_objects: 20000
Number of live objects: 101317
Memory usage: 16596
GC.stat 4 diff old_objects: 20000
Number of live objects: 121317
Memory usage: 17248
GC.stat 5 diff old_objects: 20000
Number of live objects: 141317
Memory usage: 18760
GC.stat 6 diff old_objects: 20000
Number of live objects: 161317
Memory usage: 19540
GC.stat 7 diff old_objects: 20000
Number of live objects: 181317
Memory usage: 21752
GC.stat 8 diff old_objects: 20000
Number of live objects: 201317
Memory usage: 21828
GC.stat 9 diff old_objects: 20000
Number of live objects: 221317
Memory usage: 24896
</code></pre>
<p>ObjectSpace.count_imemo_objects shows that imemo_callcache and imemo_callinfo are leaking.</p>
<p>The issue does not occur on arm64 mac or x86_64 linux with the same ruby version.<br>
The issue has also been reproduced with the latest 3.2.2 snapshot (2023-09-30).</p> Ruby master - Feature #19905 (Open): Introduce `Queue#peek`https://bugs.ruby-lang.org/issues/199052023-09-28T23:10:34Zhi@joaofernandes.me (Joao Fernandes)
<p>This ticket proposes the introduction of the <code>Queue#peek</code> method, similar to what we can find in other object oriented languages such as Java and C#. This method is similar to <code>Queue#pop</code>, but does not change the data, nor does it require a lock.</p>
<pre><code>q = Queue.new([1,2,3])
=> #<Thread::Queue:0x00000001065d7148>
q.peek
=> 1
q.peek
=> 1
</code></pre>
<p>I have felt the need of this for debugging, but I think that it can also be of practical use for presentation. I believe that the only drawback could be that newcomers could misuse it in multi-threaded work without taking into account that this method is not thread safe.</p>
<p>I also volunteer myself to implement this method.</p> Ruby master - Feature #19787 (Open): Add Enumerable#uniq_map, Enumerable::Lazy#uniq_map, Array#un...https://bugs.ruby-lang.org/issues/197872023-07-29T14:13:00Zjoshuay03 (Joshua Young)
<p>I would like to propose a collection of new methods, <code>Enumerable#uniq_map</code>, <code>Enumerable::Lazy#uniq_map</code>, <code>Array#uniq_map</code> and <code>Array#uniq_map!</code>.</p>
<p>TL;DR: It's a drop in replacement for <code>.map { ... }.uniq</code>, with (hopefully) better performance.</p>
<p>I've quite often had to map over an array and get its unique elements. It occurred to me when doing so recently that Ruby doesn't have a short form method for doing that, similar to how <code>.flat_map { ... }</code> replaces <code>.map { ... }.flatten</code> and <code>.filter_map { ... }</code> replaces <code>.map { ... }.compact</code> (with minor differences). I think these new methods could be beneficial both in terms of better performance and writing more succinct code.</p>
<p>I've got a draft PR up with some initial benchmarks in the description: <a href="https://github.com/ruby/ruby/pull/10269" class="external">https://github.com/ruby/ruby/pull/10269</a>.</p> Ruby master - Misc #19758 (Open): Statically link ext/jsonhttps://bugs.ruby-lang.org/issues/197582023-07-05T13:24:24ZMyCo (Maik Menz)
<p>Hi,</p>
<p>I'm building Ruby both as dynamic and static library with MSVC for a project. Everything appears to work fine, but now I'm trying to use the json ext, and it only works with the dynamically linked version.<br>
In the statically linked version it says it's missing json/pure but on closer inspection the reason it says that is because it can't find json/ext/parser (and probably also json/ext/generator) in the first place.</p>
<p>I can see that both parser & generator created static libs in the build directory but they aren't linked into the ruby lib.<br>
With my limited knowledge of the building processes, my first attempt was to add both of those libs into <code>LOCAL_LIBS</code> and now they apear in the linking process.<br>
But this still doesn't change anything. It's still not finding those 2 libs in the statically linked Ruby build.</p>
<p>What am I missing? What do I have to do, to get those linked into the static lib?</p>
<p>Regards<br>
Maik</p> Ruby master - Feature #19742 (Open): Introduce `Module#anonymous?`https://bugs.ruby-lang.org/issues/197422023-06-21T10:47:33Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>As a follow-on <from <a href="https://bugs.ruby-lang.org/issues/19521%3E" class="external">https://bugs.ruby-lang.org/issues/19521></a>, I'd like propose we introduce <code>Module#anonymous?</code>.</p>
<p>In some situations, like logging/formatting, serialisation/deserialization, debugging or meta-programming, we might like to know if a class is a proper constant or not.</p>
<p>However, this brings about some other issues which might need to be discussed.</p>
<p>After assigning a constant, then removing it, the internal state of Ruby still believes that the class name is permanent, even thought it's no longer true.</p>
<p>e.g.</p>
<pre><code>m = Module.new
m.anonymous? # true
M = m
m.anonyomous # false
Object.send(:remove_const, :M)
M # uninitialized constant M (NameError)
m.anonymous? # false
</code></pre>
<p>Because RCLASS data structure is not updated after the constant is removed, internally the state still has a "permanent class name".</p>
<p>I want to use this proposal to discuss this issue and whether there is anything we should do about such behaviour (or even if it's desirable).</p>
<p>Proposed PR: <a href="https://github.com/ruby/ruby/pull/7966" class="external">https://github.com/ruby/ruby/pull/7966</a></p>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/1241">@fxn (Xavier Noria)</a></p> Ruby master - Feature #19422 (Assigned): Make `--enabled-shared` mandatory on macOShttps://bugs.ruby-lang.org/issues/194222023-02-07T08:14:26Znobu (Nobuyoshi Nakada)nobu@ruby-lang.org
<p>From the troubles around linker on macOS, I propose <code>--enable-shared</code> option mandatory on macOS.<br>
This patch enables the option by default, and abort if <code>--disable-shared</code> option is given explicitly.</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">diff --git i/configure.ac w/configure.ac
index 7db2ab5257c..923ac7d1199 100644
</span><span class="gd">--- i/configure.ac
</span><span class="gi">+++ w/configure.ac
</span><span class="p">@@ -504,6 +504,11 @@</span> AS_CASE(["$target_os"],
rb_cv_binary_elf=no
: ${enable_shared=yes}
],
<span class="gi">+[darwin*], [
+ AS_IF([test "${enable_shared=yes}" = no], [
+ AC_MSG_ERROR([--disable-shared is not supported on this platform])
+ ])
+],
</span> [hiuxmpp*], [AC_DEFINE(__HIUX_MPP__)]) # by TOYODA Eizi <toyoda@npd.kishou.go.jp>
AC_PROG_LN_S
<span class="p">@@ -3055,14 +3060,7 @@</span> AC_SUBST(EXTOBJS)
: ${LDFLAGS=""}
: ${LIBPATHENV=DYLD_FALLBACK_LIBRARY_PATH}
: ${PRELOADENV=DYLD_INSERT_LIBRARIES}
<span class="gd">- AS_IF([test x"$enable_shared" = xyes], [
- # Resolve symbols from libruby.dylib when --enable-shared
- EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
- ], [test "x$EXTSTATIC" = x], [
- # When building exts as bundles, a mach-o bundle needs to know its loader
- # program to bind symbols from the ruby executable
- EXTDLDFLAGS="-bundle_loader '\$(BUILTRUBY)'"
- ])
</span><span class="gi">+ EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
</span> rb_cv_dlopen=yes],
[aix*], [ : ${LDSHARED='$(CC)'}
AS_IF([test "$GCC" = yes], [
<span class="p">@@ -3356,10 +3354,6 @@</span> AS_IF([test x"$cross_compiling" = xyes], [
AC_SUBST(XRUBY_RUBYLIBDIR)
AC_SUBST(XRUBY_RUBYHDRDIR)
PREP='$(arch)-fake.rb'
<span class="gd">- AS_CASE(["$enable_shared:$EXTSTATIC:$target_os"], [no::darwin*], [
- # darwin target requires miniruby for linking ext bundles
- PREP="$PREP"' miniruby$(EXEEXT)'
- ])
</span> RUNRUBY_COMMAND='$(MINIRUBY) -I`cd $(srcdir)/lib; pwd`'
RUNRUBY='$(RUNRUBY_COMMAND)'
XRUBY='$(MINIRUBY)'
</code></pre> Ruby master - Bug #19408 (Assigned): Object no longer frozen after moved from a ractorhttps://bugs.ruby-lang.org/issues/194082023-02-03T18:55:10Zluke-gru (Luke Gruber)luke.gru@gmail.com
<p>I think frozen objects should still be frozen after a move.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">receive</span>
<span class="nb">p</span> <span class="n">obj</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># should be true but is false</span>
<span class="nb">p</span> <span class="n">obj</span>
<span class="k">end</span>
<span class="n">obj</span> <span class="o">=</span> <span class="p">[</span><span class="no">Object</span><span class="p">.</span><span class="nf">new</span><span class="p">].</span><span class="nf">freeze</span>
<span class="n">r</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="ss">move: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">r</span><span class="p">.</span><span class="nf">take</span>
</code></pre> Ruby master - Feature #19236 (Open): Allow to create hashes with a specific capacity from Rubyhttps://bugs.ruby-lang.org/issues/192362022-12-15T09:02:19Zbyroot (Jean Boussier)byroot@ruby-lang.org
<p>Followup on [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Allow to create hashes with a specific capacity. (Closed)" href="https://bugs.ruby-lang.org/issues/18683">#18683</a>] which added a C-API for this purpose.</p>
<p>Various protocol parsers such as Redis <code>RESP3</code> or <code>msgpack</code>, have to create hashes, and they know the size in advance.<br>
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.</p>
<p><code>String</code> and <code>Array</code> both already offer similar APIs:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="no">String</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="ss">capacity: </span><span class="no">XXX</span><span class="p">)</span>
<span class="no">Array</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">XX</span><span class="p">)</span> <span class="o">/</span> <span class="n">rb_ary_new_capa</span><span class="p">(</span><span class="n">long</span><span class="p">)</span>
</code></pre>
<p>However there's no such public API for Hashes in Ruby land.</p>
<a name="Proposal"></a>
<h3 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h3>
<p>I think <code>Hash</code> should have a way to create a new hash with a <code>capacity</code> parameter.</p>
<p>The logical signature of <code>Hash.new(capacity: 1000)</code> was deemed too incompatible in [Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Allow to create hashes with a specific capacity. (Closed)" href="https://bugs.ruby-lang.org/issues/18683">#18683</a>].</p>
<p><a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> proposed to add <code>Hash.create(capacity: 1000)</code>.</p> Ruby master - Bug #19231 (Open): Integer#step and Float::INFINITY - inconsistent behaviour when c...https://bugs.ruby-lang.org/issues/192312022-12-13T15:17:41Zandrykonchin (Andrew Konchin)
<p>The initial issue was reported here <a href="https://github.com/oracle/truffleruby/issues/2797" class="external">https://github.com/oracle/truffleruby/issues/2797</a>.</p>
<p><code>0.step(Float::INFINITY, 10)</code> returns:</p>
<ul>
<li>
<code>Integers</code> when called with a block</li>
<li>
<code>Floats</code> when called without a block</li>
</ul>
<p>I would expect <code>Floats</code> to be returned in both cases.</p>
<p>Examples:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">0</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="no">Float</span><span class="o">::</span><span class="no">INFINITY</span><span class="p">,</span> <span class="mi">10</span><span class="p">).</span><span class="nf">take</span><span class="p">(</span><span class="mi">1</span><span class="p">).</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:class</span><span class="p">)</span>
<span class="o">=></span> <span class="p">[</span><span class="no">Float</span><span class="p">]</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">0</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="no">Float</span><span class="o">::</span><span class="no">INFINITY</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">offset</span><span class="o">|</span> <span class="nb">p</span> <span class="n">offset</span><span class="p">.</span><span class="nf">class</span><span class="p">;</span> <span class="k">break</span> <span class="p">}</span>
<span class="c1"># Integer</span>
</code></pre>
<p>When <code>to</code> argument is a finite <code>Float</code> value then calling with a block returns <code>Floats</code> as well:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="mi">0</span><span class="p">.</span><span class="nf">step</span><span class="p">(</span><span class="mf">100.0</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">offset</span><span class="o">|</span> <span class="nb">p</span> <span class="n">offset</span><span class="p">.</span><span class="nf">class</span><span class="p">;</span> <span class="k">break</span> <span class="p">}</span>
<span class="c1"># Float</span>
</code></pre>
<p>Wondering whether it's intentional behaviour.</p>
<p>I've found a related issue <a href="https://bugs.ruby-lang.org/issues/15518" class="external">https://bugs.ruby-lang.org/issues/15518</a>.</p> Ruby master - Feature #19057 (Assigned): Hide implementation of `rb_io_t`.https://bugs.ruby-lang.org/issues/190572022-10-15T01:54:57Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>In order to make improvements to the IO implementation like <a href="https://bugs.ruby-lang.org/issues/18455" class="external">https://bugs.ruby-lang.org/issues/18455</a>, we need to add new fields to <code>struct rb_io_t</code>.</p>
<p>By the way, ending types in <code>_t</code> is not recommended by POSIX, so I'm also trying to rename the internal implementation to drop <code>_t</code> where possible during this conversion.</p>
<p>Anyway, we should try to hide the implementation of <code>struct rb_io</code>. Ideally, we don't expose any of it, but the problem is backwards compatibility.</p>
<p>So, in order to remain backwards compatibility, we should expose some fields of <code>struct rb_io</code>, the most commonly used one is <code>fd</code> and <code>mode</code>, but several others are commonly used.</p>
<p>There are many fields which should not be exposed because they are implementation details.</p>
<a name="Current-proposal"></a>
<h2 >Current proposal<a href="#Current-proposal" class="wiki-anchor">¶</a></h2>
<p>The current proposed change <a href="https://github.com/ruby/ruby/pull/6511" class="external">https://github.com/ruby/ruby/pull/6511</a> creates two structs:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="cp">#ifndef RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="p">};</span>
<span class="cp">#else
</span><span class="k">struct</span> <span class="n">rb_io</span><span class="p">;</span>
<span class="cp">#endif
</span>
<span class="c1">// internal/io.h</span>
<span class="cp">#define RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="c1">// ... private fields ...</span>
<span class="p">};</span>
</code></pre>
<p>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 <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/772">@Eregon (Benoit Daloze)</a> + <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/73">@tenderlovemaking (Aaron Patterson)</a> have both given some kind of approval.</p>
<p>That being said, maybe it's not safe.</p>
<p>There are two alternatives:</p>
<a name="Hide-all-details"></a>
<h2 >Hide all details<a href="#Hide-all-details" class="wiki-anchor">¶</a></h2>
<p>We can make public <code>struct rb_io</code> completely invisible.</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="cp">#define RB_IO_HIDDEN
</span><span class="k">struct</span> <span class="n">rb_io</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">rb_ioptr_descriptor</span><span class="p">(</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="o">*</span><span class="n">ioptr</span><span class="p">);</span> <span class="c1">// accessor for previously visible state.</span>
<span class="c1">// internal/io.h</span>
<span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="c1">// ... all fields ...</span>
<span class="p">};</span>
</code></pre>
<p>This would only be forwards compatible, and code would need to feature detect like this:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="cp">#ifdef RB_IO_HIDDEN
#define RB_IOPTR_DESCRIPTOR rb_ioptr_descriptor
#else
#define RB_IOPTR_DESCRIPTOR(ioptr) rb_ioptr_descriptor(ioptr)
#endif
</span></code></pre>
<a name="Nested-public-interface"></a>
<h2 >Nested public interface<a href="#Nested-public-interface" class="wiki-anchor">¶</a></h2>
<p>Alternatively, we can nest the public fields into the private struct:</p>
<pre><code class="c syntaxhl" data-language="c"><span class="c1">// include/ruby/io.h</span>
<span class="k">struct</span> <span class="n">rb_io_public</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">fd</span><span class="p">;</span>
<span class="c1">// ... public fields ...</span>
<span class="p">};</span>
<span class="c1">// internal/io.h</span>
<span class="cp">#define RB_IO_T
</span><span class="k">struct</span> <span class="n">rb_io</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">rb_io_public</span> <span class="n">public</span><span class="p">;</span>
<span class="c1">// ... private fields ...</span>
<span class="p">};</span>
</code></pre>
<a name="Considerations"></a>
<h2 >Considerations<a href="#Considerations" class="wiki-anchor">¶</a></h2>
<p>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.</p>
<p>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.</p> Ruby master - Feature #18576 (Open): Rename `ASCII-8BIT` encoding to `BINARY`https://bugs.ruby-lang.org/issues/185762022-02-08T09:08:05Zbyroot (Jean Boussier)byroot@ruby-lang.org
<a name="Context"></a>
<h3 >Context<a href="#Context" class="wiki-anchor">¶</a></h3>
<p>I'm now used to it, but something that confused me for years was errors such as:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="o">>></span> <span class="s2">"fée"</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\xFF</span><span class="s2">"</span><span class="p">.</span><span class="nf">b</span>
<span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">3</span><span class="ss">:in</span> <span class="sb">`+': incompatible character encodings: UTF-8 and ASCII-8BIT (Encoding::CompatibilityError)
</span></code></pre>
<p>When you aren't that familiar with Ruby, it's really not evident that <code>ASCII-8BIT</code> basically means "no encoding" or "binary".</p>
<p>And even when you know it, if you don't read carefully it's very easily confused with <code>US-ASCII</code>.</p>
<p>The <code>Encoding::BINARY</code> alias is much more telling IMHO.</p>
<a name="Proposal"></a>
<h3 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h3>
<p>Since <code>Encoding::ASCII_8BIT</code> has been aliased as <code>Encoding::BINARY</code> for years, I think renaming it to <code>BINARY</code> and then making asking <code>ASCII_8BIT</code> the alias would significantly improve usability without backward compatibility concerns.</p>
<p>The only concern I could see would be the consistency with a handful of C API functions:</p>
<ul>
<li><code>rb_encoding *rb_ascii8bit_encoding(void)</code></li>
<li><code>int rb_ascii8bit_encindex(void)</code></li>
<li><code>VALUE rb_io_ascii8bit_binmode(VALUE io)</code></li>
</ul>
<p>But that's for much more advanced users, so I don't think it's much of a concern.</p> Ruby master - Bug #18455 (Open): `IO#close` has poor performance and difficult to understand sema...https://bugs.ruby-lang.org/issues/184552022-01-01T07:13:08Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p><code>IO#close</code> should be responsible for closing the file descriptor referred to by the IO instance. When dealing with buffered IO, one can also expect this to flush the internal buffers if possible.</p>
<p>Currently, all blocking IO operations release the GVL and perform the blocking system call using <code>rb_thread_io_blocking_region</code>. The current implementation takes a file descriptor and adds an entry to the VM global <code>waiting_fds</code> list. When the operation is completed, the entry is removed from <code>waiting_fds</code>.</p>
<p>When calling <code>IO#close</code>, this list is traversed and any threads performing blocking operations with a matching file descriptor are interrupted. The performance of this is O(number of blocking IO operations) which in practice the performance of <code>IO#close</code> can take milliseconds with 10,000 threads performing blocking IO. This performance is unacceptable.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#!/usr/bin/env ruby</span>
<span class="nb">require</span> <span class="s1">'benchmark'</span>
<span class="k">class</span> <span class="nc">Reading</span>
<span class="k">def</span> <span class="nf">initialize</span>
<span class="vi">@r</span><span class="p">,</span> <span class="vi">@w</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">pipe</span>
<span class="vi">@thread</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="vi">@r</span><span class="p">.</span><span class="nf">read</span>
<span class="k">rescue</span> <span class="no">IOError</span>
<span class="c1"># Ignore.</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="kp">attr</span> <span class="ss">:r</span>
<span class="kp">attr</span> <span class="ss">:w</span>
<span class="kp">attr</span> <span class="ss">:thread</span>
<span class="k">def</span> <span class="nf">join</span>
<span class="vi">@thread</span><span class="p">.</span><span class="nf">join</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">measure</span><span class="p">(</span><span class="n">count</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">readings</span> <span class="o">=</span> <span class="n">count</span><span class="p">.</span><span class="nf">times</span><span class="p">.</span><span class="nf">map</span> <span class="k">do</span>
<span class="no">Reading</span><span class="p">.</span><span class="nf">new</span>
<span class="k">end</span>
<span class="nb">sleep</span> <span class="mi">10</span>
<span class="n">duration</span> <span class="o">=</span> <span class="no">Benchmark</span><span class="p">.</span><span class="nf">measure</span> <span class="k">do</span>
<span class="n">readings</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">reading</span><span class="o">|</span>
<span class="n">reading</span><span class="p">.</span><span class="nf">r</span><span class="p">.</span><span class="nf">close</span>
<span class="n">reading</span><span class="p">.</span><span class="nf">w</span><span class="p">.</span><span class="nf">close</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">average</span> <span class="o">=</span> <span class="p">(</span><span class="n">duration</span><span class="p">.</span><span class="nf">total</span> <span class="o">/</span> <span class="n">count</span><span class="p">)</span> <span class="o">*</span> <span class="mf">1000.0</span>
<span class="n">pp</span> <span class="ss">count: </span><span class="n">count</span><span class="p">,</span> <span class="ss">average: </span><span class="nb">sprintf</span><span class="p">(</span><span class="s2">"%0.2fms"</span><span class="p">,</span> <span class="n">average</span><span class="p">)</span>
<span class="n">readings</span><span class="p">.</span><span class="nf">each</span><span class="p">(</span><span class="o">&</span><span class="ss">:join</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">measure</span><span class="p">(</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">measure</span><span class="p">(</span> <span class="mi">100</span><span class="p">)</span>
<span class="n">measure</span><span class="p">(</span> <span class="mi">1000</span><span class="p">)</span>
<span class="n">measure</span><span class="p">(</span><span class="mi">10000</span><span class="p">)</span>
</code></pre>
<p>In addition, the semantics of this operation are confusing at best. While Ruby programs are dealing with IO instances, the VM is dealing with file descriptors, in effect performing some internal de-duplication of IO state. In practice, this leads to strange behaviour:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="c1">#!/usr/bin/env ruby</span>
<span class="n">r</span><span class="p">,</span> <span class="n">w</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">pipe</span>
<span class="n">r2</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">for_fd</span><span class="p">(</span><span class="n">r</span><span class="p">.</span><span class="nf">to_i</span><span class="p">)</span>
<span class="n">pp</span> <span class="ss">r: </span><span class="n">r</span><span class="p">,</span> <span class="ss">r2: </span><span class="n">r2</span>
<span class="n">t</span> <span class="o">=</span> <span class="no">Thread</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span>
<span class="n">r2</span><span class="p">.</span><span class="nf">read</span> <span class="k">rescue</span> <span class="kp">nil</span>
<span class="n">r2</span><span class="p">.</span><span class="nf">read</span> <span class="c1"># EBADF</span>
<span class="k">end</span>
<span class="nb">sleep</span> <span class="mf">0.5</span>
<span class="n">r</span><span class="p">.</span><span class="nf">close</span>
<span class="n">t</span><span class="p">.</span><span class="nf">join</span> <span class="k">rescue</span> <span class="kp">nil</span>
<span class="n">pp</span> <span class="ss">r: </span><span class="n">r</span><span class="p">,</span> <span class="ss">r2: </span><span class="n">r2</span>
<span class="c1"># r is closed, r2 is valid but will raise EBADF on any operation.</span>
</code></pre>
<p>In addition, this confusing behaviour extends to Ractor and state is leaked between the two:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="n">r</span><span class="p">,</span> <span class="n">w</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">pipe</span>
<span class="n">ractor</span> <span class="o">=</span> <span class="no">Ractor</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">r</span><span class="p">.</span><span class="nf">to_i</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">fd</span><span class="o">|</span>
<span class="n">r2</span> <span class="o">=</span> <span class="no">IO</span><span class="p">.</span><span class="nf">for_fd</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span>
<span class="n">r2</span><span class="p">.</span><span class="nf">read</span>
<span class="c1"># r2.read # EBADF</span>
<span class="k">end</span>
<span class="nb">sleep</span> <span class="mf">0.5</span>
<span class="n">r</span><span class="p">.</span><span class="nf">close</span>
<span class="n">pp</span> <span class="ss">take: </span><span class="n">ractor</span><span class="p">.</span><span class="nf">take</span>
</code></pre>
<p>I propose the following changes to simplify the semantics and improve performance:</p>
<ul>
<li>Move the semantics of <code>waiting_fds</code> from per-fd to per-IO. This means that <code>IO#close</code> only interrupts blocking operations performed on the same IO instance rather than ANY IO which refers to the same file descriptor. I think this behaviour is easier to understand and still protects against the vast majority of incorrect usage.</li>
<li>Move the details of <code>struct rb_io_t</code> to <code>internal/io.h</code> so that the implementation details are not part of the public interface.</li>
</ul>
<a name="Benchmarks"></a>
<h2 >Benchmarks<a href="#Benchmarks" class="wiki-anchor">¶</a></h2>
<p>Before:</p>
<pre><code>{:count=>10, :average=>"0.19ms"}
{:count=>100, :average=>"0.11ms"}
{:count=>1000, :average=>"0.18ms"}
{:count=>10000, :average=>"1.16ms"}
</code></pre>
<p>After:</p>
<pre><code>{:count=>10, :average=>"0.20ms"}
{:count=>100, :average=>"0.11ms"}
{:count=>1000, :average=>"0.15ms"}
{:count=>10000, :average=>"0.68ms"}
</code></pre>
<p>After investigating this further I found that the <code>rb_thread_io_blocking_region</code> using <code>ubf_select</code> can be incredibly slow, proportional to the number of threads. I don't know whether it's advisable but:</p>
<pre><code class="c syntaxhl" data-language="c"> <span class="n">BLOCKING_REGION</span><span class="p">(</span><span class="n">blocking_node</span><span class="p">.</span><span class="kr">thread</span><span class="p">,</span> <span class="p">{</span>
<span class="n">val</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="n">data1</span><span class="p">);</span>
<span class="n">saved_errno</span> <span class="o">=</span> <span class="n">errno</span><span class="p">;</span>
<span class="p">},</span> <span class="nb">NULL</span> <span class="cm">/* ubf_select */</span><span class="p">,</span> <span class="n">blocking_node</span><span class="p">.</span><span class="kr">thread</span><span class="p">,</span> <span class="n">FALSE</span><span class="p">);</span>
</code></pre>
<p>Disabling the UBF function and relying on <code>read(fd, ...)</code>/<code>write(fd, ...)</code> blocking operations to fail when <code>close(fd)</code> is invoked might be sufficient? This needs more investigation but after making this change, we have constant-time IO#close.</p>
<pre><code>{:count=>10, :average=>"0.13ms"}
{:count=>100, :average=>"0.06ms"}
{:count=>1000, :average=>"0.04ms"}
{:count=>10000, :average=>"0.09ms"}
</code></pre>
<p>Which is ideally what we want.</p> Ruby master - Feature #18035 (Open): Introduce general model/semantic for immutability.https://bugs.ruby-lang.org/issues/180352021-07-09T08:10:55Zioquatix (Samuel Williams)samuel@oriontransfer.net
<p>It would be good to establish some rules around mutability, immutability, frozen, and deep frozen in Ruby.</p>
<p>I see time and time again, incorrect assumptions about how this works in production code. Constants that aren't really constant, people using <code>#freeze</code> incorrectly, etc.</p>
<p>I don't have any particular preference but:</p>
<ul>
<li>We should establish consistent patterns where possible, e.g.
<ul>
<li>Objects created by <code>new</code> are mutable.</li>
<li>Objects created by literal are immutable.</li>
</ul>
</li>
</ul>
<p>We have problems with how <code>freeze</code> works on composite data types, e.g. <code>Hash#freeze</code> does not impact children keys/values, same for Array. Do we need to introduce <code>freeze(true)</code> or <code>#deep_freeze</code> or some other method?</p>
<p>Because of this, frozen does not necessarily correspond to immutable. This is an issue which causes real world problems.</p>
<p>I also propose to codify this where possible, in terms of "this class of object is immutable" should be enforced by the language/runtime, e.g.</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">Immutable</span>
<span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">super</span><span class="p">.</span><span class="nf">freeze</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">MyImmutableObject</span>
<span class="kp">extend</span> <span class="no">Immutable</span>
<span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="vi">@x</span> <span class="o">=</span> <span class="n">x</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">freeze</span>
<span class="k">return</span> <span class="nb">self</span> <span class="k">if</span> <span class="nb">frozen?</span>
<span class="vi">@x</span><span class="p">.</span><span class="nf">freeze</span>
<span class="k">super</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">o</span> <span class="o">=</span> <span class="no">MyImmutableObject</span><span class="p">.</span><span class="nf">new</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>
<span class="nb">puts</span> <span class="n">o</span><span class="p">.</span><span class="nf">frozen?</span>
</code></pre>
<p>Finally, this area has an impact to thread and fiber safe programming, so it is becoming more relevant and I believe that the current approach which is rather adhoc is insufficient.</p>
<p>I know that it's non-trivial to retrofit existing code, but maybe it can be done via magic comment, etc, which we already did for frozen string literals.</p>
<p>Proposed PR: <a href="https://github.com/ruby/ruby/pull/4879" class="external">https://github.com/ruby/ruby/pull/4879</a></p> Ruby master - Bug #18009 (Open): Regexps \w and \W with /i option and /u option produce inconsist...https://bugs.ruby-lang.org/issues/180092021-06-28T09:09:37Zjirkamarsik (Jirka Marsik)
<p>This is a follow up to <a href="https://bugs.ruby-lang.org/issues/4044" class="external">issue 4044</a>. Its fix (<a href="https://github.com/k-takata/Onigmo/issues/4" class="external">https://github.com/k-takata/Onigmo/issues/4</a>) handled the cases that were reported in the original issue, but there are other cases, which were omitted and now produce inconsistent results.</p>
<p>If the <code>\w</code> character set is used inside a nested negated character class, it will not be picked up by the part of the character class analyzer that's responsible for limiting the case-folding of certain character sets (like <code>\w</code> and <code>\W</code>) across the ASCII boundary. We then end up with the situation where <code>/[^\w]/iu</code> and <code>/[[^\w]]/iu</code> match different sets of characters.</p>
<pre><code>irb(main):001:0> ("a".."z").to_a.join.scan(/\W/iu)
=> []
irb(main):002:0> ("a".."z").to_a.join.scan(/[^\w]/iu)
=> []
irb(main):003:0> ("a".."z").to_a.join.scan(/[[^\w]]/iu)
=> ["k", "s"]
</code></pre>
<p>This can also be demonstrated using the inverted matcher:</p>
<pre><code>irb(main):004:0> ("a".."z").to_a.join.scan(/\w/iu).length
=> 26
irb(main):005:0> ("a".."z").to_a.join.scan(/[^[^\w]]/iu).length
=> 24
</code></pre>
<p>A similar issue also arises when using character class intersection. The idea behind the pattern compiler's analysis is that characters are allowed to case-fold across the ASCII boundary only if they are included in the character class by some other means than just being included in <code>\w</code> (or in one of several other character sets which have special treatment). Therefore, in the below, <code>/[\w]/iu</code> will not match the Kelvin sign <code>\u212a</code>, because that would mean crossing the ASCII boundary from <code>k</code> to <code>\u212a</code>. However, <code>/[kx]/iu</code> will match the Kelvin sign, because the <code>k</code> was not contributed by <code>\w</code> and therefore is not subject to the ASCII boundary restriction (we have to use <code>/[kx]/iu</code> instead of <code>/[k]/iu</code> in our examples, or else the pattern analyzer would replace <code>[k]</code> with <code>k</code> and follow a different code path).</p>
<pre><code>irb(main):006:0> /[\w]/iu.match("\u212a")
=> nil
irb(main):007:0> /[kx]/iu.match("\u212a")
=> #<MatchData "K">
</code></pre>
<p>The problem then is when we perform an intersection of these two character sets. Since <code>[kx]</code> is a subset of <code>\w</code>, we would expect their intersection to behave the same as <code>[kx]</code>, but that is not the case.</p>
<pre><code>irb(main):008:0> /[\w&&kx]/i.match("\u212a")
=> nil
</code></pre>
<p>The underlying issue in these cases is the manner in which the <code>ascCc</code> character set is computed during the parsing of character classes. The <code>ascCc</code> character set should contain all characters of the character class except those which were contributed by <code>\w</code> and similar character sets. This is done in a way that these character sets are essentially ignored in the calculation of <code>ascCc</code>, which works well for set union and top-most negation (which is handled explicitly), but it doesn't handle nested set negation and set intersection.</p> Ruby master - Feature #15554 (Open): warn/error passing a block to a method which never use a blockhttps://bugs.ruby-lang.org/issues/155542019-01-22T04:48:10Zko1 (Koichi Sasada)
<a name="Abstract"></a>
<h1 >Abstract<a href="#Abstract" class="wiki-anchor">¶</a></h1>
<p>Warn or raise an ArgumentError if block is passed to a method which does not use a block.<br>
In other words, detect "block user methods" implicitly and only "block user methods" can accept a block.</p>
<a name="Background"></a>
<h1 >Background<a href="#Background" class="wiki-anchor">¶</a></h1>
<p>Sometimes, we pass a block to a method which ignores the passed block accidentally.</p>
<pre><code>def my_open(name)
open(name)
end
# user hopes it works as Kernel#open which invokes a block with opened file.
my_open(name){|f| important_work_with f }
# but simply ignored...
</code></pre>
<p>To solve this issue, this feature request propose showing warnings or raising an exception on such case.</p>
<p>Last developer's meeting, matz proposed <code>&nil</code> which declares this method never receive a block. It is explicit, but it is tough to add this <code>&nil</code> parameter declaration to all of methods (do you want to add it to <code>def []=(i, e, &nil)</code>?).<br>
(I agree <code>&nil</code> is valuable on some situations)</p>
<a name="Spec"></a>
<h1 >Spec<a href="#Spec" class="wiki-anchor">¶</a></h1>
<a name="Define-use-a-block-methods"></a>
<h2 >Define "use a block" methods<a href="#Define-use-a-block-methods" class="wiki-anchor">¶</a></h2>
<p>We need to define which method accepts a block and which method does not.</p>
<ul>
<li>(1) method has a block parameter (<code>&b</code>)</li>
<li>(2) method body has `yield'</li>
<li>(3) method body has <code>super</code> (ZSUPER in internal terminology) or <code>super(...)</code>
</li>
<li>(4) method body has singleton method (optional)</li>
</ul>
<p>(1) and (2) is very clear. I need to explain about (3) and (4).</p>
<p>(3). <code>super</code> (ZSUPER) passes all parameters as arguments. So there is no surprise that which can accept <code>block</code>.<br>
However <code>super(...)</code> also passes a block if no explicit block passing (like <code>super(){}</code> or <code>super(&b)</code>) are written.<br>
I'm not sure we need to continue this strange specification, but to keep compatibility depending this spec, I add this rule.</p>
<p>(4). surprisingly, the following code invoke a block:</p>
<pre><code>def foo
class << Object.new
yield
end
end
foo{ p :ok } #=> :ok
</code></pre>
<p>I'm also not sure we need to keep this spec, but to allow this spec, I added (4) rule.<br>
Strictly speaking, it is not required, but we don't keep the link from singleton class ISeq to lexical parent iseq now, so I added it.</p>
<a name="Exceptional-cases"></a>
<h2 >Exceptional cases<a href="#Exceptional-cases" class="wiki-anchor">¶</a></h2>
<p>A method called by <code>super</code> doesn<code>t warn warning even if this method doesn't use a block. The rule (3) can pass blocks easily and there are many methods don</code>t use a block.</p>
<p>So my patch ignores callings by <code>super</code>.</p>
<a name="corner-cases"></a>
<h2 >corner cases<a href="#corner-cases" class="wiki-anchor">¶</a></h2>
<p>There are several cases to use block without (1)-(4) rules.</p>
<h3>
<code>Proc.new/proc/lambda</code> without a block</h3>
<p>Now it was deprecated in r66772 (<a class="changeset" title="proc.c: proc without block * proc.c (proc_new): promoted lambda/proc/Proc.new with no block in..." href="https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/9f1fb0a17febc59356d58cef5e98db61a3c03550">9f1fb0a17febc59356d58cef5e98db61a3c03550</a>).<br>
Related discussion: [Bug <a class="issue tracker-1 status-6 priority-4 priority-default closed" title="Bug: Proc.new with no block shouldn't always warn (Rejected)" href="https://bugs.ruby-lang.org/issues/15539">#15539</a>]</p>
<a name="block_given"></a>
<h3 ><code>block_given?</code><a href="#block_given" class="wiki-anchor">¶</a></h3>
<p><code>block_given?</code> expects block, but I believe we use it with <code>yield</code> or a block parameter.<br>
If you know the usecase without them, please tell us.</p>
<h3>
<code>yield</code> in <code>eval</code>
</h3>
<p>We can't know <code>yield</code> (or (3), (4) rule) in an <code>eval</code> evaluating string at calling time.</p>
<pre><code>def foo
eval('yield`)
end
foo{} # at calling time,
# we can't know the method foo can accept a block or not.
</code></pre>
<p>So I added a warning to use <code>yield</code> in <code>eval</code> like that: <code>test.rb:4: warning: use yield in eval will not be supported in Ruby 3.</code></p>
<p>Workaround is use a block parameter explicitly.</p>
<pre><code>def foo &b
eval('b.call')
end
foo{ p :ok }
</code></pre>
<a name="Implementation"></a>
<h1 >Implementation<a href="#Implementation" class="wiki-anchor">¶</a></h1>
<p>Strategy is:</p>
<ul>
<li>[compile time] introduce <code>iseq::has_yield</code> field and check it if the iseq (or child iseq) contains <code>yield</code> (or something)</li>
<li>[calling time] if block is given, check <code>iseq::has_yield</code> flag and show warning (or raise an exception)</li>
</ul>
<p><a href="https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b" class="external">https://gist.github.com/ko1/c9148ad0224bf5befa3cc76ed2220c0b</a></p>
<p>On this patch, now it raises an error to make it easy to detect.<br>
It is easy to switch to show the warning.</p>
<a name="Evaluation-and-discussion"></a>
<h1 >Evaluation and discussion<a href="#Evaluation-and-discussion" class="wiki-anchor">¶</a></h1>
<p>I tried to avoid ruby's tests.</p>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786</a></p>
<p>Here is a patch.</p>
<p>There are several patterns to avoid warnings.</p>
<a name="tests-for-block_given-Procnew-and-similar-without-block"></a>
<h2 >tests for <code>block_given?</code>, <code>Proc.new</code> (and similar) without block<a href="#tests-for-block_given-Procnew-and-similar-without-block" class="wiki-anchor">¶</a></h2>
<p>Add a dummy block parameter.<br>
It is test-specific issue.</p>
<h2>empty <code>each</code>
</h2>
<p>Some tests add <code>each</code> methods do not <code>yield</code>, like: <code>def each; end</code>.<br>
Maybe test-specific issue, and adding a dummy block parameter.</p>
<a name="Subtyping-duck-typing"></a>
<h2 >Subtyping / duck typing<a href="#Subtyping-duck-typing" class="wiki-anchor">¶</a></h2>
<p><a href="https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/lib/optparse.rb#L698" class="external">https://github.com/ruby/ruby/blob/c01a5ee85e2d6a7128cccafb143bfa694284ca87/lib/optparse.rb#L698</a></p>
<p>This <code>parse</code> method doesn't use <code>yield</code>, but other sub-type's <code>parse</code> methods use.</p>
<h2>
<code>super</code> with <code>new</code> method</h2>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L61" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L61</a></p>
<p>This method override <code>Class#new</code> method and introduce a hook with block (yield a block in this hook code).</p>
<p><a href="https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#L81" class="external">https://github.com/ruby/ruby/blob/trunk/lib/rubygems/package/tar_writer.rb#L81</a></p>
<p>In this method, call <code>super</code> and it also passing a block. However, called <code>initialize</code> doesn't use a block.</p>
<a name="Change-robustness"></a>
<h2 >Change robustness<a href="#Change-robustness" class="wiki-anchor">¶</a></h2>
<p>This change reduce robustness for API change.</p>
<p><code>Delegator</code> requires to support <code>__getobj__</code> for client classes.<br>
Now <code>__getobj__</code> should accept block but most of <code>__getobj__</code> clients do not call given block.</p>
<p><a href="https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80" class="external">https://github.com/ruby/ruby/blob/trunk/lib/delegate.rb#L80</a></p>
<p>This is because of delegator.rb's API change.</p>
<p><a href="https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L86" class="external">https://gist.github.com/ko1/37483e7940cdc4390bf8eb0001883786#file-tests-patch-L86</a></p>
<p>Nobu says calling block is not required (ignoring a block is no problem) so it is not a bug for delegator client classes.</p>
<a name="Found-issues"></a>
<h2 >Found issues.<a href="#Found-issues" class="wiki-anchor">¶</a></h2>
<pre><code>[ 2945/20449] Rinda::TestRingServer#test_do_reply = 0.00 s
1) Error:
Rinda::TestRingServer#test_do_reply:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:635:in `test_do_reply'
[ 2946/20449] Rinda::TestRingServer#test_do_reply_local = 0.00 s
2) Error:
Rinda::TestRingServer#test_do_reply_local:
ArgumentError: passing block to the method "with_timeout" (defined at /home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:787) is never used.
/home/ko1/src/ruby/trunk/test/rinda/test_rinda.rb:657:in `test_do_reply_local'
[10024/20449] TestGemRequestSetGemDependencyAPI#test_platform_mswin = 0.01 s
3) Error:
TestGemRequestSetGemDependencyAPI#test_platform_mswin:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:655:in `test_platform_mswin'
[10025/20449] TestGemRequestSetGemDependencyAPI#test_platforms = 0.01 s
4) Error:
TestGemRequestSetGemDependencyAPI#test_platforms:
ArgumentError: passing block to the method "util_set_arch" (defined at /home/ko1/src/ruby/trunk/lib/rubygems/test_case.rb:1053) is never used.
/home/ko1/src/ruby/trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb:711:in `test_platforms'
</code></pre>
<p>These 4 detection show the problem. <code>with_timeout</code> method (used in Rinda test) and <code>util_set_arch</code> method (used in Rubygems test) simply ignore the given block.<br>
So these tests are simply ignored.</p>
<p>I reported them. (<a href="https://github.com/rubygems/rubygems/issues/2601" class="external">https://github.com/rubygems/rubygems/issues/2601</a>)</p>
<a name="raise-an-error-or-show-a-warning"></a>
<h2 >raise an error or show a warning?<a href="#raise-an-error-or-show-a-warning" class="wiki-anchor">¶</a></h2>
<p>At least, Ruby 2.7 should show warning for this kind of violation with <code>-w</code>.<br>
How about for Ruby3?</p> Ruby master - Feature #11446 (Open): Possible work around for the requirement to supplying argume...https://bugs.ruby-lang.org/issues/114462015-08-14T16:40:15Zjikkujose (Jikku Jose)jikkujose+os@gmail.com
<p>Any chance this <a href="http://stackoverflow.com/questions/23695653/can-you-supply-arguments-to-the-mapmethod-syntax-in-ruby/23711606#23711606" class="external">work around</a> can be considered to be part of the language. Seems to be a pretty neat.</p>
<p>NB: Matz seems to be interested in having this added: Check his <a href="https://twitter.com/yukihiro_matz/status/632016695016620033" class="external">tweet</a>.</p> Ruby master - Feature #6594 (Assigned): Integrated Functorhttps://bugs.ruby-lang.org/issues/65942012-06-15T09:02:38Ztrans (Thomas Sawyer)
<p>I know the developers meeting is coming up so I'd like to get a few ideas I've had sitting in the wings out in the air before then.</p>
<p>One the more useful is the idea of integrating Functors directly into the language. "Functor" is the term I use for "higher-order function".</p>
<p>I blogged about this idea and you can read it here: <a href="http://trans.github.com/2011-09-07-ruby-heart-higher-order-functions/" class="external">http://trans.github.com/2011-09-07-ruby-heart-higher-order-functions/</a></p>
<p>The super short version is this:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">def</span> <span class="nf">f</span> <span class="o">=></span> <span class="n">op</span><span class="p">,</span> <span class="n">arg</span>
<span class="n">arg</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">__op__</span><span class="p">,</span> <span class="n">arg</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">f</span> <span class="o">+</span> <span class="mi">3</span> <span class="c1">#=> 6</span>
<span class="n">f</span> <span class="o">*</span> <span class="mi">3</span> <span class="c1">#=> 9</span>
</code></pre>
<p>Another example:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">String</span>
<span class="k">def</span> <span class="nf">file</span> <span class="o">=></span> <span class="n">op</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span>
<span class="no">File</span><span class="p">.</span><span class="nf">send</span><span class="p">(</span><span class="n">__op__</span><span class="p">,</span> <span class="nb">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="s2">"README.rdoc"</span><span class="p">.</span><span class="nf">file</span><span class="p">.</span><span class="nf">mtime</span> <span class="c1">#=> 2012-06-14 12:34:45 -0400</span>
</code></pre>
<p>I'm using <code>=></code> as means of indicating a higher-order function. Of course another syntax could be used if this won't fly. The important thing is the idea of higher-order functions being integrated directly into the language. Doing this without that integration requires the creation of an intermediate object for each call which is very inefficient.</p> Ruby master - Feature #6337 (Assigned): FileUtils#synchttps://bugs.ruby-lang.org/issues/63372012-04-22T09:13:25Ztrans (Thomas Sawyer)
<p>=begin<br>
I'd like to see some sort of FileUtils#sync method to sync the contents of one directory with another.</p>
<p>Here is a prototype definition:</p>
<pre><code>#
# Synchronize a destination directory with a source directory.
#
def sync(src, dst, options={})
src_files = Dir[File.join(src, '**', '*')].map{ |f| f.sub(src+'/', '') }
dst_files = Dir[File.join(dst, '**', '*')].map{ |f| f.sub(dst+'/', '') }
removal = dst_files - src_files
rm_dirs, rm_files = [], []
removal.each do |f|
path = File.join(dst, f)
if File.directory?(path)
rm_dirs << path
else
rm_files << path
end
end
rm_files.each { |f| rm(f) }
rm_dirs.each { |d| rmdir(d) }
src_files.each do |f|
src_path = File.join(src, f)
dst_path = File.join(dst, f)
if File.directory?(src_path)
mkdir_p(dst_path)
else
parent = File.dirname(dst_path)
mkdir_p(parent) unless File.directory?(parent)
install(src_path, dst_path)
end
end
end
</code></pre>
<p>I haven't tested this beyond a simple trial. It needs improvement. For one, it probably should be able to handle regular files as arguments too. It also needs to handle verbose and dryrun options properly. Nonetheless, with improvements, would be okay for such to become new feature for FileUtils?</p>
<p>=end</p> Ruby master - Feature #6317 (Assigned): Range#cover?の引数としてRangeインスタンスを受けられるようにして欲しいhttps://bugs.ruby-lang.org/issues/63172012-04-18T20:51:08Zmasaakiaoyagi (Masaaki Aoyagi)masaaki.aoyagi@gmail.com
<p>青柳と申します。</p>
<p>以下のように、Range#cover?の引数としてRangeインスタンスを<br>
受けられるようにして欲しいです。<br>
(1..4).cover?(2..3) # => true<br>
(1..4).cover?(0..3) # => false</p>
<p>取り敢えず実装してみましたので、添付いたします。</p> Ruby master - Feature #5133 (Assigned): Array#unzip as an alias of Array#transposehttps://bugs.ruby-lang.org/issues/51332011-08-01T18:30:03Zmrkn (Kenta Murata)muraken@gmail.com
<p>Array#zip の逆は Array#transpose なんですけど、<br>
この対応関係が非常に分かり難いなと思いました。</p>
<p>Haskell には zip の逆をやる関数として unzip が用意されています。<br>
unzip という名前は、「zip の逆をやりたい」と思ったときに<br>
(transpose よりは) 思い付きやすい名前だと思います。</p>
<p>ということで Array#unzip を Array#transpose のエイリアスとして<br>
導入してはどうでしょう?</p>
<p>以下パッチです:</p>
<p>diff --git a/array.c b/array.c<br>
index 8caad66..dc411b7 100644<br>
--- a/array.c<br>
+++ b/array.c<br>
@@ -4720,6 +4720,7 @@ Init_Array(void)<br>
rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0);<br>
rb_define_method(rb_cArray, "zip", rb_ary_zip, -1);<br>
rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0);</p>
<ul>
<li>rb_define_alias(rb_cArray, "unzip", "transpose");<br>
rb_define_method(rb_cArray, "replace", rb_ary_replace, 1);<br>
rb_define_method(rb_cArray, "clear", rb_ary_clear, 0);<br>
rb_define_method(rb_cArray, "fill", rb_ary_fill, -1);</li>
</ul> Ruby master - Feature #3731 (Assigned): Easier Embedding API for Rubyhttps://bugs.ruby-lang.org/issues/37312010-08-22T07:16:50ZBeoran (Beoran Aegul)beoran@rubyforge.org
<p>=begin<br>
With Ruby 1.9, it has become more difficult to embed Ruby in a C application correctly.<br>
It would be nice if there was a clearly documented and simple C API to embed ruby in C programs.<br>
I know Ruby was not designed from the start to be embedded, but Ruby was used before in several<br>
products as an embedded scripting langauge. It should therefore be possible to do so in a<br>
more straightforward way.</p>
<p>Kind Regards,</p>
<p>B.<br>
=end</p>