[#122643] [Ruby Bug#21498] Windows - Ruby Overrides C Library APIs thus breaking them — "cfis (Charlie Savage) via ruby-core" <ruby-core@...>

Issue #21498 has been reported by cfis (Charlie Savage).

9 messages 2025/07/02

[#122658] [Ruby Feature#21501] Include native filenames in backtraces as sources for native methods — "ivoanjo (Ivo Anjo) via ruby-core" <ruby-core@...>

Issue #21501 has been reported by ivoanjo (Ivo Anjo).

10 messages 2025/07/05

[#122665] [Ruby Bug#21503] \p{Word} does not match on \p{Join_Control} while docs say it does — "procmarco (Marco Concetto Rudilosso) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxNTAzIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IHByb2NtYXJjbyAoTWFyY28gQ29uY2V0

8 messages 2025/07/07

[#122734] [Ruby Bug#21511] Use-after-free of the execution context after the fiber object carrying it is freed in GC — "tuonigou (tianyang sun) via ruby-core" <ruby-core@...>

Issue #21511 has been reported by tuonigou (tianyang sun).

10 messages 2025/07/14

[#122797] [Ruby Feature#21515] Add `&return` as sugar for `x=my_calculation; return x if x` — "nhorton (Noah Horton) via ruby-core" <ruby-core@...>

Issue #21515 has been reported by nhorton (Noah Horton).

13 messages 2025/07/16

[#122842] [Ruby Feature#21518] Statistical helpers to `Enumerable` — "Amitleshed (Amit Leshed) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxNTE4IGhhcyBiZWVuIHJlcG9ydGVkIGJ5IEFtaXRsZXNoZWQgKEFtaXQgTGVzaGVk

12 messages 2025/07/23

[#122847] [Ruby Feature#21520] Feature Proposal: Enumerator::Lazy#peek — "nuzair46 (Nuzair Rasheed) via ruby-core" <ruby-core@...>

SXNzdWUgIzIxNTIwIGhhcyBiZWVuIHJlcG9ydGVkIGJ5IG51emFpcjQ2IChOdXphaXIgUmFzaGVl

12 messages 2025/07/24

[ruby-core:122841] [Ruby Feature#21039] Ractor.make_shareable breaks block semantics (seeing updated captured variables) of existing blocks

From: "Eregon (Benoit Daloze) via ruby-core" <ruby-core@...>
Date: 2025-07-22 20:45:53 UTC
List: ruby-core #122841
Issue #21039 has been updated by Eregon (Benoit Daloze).


@tenderlovemaking The issue with that is it still breaks the block semantics as in the OP description, specifically reading of captured variables inside the block is snapshotted for Ractor-shareable-blocks:
```
$ ruby -e 'count = 0; b = nil.instance_exec { -> { count  } }; p b.call; count += 1; p b.call'                      
0
1
$ ruby -e 'count = 0; b = nil.instance_exec { -> { count  } }; b2 = Ractor.shareable_proc(&b); p b2.call; count += 1; p b2.call'
0
0
```

It's the general guarantee in Ruby that a given literal block always behave the same, e.g. it's either a proc or lambda, but not both (except when using `send(condition ? :proc : :lambda) { ... }` but that's explicit then), and in this case it's either a block respecting updated captures variables or not.
So how to keep this important guarantee (i.e. the block author can rely on captured variables to behave as they always have been for Ruby blocks and respect reassignments) and allow the flexibility you want?

BTW `Ractor.make_shareable` on a Proc which assigns captured variables is an error (good, better to fail early than silently ignore the write):
```
$ ruby -e 'count = 0; b = nil.instance_exec { -> { count += 1 } }; Ractor.make_shareable b'          
-e:1:in 'Ractor.make_shareable': can not make a Proc shareable because it accesses outer variables (count). (ArgumentError)
	from -e:1:in '<main>'
```

Maybe one way would be for `Ractor.shareable_proc` to be an error if there is any code around that Proc assigning any captured variable?
It can't detect `binding` and `eval` though, so that's still not complete.

One way for that Sinatra case would be to write:
```ruby

get "/", &Ractor.shareable_proc {
  "Hello world"
}
```

but this only really works if there are no captured variables, or captured variables are not reassigned and the contents of captured variables is shareable, so probably in many realistic cases it doesn't work anyway.

----------------------------------------
Feature #21039: Ractor.make_shareable breaks block semantics (seeing updated captured variables) of existing blocks
https://bugs.ruby-lang.org/issues/21039#change-114131

* Author: Eregon (Benoit Daloze)
* Status: Assigned
* Assignee: ko1 (Koichi Sasada)
----------------------------------------
```ruby
def make_counter
  count = 0
  nil.instance_exec do
    [-> { count }, -> { count += 1 }]
  end
end

get, increment = make_counter

reader = Thread.new {
  sleep 0.01
  loop do
    p get.call
    sleep 0.1
  end
}

writer = Thread.new {
  loop do
    increment.call
    sleep 0.1
  end
}

ractor_thread = Thread.new {
  sleep 1
  Ractor.make_shareable(get)
}

sleep 2
```

This prints:
```
1
2
3
4
5
6
7
8
9
10
10
10
10
10
10
10
10
10
10
10
```
But it should print 1..20, and indeed it does when commenting out the `Ractor.make_shareable(get)`.

This shows a given block/Proc instance is concurrently broken by `Ractor.make_shareable`, IOW Ractor is breaking fundamental Ruby semantics of blocks and their captured/outer variables or "environment".

It's expected that `Ractor.make_shareable` can `freeze` objects and that may cause some FrozenError, but here it's not a FrozenError, it's wrong/stale values being read.

I think what should happen instead is that `Ractor.make_shareable` should create a new Proc and mutate that.
However, if the Proc is inside some other object and not just directly the argument, that wouldn't work (like `Ractor.make_shareable([get])`).

So I think one fix would to be to only accept Procs for `Ractor.make_shareable(obj, copy: true)`.
FWIW that currently doesn't allow Procs, it gives `<internal:ractor>:828:in 'Ractor.make_shareable': allocator undefined for Proc (TypeError)`.
It makes sense to use `copy` here since `make_shareable` effectively takes a copy/snapshot of the Proc's environment.

I think the only other way, and I think it would be a far better way would be to not support making Procs shareable with `Ractor.make_shareable`.
Instead it could be some new method like `isolated { ... }` or `Proc.isolated { ... }` or `Proc.snapshot_outer_variables { ... }` or so, only accepting a literal block (to avoid mutating/breaking an existing block), and that would snapshot outer variables (or require no outer variables like Ractor.new's block, or maybe even do `Ractor.make_shareable(copy: true)` on outer variables) and possibly also set `self` since that's anyway needed.
That would make such blocks with different semantics explicit, which would fix the problem of breaking the intention of who wrote that block and whoever read that code, expecting normal Ruby block semantics, which includes seeing updated outer variables.
Related: #21033 https://bugs.ruby-lang.org/issues/18243#note-5

Extracted from https://bugs.ruby-lang.org/issues/21033#note-14



-- 
https://bugs.ruby-lang.org/
______________________________________________
 ruby-core mailing list -- ruby-core@ml.ruby-lang.org
 To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
 ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/


In This Thread