From: merch-redmine@... Date: 2021-08-11T22:01:12+00:00 Subject: [ruby-core:104892] [Ruby master Bug#17507] Regexp capture groups ignored sometimes in some multithreaded environments (possible race condition) Issue #17507 has been updated by jeremyevans0 (Jeremy Evans). This issue is due to a race condition because the MatchData object is passed indirectly through the backref. I've submitted a pull request to fix it: https://github.com/ruby/ruby/pull/4734 I think it's likely that similar Regexp methods have a similar issue, though I haven't done any testing in that area. ---------------------------------------- Bug #17507: Regexp capture groups ignored sometimes in some multithreaded environments (possible race condition) https://bugs.ruby-lang.org/issues/17507#change-93252 * Author: byteit101 (Patrick Plenefisch) * Status: Open * Priority: Normal * ruby -v: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN ---------------------------------------- Same behavior from 2.6-3.0 OS: Debian 10 Ruby Script: ``` ruby TargetStr = "a-x-foo-bar-baz-z-b" worker = lambda do # For more hits, use File.read here instead of TargetStr m = TargetStr.match(/foo-([A-Za-z0-9_\.]+)-baz/) # more cases in the []+ means more hits raise "Error, #{m.inspect}" if m[1].nil? File.exist? "/tmp" TargetStr.gsub(/foo-bar-baz/, "foo-abc-baz") # must match the same as the first match end def threaded_test(worker) 6.times.map {Thread.new {10_000.times {worker.call}}}.each(&:join) end threaded_test(worker) # must be a function calling a block or proc or lambda. Change any of that and it doesn't hit this puts "No Error Hits" ``` Result of script (number of exceptions varies per-run): ``` # terminated with exception (report_on_exception is true): bug.rb:6:in `block in
': Error, # (RuntimeError) from bug.rb:12:in `block (3 levels) in threaded_test' from bug.rb:12:in `times' from bug.rb:12:in `block (2 levels) in threaded_test' # terminated with exception (report_on_exception is true): bug.rb:6:in `block in
': Error, # (RuntimeError) from bug.rb:12:in `block (3 levels) in threaded_test' from bug.rb:12:in `times' from bug.rb:12:in `block (2 levels) in threaded_test' # terminated with exception (report_on_exception is true): bug.rb:6:in `block in
': Error, # (RuntimeError) from bug.rb:12:in `block (3 levels) in threaded_test' from bug.rb:12:in `times' from bug.rb:12:in `block (2 levels) in threaded_test' bug.rb:6:in `block in
': Error, # (RuntimeError) from bug.rb:12:in `block (3 levels) in threaded_test' from bug.rb:12:in `times' from bug.rb:12:in `block (2 levels) in threaded_test' ``` Expected Result: ``` No Error Hits ``` Details: As is, it usually errors (most of the time it fails about 300-500 iterations in) A success is what is expected, m == #<MatchData "foo-bar-baz" 1:"bar"> An error is when m == #<MatchData "foo-bar-baz"> (no capture saved) * If threaded_test is only one thread (1.times) it always works. For more than one thread, it usually errors. * If File.exist? is removed, it always works. * If the gsub is removed, it always works. * If the gsub is changed to not match the match() call, it always works. * If the match expression is simpler (/foo-(bar)-baz/, or even /foo-([a-z]+)-baz/), it usually works. * If the threaded_test is not a method, but executed inline (ie, comment out the def, end, call, on lines 11 & 13-14) it always works. * If worker is a block, or a lambda (as provided), it usually errors. * If worker is put inline into the 10_000.times call, it always works. * If TargetStr matches on index 0, it always works. -- https://bugs.ruby-lang.org/ Unsubscribe: