Project

General

Profile

Actions

Bug #5429

closed

64ビットなFreeBSDのioctlでビット31が1なリクエストの時の不具合

Added by metanest (Makoto Kishimoto) over 12 years ago. Updated over 10 years ago.

Status:
Closed
Target version:
-
ruby -v:
-
Backport:
[ruby-dev:44589]

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の受け入れるべき引数の値の範囲の
問題などがあるので、とりあえずチケットのみ登録します。


Related issues 2 (0 open2 closed)

Related to Backport193 - Backport #6127: IO#ioctl range error in 1.9.3Closednaruse (Yui NARUSE)03/10/2012Actions
Has duplicate Ruby master - Bug #6427: ruby ioctl: Error integer 2148012656 too big to convert to `int'Rejected05/12/2012Actions

Updated by naruse (Yui NARUSE) over 12 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) over 12 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) over 12 years ago

途中までやってみましたが、ioctlはunsigned longでもfcntl はintなので、もうちょっと工夫がいりますね。

Updated by kosaki (Motohiro KOSAKI) over 12 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) over 12 years ago

よく見たら、fcntlのときに IOCPARM_LEN を呼んでるのはバグですね。ioctlのcmdしか IOCPARM_LEN でデコードできません。これが動くのはfcntlの引数にstring渡す人が一人もいなかったからでしょうね。

Actions #6

Updated by kosaki (Motohiro KOSAKI) over 12 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
Actions #7

Updated by kosaki (Motohiro KOSAKI) over 12 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) over 12 years ago

なかださんがミスを直してくれました。
r33724, r33727 も追加で。

Updated by kosaki (Motohiro KOSAKI) over 12 years ago

Chikanaga さんのレビューコメントを反映し、r33728 をコミットしました。

Updated by ayumin (Ayumu AIZAWA) over 12 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.

  1. 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) over 12 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) over 12 years ago

2011年11月14日11:25 Tomoyuki Chikanaga :

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) over 12 years ago

これでバックポート対象に r33752, r33753 が追加ですね

Updated by ayumin (Ayumu AIZAWA) over 12 years ago

近永さんありがとうございます。
r33753 でなおしておきました。

2011年11月15日1:41 KOSAKI Motohiro :

2011年11月14日11:25 Tomoyuki Chikanaga :

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) over 12 years ago

2011年11月15日1:41 KOSAKI Motohiro :

うーん、あんまり凝ったことをするとまた別の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) over 12 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) about 12 years ago

思ったよりもパッチが大きくなったのと元報告者のKishimoto さんからFreeBSDでのフィードバックが得られていないので1.9.3ではrejectにしようかと考えています。ご意見お聞かせください

Updated by naruse (Yui NARUSE) about 12 years ago

  • Assignee changed from yugui (Yuki Sonoda) to metanest (Makoto Kishimoto)
  • Priority changed from 3 to Normal

Updated by metanest (Makoto Kishimoto) about 12 years ago

とりあえず今気づきましたというACKだけ。
特に何か「これは困る」というものではないので、
1.9.3へのバックポートは、なしで、私はかまいません。

trunkで問題が起きないことを確認すればいいんですよね?
(さて問題のスクリプトはハードディスクのどこだっけ……)

Updated by metanest (Makoto Kishimoto) about 12 years ago

確認しました。
最初の報告にあるような、ウォーニングシステムメッセージは出なくなっています。
クローズお願いします。

Actions #21

Updated by naruse (Yui NARUSE) about 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) about 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) over 10 years ago

  • ruby -v set to -

メモ: Linux の ioctl の manpage がなおったらしい
Linux's bug
http://mkosaki.blog46.fc2.com/blog-entry-1246.html

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0