Bug #2575
closeda test fail for IO#readpartial is broken on *BSD
Description
=begin
IO#readpartialのテストに失敗します。確認はNetBSD 5.0_STABLE, current (5.99.22)とFreeBSD 7.2-STABLE、いずれもi386環境で行いました。
test/ruby/test_io.rb の test_readpartial_pos() に、
open("foo", "w") {|f| f << "abc" }
open("foo") {|f|
f.seek(0)
assert_equal("ab", f.readpartial(2))
assert_equal(2, f.pos)
}
といったテストがあります。ここで、f.posの結果がゼロとなってテストに失敗します。直前のf.seek(0)を削除するとテストに成功するようになりますが、この有無で結果が変わってはなりません。
io.cのio_getpartial()では、
- read_buffered_data()でFILE構造体に読み込み済みのデータを読んでみる。
- 読み込み済みのデータがなければ、
2.1 read(2)でデータをFILE構造体に読み込む。
2.2 後でfflush(3)を呼び出してFILE構造体の内容の整合性が取れ(ることを
期待してい)る。
といったことをしています。2.1の処理は、
merge revision(s) 21913:
* io.c (io_getpartial): fflush after read for updating pos in FILE.
not portable, I guess. [ruby-core:21561]
とコミットされています。ここで推測されているように実際に移植性はありません。そもそも、fflush(3)で構造体の内容が適切になされると期待することに無理がある気もします。
*BSDのFILE構造体(DragonFlyは不明)には、
o ファイル中のオフセットを示す構造体メンバ _offset があります。
o 構造体メンバ_flagsのフラッグ値には、_offsetの値が実際に有効かどうかを
示す __SOFF という値があります。
そして、この問題は以下のように説明できます。
(1) f.seek(0)を呼び出すとfseeko(3)が呼び出されて、_offsetに値と__SOFFが
フラッグが設定されます。このときの _offset が後のf.tellの戻り値となっ
ています。
(2) f.seek(0)を呼び出さないと、f.tellの呼び出された時点で_offsetに値と
__SOFFが設定されるため、期待した値が返ることになります。
解決策としては、fflush(3)の呼び出しに代えて__SOFFをアンセットしてからftello(3)を呼び出すといったことが考えられます。取り敢えずのパッチで、問題が解決することを確認しました。
=end
Files