[ruby-core:108292] [Ruby master Bug#18649] Enumerable#first breaks out of the incorect block when across threads
From:
"nobu (Nobuyoshi Nakada)" <noreply@...>
Date:
2022-04-19 09:46:11 UTC
List:
ruby-core #108292
Issue #18649 has been updated by nobu (Nobuyoshi Nakada).
jeremyevans0 (Jeremy Evans) wrote in #note-2:
> With the block uncommented, the yielding thread raises LocalJumpError, but the calling thread gets the yielded value without an exception.
Isn't it natural because the test code rescues but doesn't re-raise?
----------------------------------------
Bug #18649: Enumerable#first breaks out of the incorect block when across threads
https://bugs.ruby-lang.org/issues/18649#change-97313
* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* ruby -v: ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux]
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN
----------------------------------------
```ruby
def synchronize
yield
end
def execute(task)
success = true
value = reason = nil
end_sync = false
synchronize do
begin
p :before
value = task.call
p :never_reached
success = true
rescue StandardError => ex
p [:rescue, ex]
reason = ex
success = false
end
end_sync = true
p :end_sync
end
p :should_not_reach_here! unless end_sync
[success, value, reason]
end
def foo
Thread.new do
result = execute(-> { yield 42 })
p [:result, result]
end.join
end
p [:first, to_enum(:foo).first]
```
This code should raise LocalJumpError (and that should get `rescue`'d) because Enumerable#first can't break/return across threads.
But instead, it seems to break out of the block given to `synchronize`, which is clearly wrong.
That case is shown as `:should_not_reach_here!`.
Results:
```
ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x86_64-linux]
:before
:should_not_reach_here!
[:result, [true, nil, nil]]
[:first, 42]
ruby 3.1.1p18 (2022-02-18 revision 53f5fc4236) [x86_64-linux]
:before
:should_not_reach_here!
[:result, [true, nil, nil]]
[:first, 42]
```
CRuby (3.0 and 3.1) print `:should_not_reach_here!`, which is a semantic bug, if we get to the end of `execute` we should have gotten to the end of the block given to synchronize.
This is related to #18474 and https://github.com/ruby-concurrency/concurrent-ruby/issues/931.
--
https://bugs.ruby-lang.org/
Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>