Bug #2747

io.dup doesn't handle pos properly

Added by kosaki (Motohiro KOSAKI) over 2 years ago. Updated about 1 year ago.

[ruby-dev:40424]
Status:Rejected Start date:02/15/2010
Priority:Normal Due date:
Assignee:- % Done:

0%

Category:core
Target version:2.0.0
ruby -v:ruby 1.9.2dev (2010-02-03) [x86_64-linux]

Description

記録のために、IRCから転記します。

duptest.rb
-----------------------------
f1 = File.new("foo.txt")
f2 = f1.dup()
p f1.pos
p f2.gets
p f1.pos
p f2.pos

foo.txt
-------------
1
2
3

このようなテストプログラムを実行すると、

0
"1\n"
6
2

となります。dupはf1とf2で同じposが返るべきであるし、6はどこから出てきたのかよく分かりません。

Related issues

related to ruby-trunk - Bug #2516: IO#reopen Compatibility (original: [ruby-dev:39479]) Rejected 12/23/2009

History

Updated by kosaki (Motohiro KOSAKI) over 2 years ago

#2516 と関連しています

Updated by kosaki (Motohiro KOSAKI) over 2 years ago

1.8.6での挙動

% /usr/bin/ruby -v duptest.rb
ruby 1.8.6 (2009-08-04 patchlevel 383) [x86_64-linux]
0
"1\n"
0
2


f1とf2のposがずれているので、これもおかしい

Updated by kosaki (Motohiro KOSAKI) over 2 years ago

6の秘密はstraceが教えてくれている

dup(4)                                  = 5
lseek(4, 0, SEEK_CUR)                   = 0
lseek(5, 0, SEEK_SET)                   = 0
lseek(4, 0, SEEK_CUR)                   = 0
write(1, "0\n", 20
)                      = 2
read(5, "1\n2\n3\n", 8192)              = 6
write(1, "\"1\\n\"\n", 6"1\n"
)               = 6
lseek(4, 0, SEEK_CUR)                   = 6
write(1, "6\n", 26
)                      = 2
lseek(5, -4, SEEK_CUR)                  = 2
lseek(5, 0, SEEK_CUR)                   = 2
write(1, "2\n", 22
)


read(f2, buf, 8192)でバッファリング読み込みしたあと、オフセットを戻すのを忘れて
lseek(f1, 0, SEEK_CUR) でposを読み込むのでファイル終端のposが得られている。

Updated by mame (Yusuke Endoh) over 2 years ago

kosaki さん
遠藤です。

2010年2月15日21:40 Motohiro KOSAKI <redmine@ruby-lang.org>:
> 6の秘密はstraceが教えてくれている
>
*snip*
>
> read(f2, buf, 8192)でバッファリング読み込みしたあと、オフセットを戻すのを忘れて
> lseek(f1, 0, SEEK_CUR) でposを読み込むのでファイル終端のposが得られている。


dup の前後でバッファを共有していないのが問題ですよね。

しかし、バッファは現在 rb_io_t 構造体に直接埋め込まれてしまっています。
rb_io_t の定義を変えないと、バッファを共有させるのは難しい気がします。

rb_io_t は公開 API であり、etc/ 以下だけでなくいくつかの 3rd party の
拡張ライブラリで実際に使われています。下手にいじると、バイナリ互換性の
問題が起きてしまいそうです。


設計上のバグなんですが、バイナリ互換性を崩してでも修正したいほど重大な
問題ではないと思います。なので 1.9.2 では、

  「IO#dup や reopen の元になった IO はもう使ってはいけない (close
    しかしてはならない) 。バグだが当面 WONTFIX である。」

と宣言してしまい、いつか他の要因でバイナリ互換性を捨てる際 (遅くとも
2.0) に、あわせて修正するのがいいのではないかと思いました。


もちろん、バイナリ互換性に影響のない形で修正できるなら、それが一番いい
と思います (ただし、煩わしい workaround のせいでひどくメンテナンス性が
落ちるとしたら考えもの) 。

今考えている修正方針の案などがあれば教えてください。

-- 
Yusuke ENDOH <mame@tsg.ne.jp>

Updated by mame (Yusuke Endoh) about 2 years ago

  • Status changed from Open to Rejected
遠藤です。

1.9.2 では仕様ということで reject します。([ruby-core:28335] 他)

わかりにくい挙動なことは確かなので、1.9.3 以降での改善を Feature
チケットとして別に登録しておきます。

-- 
Yusuke Endoh <mame@tsg.ne.jp>

Also available in: Atom PDF