From: "mame (Yusuke Endoh)" Date: 2022-02-09T08:58:34+00:00 Subject: [ruby-dev:51162] [Ruby master Bug#18578] Hash#shift を繰り返していると ruby が無応答になる。 Issue #18578 has been updated by mame (Yusuke Endoh). メモ:entries_bound は使用中のビン(DELETEDになったビンを含む)の数に(ほぼ)対応していて、これをみてテーブルをリビルドしている(rebuild_table_if_necessary)。空のハッシュに対する Hash#shift はなぜか entries_bound を 0 にしているので、リビルドすべきタイミングを逃し、ビンがすべて使用中になった状態で空きビンを探そうとするので無限ループに陥っていた(find_table_bin_ind)。 ---------------------------------------- Bug #18578: Hash#shift を繰り返していると ruby が無応答になる。 https://bugs.ruby-lang.org/issues/18578#change-96432 * Author: Anonymous * Status: Open * Priority: Normal * Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- はじめまして ds14050 といいます。最近スクリプトではなくインタープリタが 原因で ruby の応答がなくなるケースに遭遇したと思いました。確認をお願いで きますか。 <<<以下再現スクリプト # ウチではだいたい 20 から 30 回で "empty?: true" を最後にして止まる。 # ウチの Ruby-2.5: ruby 2.5.5p157 (2019-03-15 revision 67260) [x64-mingw32] # ウチの Ruby-2.7: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x64-mingw32] # ウチの Ruby-3.1: ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x64-mingw-ucrt] H = {} 100.times{|n| while H.size < n k = Random.rand 0..1<<30 H[k] = 1 # たぶんここで止まる。 end warn "size: #{H.size} before shifting." 0 while H.shift warn "empty?: #{H.empty?}" } warn :exit >>> Hash に要素を詰めて空にしてを 100 回繰り返すスクリプトです。3.1 を含む3 つのバージョンでほぼ確実に止まる(ruby.exe がビジー状態で終了しない)こと を確認しています。2.5 より古い Ruby-1.9 では止まらずに最後まで実行が完了 しました。 Hash を空にする方法として 0 while H.shift の代わりに H.shift until H.empty? を選ぶと最後まで実行が完了するようになったことから呼び出すメ ソッドを揃えて比較したところ、Hash が空になったあとの余分な Hash#shift が何か悪さをしているように思えます。 また、デバッグプリントを増やして確認したところ実際に停止しているのは Hash#shift の行ではなく H[k] = 1 の行であるようでした。 よろしくお願いします。 -- https://bugs.ruby-lang.org/