Bug #21357
closedCrash in Hash#merge! with ruby-dev in rubocop-rspec test suite
Description
I've encountered crahses on ruby-head in recent days, related to hash methods like merge
and merge!
. I can now reproduce it locally while running the rubocop-rspec test suite:
- Clone https://github.com/rubocop/rubocop-rspec
- Run
NO_COVERAGE=1 bundle exec rake spec
I attached the crash report. I want to reduce this down but have no idea how. The crash is very consistent for me though, it doesn't take very long for it to happen (only a few seconds usually).
There were related(?) changes to hash like https://bugs.ruby-lang.org/issues/21333, maybe related.
Files
Updated by Earlopain (Earlopain _) 4 days ago
I reduced it down significantly:
require "yaml"
YML = <<~YML
foo:
- bar: abc
baz: def
bat: ghi
YML
x = 1500 # lower numbers don't consistently crash
(0..x).each_with_object({}) do |_i, hash|
hash.merge!(YAML.safe_load(YML)) do |_key, first, second|
first.concat(second)
end
end
This doesn't have much in common with the real code anymore, but the crash is the same.
Updated by dodecadaniel (Daniel Colson) 3 days ago
Possible fix https://github.com/ruby/ruby/pull/13404 (if tests pass 🤞🏻)
Updated by dodecadaniel (Daniel Colson) 3 days ago
- Status changed from Open to Closed
Applied in changeset git|056497319658cbefe22351c6ec5c9fa6e4df72bd.
[Bug #21357] Fix crash in Hash#merge with block
Prior to https://github.com/ruby/ruby/commit/49b306ecb9e2e9e06e0b1590bacc5f4b38169c3c
the optional_arg
passed from rb_hash_update_block_i
to tbl_update
was a hash value (i.e. a VALUE). After that commit it changed to an
update_call_args
.
If the block sets or changes the value, tbl_update_modify
will set the
arg.value
back to an actual value and we won't crash. But in the case
where the block returns the original value we end up calling
RB_OBJ_WRITTEN
with the update_call_args
which is not expected and
may crash.
arg.value
appears to only be used to pass to RB_OBJ_WRITTEN
(others
who need the update_call_args
get it from arg.arg
), so I don't think
it needs to be set to anything upfront. And tbl_update_modify
will set
the arg.value
in the cases we need the write barrier.
Updated by Earlopain (Earlopain _) 3 days ago
Thanks! Works nicely.
Updated by byroot (Jean Boussier) 3 days ago
- Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED
Updated by nagachika (Tomoyuki Chikanaga) 1 day ago
- Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: REQUIRED to 3.2: UNKNOWN, 3.3: REQUIRED, 3.4: REQUIRED
I'm going to backport the fix for #21333, and fill Backport field REQUIRED for 3.3.
Updated by nagachika (Tomoyuki Chikanaga) 1 day ago
- Backport changed from 3.2: UNKNOWN, 3.3: REQUIRED, 3.4: REQUIRED to 3.2: UNKNOWN, 3.3: DONE, 3.4: REQUIRED
ruby_3_3 24c994b91a67f0023e8fe22a5428581110564332 merged revision(s) 056497319658cbefe22351c6ec5c9fa6e4df72bd.