[ruby-core:116656] [Ruby master Bug#20253] `Proc.dup` and `Proc#clone` don't preserve finalizers

Issue #20253 has been reported by byroot (Jean Boussier). ---------------------------------------- Bug #20253: `Proc.dup` and `Proc#clone` don't preserve finalizers https://bugs.ruby-lang.org/issues/20253 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal * Backport: 3.0: WONTFIX, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- While reviewing the fix for [Bug #20250] @peterzhu2118 pointed that `FL_FINALIZE` should probably also be cleared. However after some extra testing, it appears `Object#dup` and `Object#clone` do copy over the finalizer (which makes sense). But for some reason `Proc` has its own `dup/clone` implementation, which does copy the `FL_FINALIZE` flag, but doesn't copy the finalizer: Test script: ```ruby def fin(sym) ->(_) { p sym } end obj = Object.new ObjectSpace.define_finalizer(obj, fin(:obj)) obj.dup obj.clone proc = Proc.new { } ObjectSpace.define_finalizer(proc, fin(:proc)) proc.dup proc.clone ``` Expected output: ``` :proc :proc :proc :obj :obj :obj ``` Actual output: ``` :proc :obj :obj :obj ``` This discrepancy is present all the way back to Ruby 1.9. It's so niche I'm not sure it's worth a backport though... -- https://bugs.ruby-lang.org/

Issue #20253 has been updated by byroot (Jean Boussier). While looking at this, it appears that instance variables are also not copied over in `Proc#dup`, but somehow are in `Proc#clone`: ```ruby def ivar_dup(obj) obj.instance_variable_set(:@foo, 1) p [:dup, obj.dup.instance_variable_get(:@foo)] p [:clone, obj.clone.instance_variable_get(:@foo)] end ivar_dup(Object.new) ivar_dup(Proc.new { }) ``` ``` [:dup, 1] [:clone, 1] [:dup, nil] [:clone, 1] ``` Which really raise the question of why Proc has a completely different codepath for duping/cloning, AFAIK no other core type does this. ---------------------------------------- Bug #20253: `Proc.dup` and `Proc#clone` don't preserve finalizers https://bugs.ruby-lang.org/issues/20253#change-106667 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal * Backport: 3.0: WONTFIX, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- While reviewing the fix for [Bug #20250] @peterzhu2118 pointed that `FL_FINALIZE` should probably also be cleared. However after some extra testing, it appears `Object#dup` and `Object#clone` do copy over the finalizer (which makes sense). But for some reason `Proc` has its own `dup/clone` implementation, which does copy the `FL_FINALIZE` flag, but doesn't copy the finalizer: Test script: ```ruby def fin(sym) ->(_) { p sym } end obj = Object.new ObjectSpace.define_finalizer(obj, fin(:obj)) obj.dup obj.clone proc = Proc.new { } ObjectSpace.define_finalizer(proc, fin(:proc)) proc.dup proc.clone ``` Expected output: ``` :proc :proc :proc :obj :obj :obj ``` Actual output: ``` :proc :obj :obj :obj ``` This discrepancy is present all the way back to Ruby 1.9. It's so niche I'm not sure it's worth a backport though... -- https://bugs.ruby-lang.org/

Issue #20253 has been updated by byroot (Jean Boussier). We just found yet another issue with @etienne: ```ruby
Proc.new { }.freeze.clone (irb):1:in `initialize_copy': can't modify frozen Proc: #<Proc:0x000000011e3a96b0 (irb):1> (FrozenError) from (irb):1:in `initialize_clone' from (irb):1:in `clone' from (irb):1:in `<main>'
This one was introduced in Ruby 3.3.0.
----------------------------------------
Bug #20253: `Proc.dup` and `Proc#clone` don't preserve finalizers
https://bugs.ruby-lang.org/issues/20253#change-106688
* Author: byroot (Jean Boussier)
* Status: Open
* Priority: Normal
* Backport: 3.0: WONTFIX, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
While reviewing the fix for [Bug #20250] @peterzhu2118 pointed that `FL_FINALIZE` should probably also be cleared.
However after some extra testing, it appears `Object#dup` and `Object#clone` do copy over the finalizer (which makes sense).
But for some reason `Proc` has its own `dup/clone` implementation, which does copy the `FL_FINALIZE` flag, but doesn't copy the finalizer:
Test script:
```ruby
def fin(sym)
->(_) { p sym }
end
obj = Object.new
ObjectSpace.define_finalizer(obj, fin(:obj))
obj.dup
obj.clone
proc = Proc.new { }
ObjectSpace.define_finalizer(proc, fin(:proc))
proc.dup
proc.clone
Expected output: ``` :proc :proc :proc :obj :obj :obj ``` Actual output: ``` :proc :obj :obj :obj ``` This discrepancy is present all the way back to Ruby 1.9. It's so niche I'm not sure it's worth a backport though... -- https://bugs.ruby-lang.org/

Issue #20253 has been updated by byroot (Jean Boussier). https://github.com/ruby/ruby/pull/9926 fixes all the issues above and a few others. ---------------------------------------- Bug #20253: `Proc.dup` and `Proc#clone` don't preserve finalizers https://bugs.ruby-lang.org/issues/20253#change-106689 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal * Backport: 3.0: WONTFIX, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- While reviewing the fix for [Bug #20250] @peterzhu2118 pointed that `FL_FINALIZE` should probably also be cleared. However after some extra testing, it appears `Object#dup` and `Object#clone` do copy over the finalizer (which makes sense). But for some reason `Proc` has its own `dup/clone` implementation, which does copy the `FL_FINALIZE` flag, but doesn't copy the finalizer: Test script: ```ruby def fin(sym) ->(_) { p sym } end obj = Object.new ObjectSpace.define_finalizer(obj, fin(:obj)) obj.dup obj.clone proc = Proc.new { } ObjectSpace.define_finalizer(proc, fin(:proc)) proc.dup proc.clone ``` Expected output: ``` :proc :proc :proc :obj :obj :obj ``` Actual output: ``` :proc :obj :obj :obj ``` This discrepancy is present all the way back to Ruby 1.9. It's so niche I'm not sure it's worth a backport though... -- https://bugs.ruby-lang.org/
participants (1)
-
byroot (Jean Boussier)