Bug #5429
closed64ビットなFreeBSDのioctlでビット31が1なリクエストの時の不具合
Description
64ビットなFreeBSD 8において、ioctl(2)のプロトタイプ宣言は以下のように
なっていて、
int
ioctl(int d, unsigned long request, ...);
ビット31(32ビットであればMSB)が1なリクエストでも、上位ビットがゼロ拡張
された64ビット値を期待しています。
それに対しrubyのtrunkではIO#ioctlの引数の値の範囲は符号付き32ビットに
なっていて、最終的にio.cのnogvl_io_cntlに、intを引数としたioctlの
呼び出しがあり、ビット31が1なリクエストは符号拡張されて、ioctlを呼ぶことに
なり、
その結果システムメッセージに、(SNDCTL_DSP_SPEED の例)
WARNING pid 82043 (initial thread): ioctl sign-extension ioctl ffffffffc0045002
というようなウォーニングが出ます(一応目的の動作はしている)。
回避する修正は (unsigned) とキャストを入れればいいように思うのですが、
他のプラットフォームでの問題や、IO#ioctlの受け入れるべき引数の値の範囲の
問題などがあるので、とりあえずチケットのみ登録します。
Updated by naruse (Yui NARUSE) about 13 years ago
ざっと調べてみましたが、
== POSIX
int ioctl(int fildes, int request, ... /* arg */);
http://pubs.opengroup.org/onlinepubs/9699919799/functions/ioctl.html
== AIX
int ioctl (fd, request, .../arg/)
int fd;
int request;
int .../arg/;
http://publib.boulder.ibm.com/infocenter/aix/v6r1/topic/com.ibm.aix.commtechref/doc/commtrf2/ioctl.htm
== Solaris
int ioctl(int fildes, int request, /* arg */ ...);
http://download.oracle.com/docs/cd/E19963-01/html/821-1463/ioctl-2.html
== HP-UX
int ioctl(int fildes, int request, ... /* arg */);
http://nixdoc.net/man-pages/HP-UX/man2/ioctl.2.html
== Tru64
int ioctl(
int fildes,
int request,
... /* arg */ );
http://nixdoc.net/man-pages/Tru64/man2/ioctl.2.html
== IRIX
int ioctl (int fildes, int request, ...);
http://nixdoc.net/man-pages/irix/man2/ioctl.2.html
== Linux
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
manpageは以下の通りだが、実際のヘッダは異なる。
int ioctl(int d, int request, ...);
https://www.kernel.org/doc/man-pages/online/pages/man2/ioctl.2.html
== NetBSD
int ioctl(int d, unsigned long request, ...);
http://netbsd.gw.com/cgi-bin/man-cgi?ioctl+2+NetBSD-current
== OpenBSD
int ioctl(int d, unsigned long request, ...);
http://www.openbsd.org/cgi-bin/man.cgi?query=ioctl&sektion=2&format=html
== Darwin
int ioctl(int fildes, unsigned long request, ...);
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/ioctl.2.html
いやー、やっぱり Linux はダメですね!ってのはおいといて、
商用 UNIX は int、それ以外は unsigned long っぽいですね。
Updated by kosaki (Motohiro KOSAKI) about 13 years ago
- ruby -v changed from ruby 1.9.4dev (2011-10-09 trunk 33439) [x86_64-freebsd8.2] to -
== Linux
extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
manpageは以下の通りだが、実際のヘッダは異なる。
int ioctl(int d, int request, ...);
https://www.kernel.org/doc/man-pages/online/pages/man2/ioctl.2.htmlいやー、やっぱり Linux はダメですね!ってのはおいといて、
商用 UNIX は int、それ以外は unsigned long っぽいですね。
うう・・すいません
Linuxのmanはこちらであずかります。man pageメンテナが夜逃げ中なので
ちょっと時間かかるかも
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
途中までやってみましたが、ioctlはunsigned longでもfcntl はintなので、もうちょっと工夫がいりますね。
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
fcntl は全プラットフォーム int のようである。めでたい
== Linux
int fcntl(int fd, int cmd, ... /* arg */ );
https://www.kernel.org/doc/man-pages/online/pages/man2/fcntl.2.html
== FreeBSD
int fcntl(int fd, int cmd, ...);
http://fuse4bsd.creo.hu/localcgi/man-cgi.cgi?fcntl+2
== NetBSD
int fcntl(int fd, int cmd, ...);
http://www.daemon-systems.org/man/fcntl.2.html
== OpenBSD
int fcntl(int fd, int cmd, ...);
http://nixdoc.net/man-pages/OpenBSD/fcntl.2.html
== AIX
int fcntl(int descriptor,
int command,
...)
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fapis%2Ffcntl.htm
== Solaris
int fcntl(int fildes, int cmd, /* arg */ ...);
http://download.oracle.com/docs/cd/E19963-01/html/821-1463/fcntl-2.html
== HP-UX
int fcntl(int fildes, int cmd, ... /* arg */);
http://nixdoc.net/man-pages/HP-UX/man2/fcntl.2.html
== Tru64
int fcntl(
int filedes,
int request [,
int argument |,
struct flock *argument |,
advfs_opT argument] ); int dup(
int filedes ); int dup2(
int old,
int new );
http://nixdoc.net/man-pages/Tru64/man2/fcntl.2.html
== IRIX
int fcntl (int fildes, int cmd, ... /* arg */);
http://nixdoc.net/man-pages/irix/man2/fcntl.2.html
== Darwin
int fcntl(int fildes, int cmd, ...);
http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/fcntl.2.html
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
よく見たら、fcntlのときに IOCPARM_LEN を呼んでるのはバグですね。ioctlのcmdしか IOCPARM_LEN でデコードできません。これが動くのはfcntlの引数にstring渡す人が一人もいなかったからでしょうね。
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r33716.
Makoto, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- io.c (ioctl_req_t): Type of req argument of ioctl() depend on platform.
Moreover almost all linux ioctl can't be represented by 32bit integer
(i.e. MSB is 1). We need wrap ioctl argument type.
[Bug #5429] [ruby-dev:44589] - io.c (struct ioctl_arg): ditto.
- io.c (rb_ioctl): ditto.
- test/ruby/test_io.rb (test_ioctl_linux): add a testcase for ioctl
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
- Tracker changed from Bug to Backport
- Project changed from Ruby master to Backport193
- Category deleted (
core) - Status changed from Closed to Assigned
- Assignee set to yugui (Yuki Sonoda)
- Target version deleted (
2.0.0)
r33711 - r33721 のバックポートを依頼します
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
なかださんがミスを直してくれました。
r33724, r33727 も追加で。
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
Chikanaga さんのレビューコメントを反映し、r33728 をコミットしました。
Updated by ayumin (Ayumu AIZAWA) almost 13 years ago
あいざわです
r33720で追加されたテストケースが Mac OSX SnowLeopardで失敗します。
以下のパッチ動くようにはなりますが、これってTempfile#openのバグなんでしょうか?
git diff --no-prefix
diff --git test/ruby/test_io.rb test/ruby/test_io.rb
index 6382cd7..e1ec389 100644
--- test/ruby/test_io.rb
+++ test/ruby/test_io.rb
@@ -1919,7 +1919,8 @@ End
end
def test_fcntl_dupfd
- Tempfile.open(self.class.name) do |f|
- Tempfile.new(self.class.name) do |f|
-
f.open fd = f.fcntl(Fcntl::F_DUPFD, 500) begin assert_equal(fd, 500)
= パッチあてるまえの実行結果
make test-all TESTS='test/ruby/test_io.rb'
./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext
-- --disable-gems "./test/runner.rb" --ruby="./miniruby -I./lib -I.
-I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems"
test/ruby/test_io.rb
Run options: "--ruby=./miniruby -I./lib -I. -I.ext/common
./tool/runruby.rb --extout=.ext -- --disable-gems"
Running tests:¶
...........................................E...................................................................
Finished tests in 4.617944s, 24.0367 tests/s, 122.3488 assertions/s.
- Error:
test_fcntl_dupfd(TestIO):
Errno::EINVAL: Invalid argument -
/var/folders/uN/uN7thnp5EriPwEKPnKdfvk+++TI/-Tmp-/TestIO20111114-57558-itj964
/users/ayumin/github/ruby/test/ruby/test_io.rb:1923:in `block in
test_fcntl_dupfd'
111 tests, 565 assertions, 0 failures, 1 errors, 0 skips
ruby -v: ruby 2.0.0dev (2011-11-14 trunk 33748) [x86_64-darwin10.8.0]
make: *** [yes-test-all] Error 1
Updated by nagachika (Tomoyuki Chikanaga) almost 13 years ago
あいざわさんのパッチだと、Tempfile.new がブロックを yield しないので、assert を通っていないだけのようです。
SnowLeopard の man fcntl によると
[EINVAL] Cmd is F_DUPFD and arg is negative or greater than the maximum allowable number (see getdtablesize(2)).
で getdtablesize() は 256 を返すのでとりあえず 500 -> 255 にすると通るようになりました。
500 というのは他の open 済みの fd と重複しない程度に大きな数字ということだと思うので、とりあえず 255 にしてしまってもいいでしょうか。ちゃんと空き fd を確保してそこに dup するようにしたほうがいいのかもしれませんが。
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
2011年11月14日11:25 Tomoyuki Chikanaga nagachika00@gmail.com:
Issue #5429 has been updated by Tomoyuki Chikanaga.
あいざわさんのパッチだと、Tempfile.new がブロックを yield しないので、assert を通っていないだけのようです。
SnowLeopard の man fcntl によると
[EINVAL] Cmd is F_DUPFD and arg is negative or greater than the maximum allowable number (see getdtablesize(2)).
で getdtablesize() は 256 を返すのでとりあえず 500 -> 255 にすると通るようになりました。
500 というのは他の open 済みの fd と重複しない程度に大きな数字ということだと思うので、とりあえず 255 にしてしまってもいいでしょうか。ちゃんと空き fd を確保してそこに dup するようにしたほうがいいのかもしれませんが。
うーん、あんまり凝ったことをするとまた別のOSの制限にひっかかるかもしれないので
255でお願いできるとうれしいなあ。
fcntlのテストが全然ないから追加したんだけど、ポータブルに動きそうなコマンドって
難しいのよねえ・・
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
これでバックポート対象に r33752, r33753 が追加ですね
Updated by ayumin (Ayumu AIZAWA) almost 13 years ago
近永さんありがとうございます。
r33753 でなおしておきました。
2011年11月15日1:41 KOSAKI Motohiro kosaki.motohiro@gmail.com:
2011年11月14日11:25 Tomoyuki Chikanaga nagachika00@gmail.com:
Issue #5429 has been updated by Tomoyuki Chikanaga.
あいざわさんのパッチだと、Tempfile.new がブロックを yield しないので、assert を通っていないだけのようです。
SnowLeopard の man fcntl によると
[EINVAL] Cmd is F_DUPFD and arg is negative or greater than the maximum allowable number (see getdtablesize(2)).
で getdtablesize() は 256 を返すのでとりあえず 500 -> 255 にすると通るようになりました。
500 というのは他の open 済みの fd と重複しない程度に大きな数字ということだと思うので、とりあえず 255 にしてしまってもいいでしょうか。ちゃんと空き fd を確保してそこに dup するようにしたほうがいいのかもしれませんが。うーん、あんまり凝ったことをするとまた別のOSの制限にひっかかるかもしれないので
255でお願いできるとうれしいなあ。
fcntlのテストが全然ないから追加したんだけど、ポータブルに動きそうなコマンドって
難しいのよねえ・・
Updated by akr (Akira Tanaka) almost 13 years ago
2011年11月15日1:41 KOSAKI Motohiro kosaki.motohiro@gmail.com:
うーん、あんまり凝ったことをするとまた別のOSの制限にひっかかるかもしれないので
255でお願いできるとうれしいなあ。
たしか OpenBSD のデフォルトの file descriptor limit はもっと少なかったような。
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/login.conf.in?rev=1.5
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/mklogin.conf?rev=1.6
によると 128 ですかね。
(履歴を見ると以前は 64 だった?)
それより小さくしといた方が面倒がないんじゃないでしょうか。¶
[田中 哲][たなか あきら][Tanaka Akira]
Updated by kosaki (Motohiro KOSAKI) almost 13 years ago
うーん、あんまり凝ったことをするとまた別のOSの制限にひっかかるかもしれないので
255でお願いできるとうれしいなあ。たしか OpenBSD のデフォルトの file descriptor limit はもっと少なかったような。
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/login.conf.in?rev=1.5
http://www.openbsd.org/cgi-bin/cvsweb/src/etc/mklogin.conf?rev=1.6によると 128 ですかね。
(履歴を見ると以前は 64 だった?)それより小さくしといた方が面倒がないんじゃないでしょうか。
そのようにしました
Updated by kosaki (Motohiro KOSAKI) over 12 years ago
思ったよりもパッチが大きくなったのと元報告者のKishimoto さんからFreeBSDでのフィードバックが得られていないので1.9.3ではrejectにしようかと考えています。ご意見お聞かせください
Updated by naruse (Yui NARUSE) over 12 years ago
- Assignee changed from yugui (Yuki Sonoda) to metanest (Makoto Kishimoto)
- Priority changed from 3 to Normal
Updated by metanest (Makoto Kishimoto) over 12 years ago
とりあえず今気づきましたというACKだけ。
特に何か「これは困る」というものではないので、
1.9.3へのバックポートは、なしで、私はかまいません。
trunkで問題が起きないことを確認すればいいんですよね?
(さて問題のスクリプトはハードディスクのどこだっけ……)
Updated by metanest (Makoto Kishimoto) over 12 years ago
確認しました。
最初の報告にあるような、ウォーニングシステムメッセージは出なくなっています。
クローズお願いします。
Updated by naruse (Yui NARUSE) over 12 years ago
- Tracker changed from Backport to Bug
- Project changed from Backport193 to Ruby master
- Status changed from Assigned to Closed
Makoto Kishimoto wrote:
とりあえず今気づきましたというACKだけ。
特に何か「これは困る」というものではないので、
1.9.3へのバックポートは、なしで、私はかまいません。
じゃあ、なしで。
trunkで問題が起きないことを確認すればいいんですよね?
(さて問題のスクリプトはハードディスクのどこだっけ……)
問題のスクリプトとやらをこのチケットに貼っておいて頂けますか。
Updated by metanest (Makoto Kishimoto) over 12 years ago
たいして長くないので添付じゃなくインラインにしますが、
SNDCTL_DSP_SPEED = 0xc0045002 - 0x1_0000_0000
SNDCTL_DSP_STEREO = 0xc0045003 - 0x1_0000_0000
SNDCTL_DSP_SETFMT = 0xc0045005 - 0x1_0000_0000
AFMT_S16_LE = 0x00000010
open("/dev/dsp", "w:ASCII-8BIT"){|dsp|
ioarg = [AFMT_S16_LE].pack "i!"
dsp.ioctl SNDCTL_DSP_SETFMT, ioarg
ioarg = [44100].pack "i!"
dsp.ioctl SNDCTL_DSP_SPEED, ioarg
ioarg = [1].pack "i!"
dsp.ioctl SNDCTL_DSP_STEREO, ioarg
loop {
buf = STDIN.read 4
break unless buf
buf.force_encoding "ASCII-8BIT"
dsp.write buf
}
}
こんな感じです。CDからリップした、
track01.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 16 bit, stereo 44100 Hz
こんな感じのwavを標準入力から食わせると音が出ます。
Updated by naruse (Yui NARUSE) almost 11 years ago
- ruby -v set to -
メモ: Linux の ioctl の manpage がなおったらしい
Linux's bug
http://mkosaki.blog46.fc2.com/blog-entry-1246.html