[ruby-dev:49894] [Ruby trunk Bug#13004] rb_get_kwargs はバグってないでしょうか?
From:
nobu@...
Date:
2016-12-04 08:54:14 UTC
List:
ruby-dev #49894
Issue #13004 has been updated by Nobuyoshi Nakada.
Description updated
Backport changed from 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: REQUIRED, 2.2: REQUIRED, 2.3: REQUIRED
----------------------------------------
Bug #13004: rb_get_kwargs はバグってないでしょうか?
https://bugs.ruby-lang.org/issues/13004#change-61865
* Author: Makoto Kishimoto
* Status: Closed
* Priority: Normal
* Assignee:
* ruby -v:
* Backport: 2.1: REQUIRED, 2.2: REQUIRED, 2.3: REQUIRED
----------------------------------------
きしもとです
拡張ライブラリで `rb_get_kwargs` を使おうとしたところ、いくつか変に
感じた点がありましたので、確認をお願いしたくこちらにメイルします。
もしバグでしたらチケットにまとめます。
(1) `values`を渡すと、全て変更(初期化)される。
extension(.ja).rdoc には、
> ```
> ... If an optional key is not present in
> +keyword_hash+, the corresponding element in +values+ is not changed.
> ```
> ```
> ...省略可能キーワー
> ドがない場合は,values中の対応する要素は変更されません.
> ```
とあるが、コードでは、
```C
1866 if (values) {
1867 for (j = 0; j < required + optional; j++) {
1868 values[j] = Qundef;
1869 }
1870 }
```
となっていて、`values`が非`NULL`であれば一律に `Qundef` で初期化している。
(2) "unknown keyword" `ArgumentError` を `raise` しそこねることがある。
該当部分のコードはこうなっていて、
```C
1898 if (!rest && keyword_hash) {
1899 if (RHASH_SIZE(keyword_hash) > (unsigned int)j) {
1900 unknown_keyword_error(keyword_hash, table, required+optional);
1901 }
1902 }
```
ここで `j` には認識されたキーワード引数の個数が入っていて、`values`が
`NULL`の時には`keyword_hash`の中身が変更されず、恐らくその意図通りの
動作になるが、`values`が非`NULL`の場合は`keyword_hash`からエントリが
除かれるため、認識できなかった引数があってもこのチェックを通り
抜けてしまうことがある(`extract_kwarg`マクロも参照)。
```C
1855 #define extract_kwarg(keyword, val) \
1856 (key = (st_data_t)(keyword), values ? \
1857 st_delete(rb_hash_tbl_raw(keyword_hash), &key, (val)) : \
1858 st_lookup(rb_hash_tbl_raw(keyword_hash), key, (val)))
```
(3) 使用されない要素は`keyword_hash`に残されるだけで、別には保存されない。
extension(.ja).rdoc には、
> ```
> If +optional+ is negative, rest of +keyword_hash+ are stored in the
> next to optional +values+ as a new Hash, ...
> ```
> ```
> keyword_hashに使用されない要素がある場合は,optionalが負なら
> 新しいHashとして省略可能引数の次に保存されますが,...
> ```
とあるが、該当するコードが見つからない。またもし、そのような動作を
するのであれば、ドキュメントのこの関数に関する記述の冒頭部に、
`values`のサイズは必ず「`required+optional + 1`」以上でなければ
ならないと書く必要があるように思う。
--
https://bugs.ruby-lang.org/