C23 has qualifier-preserving standard library functions, so calling
strchr with a `const char *` will return a `const char *`. We can change
the type of the local variables because we don't mutate the strings.
[PATCH] fix ENV.keys encoding on windows
Fix the encoding of ENV.keys elements to UTF-8 on windows.
They contain UTF-8 byte sequences with locale encoding.
[PATCH] [Bug #20958] Fix test_keys_encoding on hosts without en_US.UTF-8
`EnvUtil.invoke_ruby` forces the C locale on the child process, so the
test set `LC_ALL=en_US.UTF-8` to get a UTF-8 locale back. That locale
is not generated on the debian11 chkbuild host, where `setlocale` falls
back to C and the ENV key comes out as ASCII-8BIT instead of the
default internal encoding. Inherit the locale of the parent process
instead, and omit the test when that locale is not UTF-8.
https://rubyci.s3.amazonaws.com/debian11/ruby-master/log/20260725T093003Z.fail.html.gz
* While perusing code in hash.c I found it suspicious that ar_find_entry_hint()
didn't reread bound in the loop and yet called arbitrary code through #eql?.
* ar_find_entry_hint() before this commit would not check if bound or the storage (AR->ST) changed
and would return a bin index which is not correct to access.
* Check bound in the loop so it's always up-to-date.
* Return RHASH_AR_TABLE_CONVERTED_TO_ST_TABLE when converted to st_table
and make callers retry the operation as a st_table.
[Bug #22120]
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit c88430e187)
[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.
If the TZ environment variable is not set, the time zone names
retrieved from the system are localized for UI display and may vary
across editions and language packs for the same time zone.
Use the time zone IDs that are invariant across environments instead.
The inspect format was intentionally changed as an outcome of
[Bug #20433] [ruby-core:118668], but some documentation update
was missing, as [Bug #20962] pointed out. Update some output
examples that clearly use Hash#inspect.
If a Hash which is empty or only using literals is frozen, we detect
this as a peephole optimization and change the instructions to be
`opt_hash_freeze`.
[Feature #20684]
Co-authored-by: Jean Boussier <byroot@ruby-lang.org>
28a1c4f33e seems to call an improper
ensure clause. [Bug #20655]
Than fixing it properly, I bet it would be much better to simply revert
that commit. It reduces the unneeded complexity. Jumping into a block
called by a C function like Hash#each with callcc is user's fault.
It does not need serious support.
The macro SafeStringValue() became just StringValue() in c5c05460ac,
and it is deprecated nowadays.
This patch replaces remaining macro usage. Some occurrences are left in
ext/stringio and ext/win32ole, they should be fixed upstream.
The macro itself is not deleted, because it may be used in extensions.
[Bug #20145]
Before this commit, both copy_compare_by_id and hash_copy will create a
copy of the ST table, so the ST table created in copy_compare_by_id will
be leaked.
h = { 1 => 2 }.compare_by_identity
10.times do
1_000_000.times do
h.select { false }
end
puts `ps -o rss= -p #{$$}`
end
Before:
110736
204352
300272
395520
460704
476736
542000
604704
682624
770528
After:
15504
16048
16144
16256
16320
16320
16752
16752
16752
16752
If a Hash is non-empty, there's no point calling `ar_force_convert_table`. We'll be immediately discarding that new st table, and replacing it with the new `identtable` st table that we're stealing out of `tmp`.
For non-empty Hashes, this function needs to rehash all the stored values (using the new `compare` and `hash` functions from `identhash`). It does so by writing into a newly allocated `tmp` Hash, and then transferring ownership of its st table into `self`.
For empty Hashes, we can skip allocating this `tmp`, because there's nothing to re-hash. We can just modify our new st table's `type` in-place.
* delete `ar_try_convert` but use `ar_force_convert_table`
to make program simple.
* `ar_force_convert_table` checks hash modification while
calling `#hash` method with the following strategy:
1. copy keys (and vals) of ar_table
2. calc hashes from keys
3. check copied keys and hash's keys. if not matched, repeat from 1
fix [Bug #20050]
st.c redefines malloc and free to be ruby_xmalloc and ruby_xfree, so
when this was copied into hash.c it ended up mismatching an xmalloc with
a regular free, which ended up inflating oldmalloc_increase_bytes when
hashes were freed by minor GC.
ar_table may be converted to st_table by `ar_force_convert_table`.
If the conversion occurs during the iteration of ar_table, the iteration
may lead to memory corruption.
This change prevents the catastrophy by throwing an exception when the
conversion is detected.
This issue is reported by [SuperS](https://hackerone.com/superss)