Ruby Issue Tracking System: Issues
https://bugs.ruby-lang.org/
https://bugs.ruby-lang.org/favicon.ico?1711330511
2024-03-24T15:46:18Z
Ruby Issue Tracking System
Redmine
Ruby master - Feature #20390 (Closed): Issue with StringIO and chilled strings
https://bugs.ruby-lang.org/issues/20390
2024-03-24T15:46:18Z
mdalessio (Mike Dalessio)
mike.dalessio@gmail.com
<p>StringIO doesn't appear to handle chilled strings in a backwards-compatible way after 12be40ae</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">require</span> <span class="s2">"stringio"</span>
<span class="n">sio</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="p">)</span>
<span class="n">sio</span><span class="p">.</span><span class="nf">write</span><span class="p">(</span><span class="s2">"hello"</span><span class="p">)</span>
</code></pre>
<p>When not specifying a value for <code>frozen-string-literal</code>, the empty string is chilled so I would expect to get a warning but also expect the write to complete.</p>
<p>Instead, the write fails as if the string is frozen:</p>
<pre><code>ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
./issue-stringio-frozen.rb:8:in 'StringIO#write': not opened for writing (IOError)
from ./issue-stringio-frozen.rb:8:in '<main>'
</code></pre>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/7941">@byroot (Jean Boussier)</a> <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/8880">@etienne (Étienne Barrié)</a></p>
Ruby master - Bug #20389 (Closed): Issue with chilled strings and mutability after 12be40ae
https://bugs.ruby-lang.org/issues/20389
2024-03-24T13:33:43Z
mdalessio (Mike Dalessio)
mike.dalessio@gmail.com
<p>Commit 12be40ae introduced the concept of "chilled" strings when code is compiled with frozen-string-literals not explicitly enabled or disabled. I believe I've found a related bug, which I've bisected to this commit.</p>
<p>This reproduction has been simplified from a failing test case in the <code>http-cookie</code> gem:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="nb">puts</span> <span class="no">RUBY_DESCRIPTION</span>
<span class="n">re</span> <span class="o">=</span> <span class="sr">%r{.(?<thing>.*)}</span>
<span class="n">input</span> <span class="o">=</span> <span class="s2">"x/dir[]/file.html"</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="nf">match</span><span class="p">(</span><span class="n">input</span><span class="p">)</span> <span class="c1"># => "#<MatchData \"x/dir[]/file.html\" thing:\"/dir[]/file.html\">"</span>
<span class="n">thing</span> <span class="o">=</span> <span class="n">match</span><span class="p">[</span><span class="ss">:thing</span><span class="p">]</span>
<span class="nb">puts</span> <span class="s2">"before: </span><span class="si">#{</span><span class="n">thing</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span>
<span class="n">input</span><span class="p">[</span><span class="n">match</span><span class="p">.</span><span class="nf">begin</span><span class="p">(</span><span class="ss">:thing</span><span class="p">)</span><span class="o">...</span><span class="n">match</span><span class="p">.</span><span class="nf">end</span><span class="p">(</span><span class="ss">:thing</span><span class="p">)]</span> <span class="o">=</span> <span class="s2">"/dir%5B%5D/file.html"</span>
<span class="nb">puts</span> <span class="s2">"after : </span><span class="si">#{</span><span class="n">thing</span><span class="p">.</span><span class="nf">inspect</span><span class="si">}</span><span class="s2">"</span>
<span class="nb">exit</span> <span class="mi">1</span> <span class="k">unless</span> <span class="n">thing</span> <span class="o">==</span> <span class="s2">"/dir[]/file.html"</span>
</code></pre>
<p>Ruby 3.3.0 and earlier is fine:</p>
<pre><code>$ ruby ./issue-chilled-strings.rb
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir[]/file.html"
</code></pre>
<p>Master with frozen string explicitly disabled passes:</p>
<pre><code>$ ruby --disable-frozen-string-literal ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir[]/file.html"
</code></pre>
<p>Master with frozen strings explicitly enabled fails as expected:</p>
<pre><code>$ ruby --enable-frozen-string-literal ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
./issue-chilled-strings.rb:12:in 'String#[]=': can't modify frozen String: "x/dir[]/file.html" (FrozenError)
from ./issue-chilled-strings.rb:12:in '<main>'
</code></pre>
<p>But master with no frozen string setting ("chilled") fails, and modifies what should be a frozen string:</p>
<pre><code>$ ruby ./issue-chilled-strings.rb
ruby 3.4.0dev (2024-03-23T16:40:17Z master 8265a7531f) [x86_64-linux]
before: "/dir[]/file.html"
after : "/dir%5B%5D/file."
</code></pre>
<p>I believe in this case, the chilled warning should be emitted, but then the frozen string should not be modified.</p>
Ruby master - Bug #19427 (Closed): Marshal.load(source, freeze: true) doesn't freeze in some cases
https://bugs.ruby-lang.org/issues/19427
2023-02-09T16:10:13Z
andrykonchin (Andrew Konchin)
<p>I've noticed that the <code>freeze</code> option doesn't work in the following cases:</p>
<ul>
<li>when dumped object extends a module</li>
<li>when dumped object responds to <code>#marshal_dump</code> and <code>#marshal_load</code> methods</li>
<li>when dumped object responds to <code>#_dump</code> method</li>
</ul>
<p>Is it expected behaviour or maybe a known issue?</p>
<p>Examples:</p>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">module</span> <span class="nn">M</span>
<span class="k">end</span>
<span class="n">object</span> <span class="o">=</span> <span class="no">Object</span><span class="p">.</span><span class="nf">new</span>
<span class="n">object</span><span class="p">.</span><span class="nf">extend</span><span class="p">(</span><span class="no">M</span><span class="p">)</span>
<span class="n">object</span> <span class="o">=</span> <span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="no">Marshal</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="n">object</span><span class="p">),</span> <span class="ss">freeze: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">object</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># => false</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">UserMarshal</span>
<span class="nb">attr_accessor</span> <span class="ss">:data</span>
<span class="k">def</span> <span class="nf">initialize</span>
<span class="vi">@data</span> <span class="o">=</span> <span class="s1">'stuff'</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">marshal_dump</span><span class="p">()</span> <span class="ss">:data</span> <span class="k">end</span>
<span class="k">def</span> <span class="nf">marshal_load</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="vi">@data</span> <span class="o">=</span> <span class="n">data</span> <span class="k">end</span>
<span class="k">end</span>
<span class="n">object</span> <span class="o">=</span> <span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="no">Marshal</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="no">UserMarshal</span><span class="p">.</span><span class="nf">new</span><span class="p">),</span> <span class="ss">freeze: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">object</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># => false</span>
</code></pre>
<pre><code class="ruby syntaxhl" data-language="ruby"><span class="k">class</span> <span class="nc">UserDefined</span>
<span class="nb">attr_reader</span> <span class="ss">:a</span><span class="p">,</span> <span class="ss">:b</span>
<span class="k">def</span> <span class="nf">initialize</span>
<span class="vi">@a</span> <span class="o">=</span> <span class="s1">'stuff'</span>
<span class="vi">@b</span> <span class="o">=</span> <span class="vi">@a</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">_dump</span><span class="p">(</span><span class="n">depth</span><span class="p">)</span>
<span class="no">Marshal</span><span class="p">.</span><span class="nf">dump</span> <span class="p">[</span><span class="ss">:stuff</span><span class="p">,</span> <span class="ss">:stuff</span><span class="p">]</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">_load</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span> <span class="n">data</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">allocate</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">instance_variable_set</span> <span class="ss">:@a</span><span class="p">,</span> <span class="n">a</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">instance_variable_set</span> <span class="ss">:@b</span><span class="p">,</span> <span class="n">b</span>
<span class="n">obj</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">object</span> <span class="o">=</span> <span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="no">Marshal</span><span class="p">.</span><span class="nf">dump</span><span class="p">(</span><span class="no">UserDefined</span><span class="p">.</span><span class="nf">new</span><span class="p">),</span> <span class="ss">freeze: </span><span class="kp">true</span><span class="p">)</span>
<span class="n">object</span><span class="p">.</span><span class="nf">frozen?</span> <span class="c1"># => false</span>
</code></pre>
Ruby master - Feature #17881 (Closed): Add a Module#const_added callback
https://bugs.ruby-lang.org/issues/17881
2021-05-22T11:43:26Z
byroot (Jean Boussier)
byroot@ruby-lang.org
<a name="Use-case"></a>
<h3 >Use case<a href="#Use-case" class="wiki-anchor">¶</a></h3>
<p>Autoloaders like <code>zeitwerk</code> need a callback when a new class or module is registered in the constant table.</p>
<p>Currently this is implemented with TracePoint's <code>:class</code> event. It works, but it is a bit unfortunate to have to use an API intended for debugging to implement production features. It doesn't feel "conceptually clean".</p>
<p>It also <a href="https://k0kubun.medium.com/ruby-3-jit-can-make-rails-faster-756310f235a" class="external">doesn't play well with MJIT</a>, even though it's more of an MJIT limitation.</p>
<p>Additionally this usage of TracePoint cause <a href="https://github.com/deivid-rodriguez/byebug/issues/564" class="external">some incompatibilities with some debuggers like <code>byebug</code></a> (even though others don't have this issue).</p>
<a name="Proposal"></a>
<h3 >Proposal<a href="#Proposal" class="wiki-anchor">¶</a></h3>
<p>I believe that if Ruby was to call <code>Module#const_added</code> when a constant is registered, Zeitwerk could get rid of TracePoint.</p>
<p>For now I implemented it as: <code>const_added(const_name)</code> for similarity with <code>method_added</code>. But maybe it could make sense to have the signature be <code>const_added(const_name, const_value)</code>.</p>
<p>Also since <code>method_removed</code> exists, maybe <code>const_removed</code> would need to be added for consistency.</p>
<a name="Links"></a>
<h3 >Links<a href="#Links" class="wiki-anchor">¶</a></h3>
<p>Patch: <a href="https://github.com/ruby/ruby/pull/4521" class="external">https://github.com/ruby/ruby/pull/4521</a><br>
Zeitwerk side discussion: <a href="https://github.com/fxn/zeitwerk/issues/135" class="external">https://github.com/fxn/zeitwerk/issues/135</a></p>
<p>cc <a class="user active user-mention" href="https://bugs.ruby-lang.org/users/10073">@k0kubun (Takashi Kokubun)</a></p>
Ruby master - Bug #17020 (Closed): ObjectSpace.trace_object_allocations_stop raises if called bef...
https://bugs.ruby-lang.org/issues/17020
2020-07-08T13:06:56Z
byroot (Jean Boussier)
byroot@ruby-lang.org
<p>The error is easy to reproduce:</p>
<p>e.g. on Ruby 2.3:</p>
<pre><code>$ ruby -robjspace -e 'ObjectSpace.trace_object_allocations_stop'
-e:1:in `trace_object_allocations_stop': wrong argument type false (expected tracepoint) (TypeError)
from -e:1:in `<main>'
</code></pre>
<p>Up to ruby 2.7.1:</p>
<pre><code>$ ruby -robjspace -e 'ObjectSpace.trace_object_allocations_stop'
Traceback (most recent call last):
1: from -e:1:in `<main>'
-e:1:in `trace_object_allocations_stop': wrong argument type false (expected tracepoint) (TypeError)
</code></pre>
<p>Patch: <a href="https://github.com/ruby/ruby/pull/3001" class="external">https://github.com/ruby/ruby/pull/3001</a></p>