GCC Bugzilla で、Mark Mitchell がさまざまなバグの優先順位をつけ直した。そーか、優先順位ってのはそう使うのか。
GCC Bug 22127 と GCC Bug 22429 はめでたく(?) P1 になり、とくに後者は showstopper だそうなので、4.1 までには直るようだ。(まぁ、showstopper なのはこれ以外にもたくさんあるようだけど)
前者も修正が入りそうな気配なのはなかなか良い。
さっそく GCC Bug 22429 が直ったようなので、試してみる... が、直ってない?
... がー。cvs から svn に移行してやがった。
chkbuild の sample/build-gcc-ruby で、とりあえず gcc を svn で取って来るようにしてもう一度試すと、直っているようである。
取って来るだけじゃなくて、cvs でやっているようにいろいろと情報を出すにはどうしたらいいか。ViewCVS による diff へのリンクとか。
でも、svn だと同じ場所にあっても同じファイルとは限らないし、適切な表示とはそもそもどういうものだろうな。
しばらく考えて適切であろうという表示形式を思いつく。でも、やはり svn up 前後でどうファイルが移動したかの情報が必要だなぁ。.svn をちょっと覗いた限りではその情報は見当たらないのだが、どうしたもんかね。
とある文庫本の後書きで、ページ数をオーバーして本文二段組になったという話があり、二段組にするとどうしてページ数を減るのか考える。
直観的に、ページ下部の空白が減るからという理由を思いつく。
さらにしばらく考えて、段落末尾における文末から行端までの空白が減るからと、理由を考え直す。とすれば、段落が多いほど減りやすいはずである。
ここで、件の文庫本を含む、ひとつの段落が数行以下であることが多いとあるジャンルを考えると、かなり効きそうである。
ふと唐突に思いついたのだが、(言語内) DSL っぽくしたい場合と関数呼び出しの括弧を使いたくない場合に相関はあるだろうか。
svn には working directory に lock があることに気がつく
chkbuild で gcc を svn update するところで timeout して殺してしまったら、lock が残ってうまくない
SIGINT, SIGTERM, SIGKILL の順に (5秒待ちつつ) 送るのだが、SIGINT, SIGTERM では死んでくれなくて、SIGKILL までいってしまったようだ
行儀良く死んでくれないのはなぜ? 5秒では足りないということか?
なお、lock を外すのは (lock がかかっているときのエラーメッセージに出て来るが) svn cleanup であった。
おぉ、いつのまにか returns_twice という attribute が出来ていたのか。
ViewCVS は ViewVC に改名した模様
ふと
% grep '\<regist\>' **/*(.) doc/ChangeLog-1.8.0: * ext/marshal/marshal.c (r_object): remove temporal regist for doc/ChangeLog-1.8.0: * ext/marshal/marshal.c (r_object): forgot to re-regist structs in ext/tk/MANUAL_tcltklib.eng: : to _eval and regist the command once, after that, the lib/drb/extserv.rb: @invoker = ro.regist(name, DRbObject.new(self, @server.uri)) lib/drb/extservm.rb: def regist(name, ro)
request-response 型プロトコルにおけるサーバにおいて、signal で安全にサーバを停止するにはどうしたらいいか?
次のような構造のサーバを考える。
def process_connection(s) while req = read_request(s) process_request(req, s) end s.close end TCPServer.open(...) {|serv| loop { Thread.new(serv.accept) {|s| process_connection(s) } } }
ここで、要求は、signal (仮に SIGTERM としよう) を受け取った場合に、新しいコネクションを accept するのを終了し、また、既存のコネクションに対応するスレッドはすでに始まっているリクエストの処理が終りしだい終了し、すべてのリクエストの処理が終ったら全体が終了するというものである。
accept するのを停止するのは難しくなさそうである。accept のループを独立したスレッドで行って、SIGTERM のハンドラからそのスレッドを殺してしまえば良い。殺すタイミングによって accept が行われたり行われなかったりするかも知れないが、その違いはクライアントからは見えないので問題ない。
各コネクションの処理を止めるのは難しい。リクエストを待っているとき (もしくは読んでいる途中) には殺しても良いが、実際に処理をしている (または結果をクライアントに書き出している) ときには殺せない。外部からその違いをテストして殺すとレースコンディションになるので、そのスレッド自身が適切なタイミングで自殺する必要がある。すぐに思いつくのはフラグを用意して通信することだが、リクエストを読むのにブロックしているときにフラグをセットしてもそのスレッド自身はフラグを検査できないのでうまくいかない。
さて?
Linux 2.6 ってパイプのサイズが 64K になってる?
% ruby -rio/nonblock -e 'r, w = IO.pipe; w.nonblock = true; p w.syswrite("a" * (1024 * 1024))' 65536 % uname -a Linux nute 2.6.12-1-686 #1 Tue Sep 27 12:52:50 JST 2005 i686 GNU/Linux
signal についてしばらく考えて、3つ方法を考え付く。
いつでも殺していいスレッドと殺せないスレッドに分ける
リクエストを読み込むスレッドとリクエストを処理するスレッドに分割する。終了時には前者を殺し、後者の終了を待つ。
リクエストの結果によってリクエストの読み方が変化する場合、二つのスレッドは完全に同期して動作しなければならない。コルーチンのほうが適切かも知れない。
self pipe trick
終了のタイミングを伝えるためのパイプを用意し、ソケットを読むときには同時にそのパイプを select で読む。パイプからデータが来たら終了する。
IO クラスのバッファリング機構は使えなくなる。
sigsuspend みたいなのをつける
外部から来た例外を少し待たせておくような機構を提案する
スクリプト言語Rubyの拡張可能な多言語テキスト処理の実装, 松本行弘, 縄手雅彦, 情報処理学会論文誌 Vol.46, No. 11
Gauche のScheme:初心者の質問箱というので不完全文字列というものの話が出ている。
探してみると、<URL:http://www.shiro.dreamhost.com/scheme/gauche/memo-str-j.html> に説明がある。
不正なバイトを文字扱いするという話は、なんというか、Emacs 20.3 を腐る程落してレポートした経験を思い出すものがある。
実際に同じ性質になるかどうかはわからないけれど。
WEBrick と XMLRPC の脆弱性情報が公開されたが、公開に至るまでの感想としては、催促するのに飽きたというのが実感である。
IPA 経由にするともしかしたら自分で催促しなくてもいいかも知れないので、今度何かあればそっちにしよう。
TypeKey API を読んでみる
うぅむ、seconds since the epoch を使ってるなぁ
leap second は無いものとして扱っている模様
4.4BSD には daemon という関数がある。これは
int daemon(int nochdir, int noclose);
という形式で、呼び出したプロセス自体をデーモン化する。
最近の NetBSD での定義は次のようになっている。
int daemon(nochdir, noclose) int nochdir, noclose; { int fd; switch (fork()) { case -1: return (-1); case 0: break; default: _exit(0); } if (setsid() == -1) return (-1); if (!nochdir) (void)chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > STDERR_FILENO) (void)close(fd); } return (0); }
http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/lib/libc/gen/daemon.c?rev=1.9&content-type=text/x-cvsweb-markup
つまり、(カレントディレクトリと標準入出力のあたりを除けば) fork して setsid するというものである。
さて、ここでデーモンを作る作法は昔からいろいろといわれているが、そのなかに、間違って制御端末を得てしまわないようにひとつ余計に fork する、という話がある。
でも、この実装はそうしていないようなんだけどいいのだろうか?
Unix では、プロセスは高々一つの制御端末を持つ。で、制御端末を持っていると、その端末から ^C という文字で SIGINT を送ったりしてプロセスを制御できる。でも、デーモンが不用意に制御端末を持ってしまうと、意図せずしてその端末から制御されてしまうかも知れない。デーモンを制御する権限を持っていない人がそういう端末を持てるとこれは権限上昇になるので危険である。
ここで、プロセスが制御端末を得る方法は、たしか規格では決まっていないのだが、伝統的には、制御端末を持っていないプロセスリーダーが端末を open することである。 (もっと条件があったかも?) したがって、端末を ~/public_html 下にシンボリックリンクして HTTP サーバに open させるなどの攻撃が考えられる。
もし、daemon 関数が余計に fork していれば、プロセスがプロセスリーダではなくなるので大丈夫なのだが、そうしてないわけで、daemon 関数でデーモンにした場合、大丈夫なのだろうか?
と、疑問に思ったわけであるが、調べてみると、 4.4BSD で制御端末を得るには ioctl で TIOCSCTTY を使わなければならず、 open では行えない事がわかった。(つまり O_NOCTTY には効果が無く、マニュアルにも記載されていない) つまり、不用意に open するというのは考えられるが、不用意に TIOCSCTTY するというのは考えられないので、どうも危険はなさそうである。
ところで、daemon は glibc にも移植されている。
int daemon(nochdir, noclose) int nochdir, noclose; { int fd; switch (__fork()) { case -1: return (-1); case 0: break; default: _exit(0); } if (__setsid() == -1) return (-1); if (!nochdir) (void)__chdir("/"); if (!noclose) { struct stat64 st; if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1 && (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) == 0)) { if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR && (st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)) #endif ) { (void)__dup2(fd, STDIN_FILENO); (void)__dup2(fd, STDOUT_FILENO); (void)__dup2(fd, STDERR_FILENO); if (fd > 2) (void)__close (fd); } else { /* We must set an errno value since no function call actually failed. */ close_not_cancel_no_status (fd); __set_errno (ENODEV); return -1; } } else { close_not_cancel_no_status (fd); return -1; } } return (0); }
まぁ、関数名に _ が付いていたり、/dev/null をいろいろ検査してたりもするようであるが、 NetBSD のとよく似ている。
4.4BSD で問題なかったのだから glibc も問題ないかというとそこが問題である。どのシステムコールが制御端末に影響するかというのはカーネル側の話なので、 4.4BSD カーネルではなく、Linux (や Hurd) の挙動を調べなければならない。
で、少なくとも Linux では open で制御端末を得られるような気がするのだが... いいんかね?
なお、uClibc では、次のように、setsid の後に再度 fork している。
int daemon( int nochdir, int noclose ) { int fd; switch (fork()) { case -1: return(-1); case 0: break; default: _exit(0); } if (setsid() == -1) return(-1); /* Make certain we are not a session leader, or else we * might reacquire a controlling terminal */ if (fork()) _exit(0); if (!nochdir) chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); } return(0); }
http://www.uclibc.org/cgi-bin/viewcvs.cgi/trunk/uClibc/libc/unistd/daemon.c?rev=11757&view=auto
Linux と Hurd 以外で glibc が使われている事ってあるのかな?
そっか、Ging があるか。
http://slashdot.jp/bsd/05/11/10/2128242.shtml
% cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/glibc co libc
・ テンポラリファイル ・ IFS ・ setuid-script ・ 他には?
! daemon と制御端末 4.4BSD には daemon という関数がある。 これは int daemon(int nochdir, int noclose); という形式で、呼び出したプロセス自体をデーモン化する。 最近の NetBSD での定義は次のようになっている。 int daemon(nochdir, noclose) int nochdir, noclose; { int fd; switch (fork()) { case -1: return (-1); case 0: break; default: _exit(0); } if (setsid() == -1) return (-1); if (!nochdir) (void)chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { (void)dup2(fd, STDIN_FILENO); (void)dup2(fd, STDOUT_FILENO); (void)dup2(fd, STDERR_FILENO); if (fd > STDERR_FILENO) (void)close(fd); } return (0); } http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/lib/libc/gen/daemon.c?rev=1.9&content-type=text/x-cvsweb-markup つまり、(カレントディレクトリと標準入出力のあたりを除けば) fork して setsid するというものである。 さて、ここでデーモンを作る作法は昔からいろいろといわれているが、 そのなかに、間違って制御端末を得てしまわないようにひとつ余計に fork する、という話がある。 でも、この実装はそうしていないようなんだけどいいのだろうか? Unix では、プロセスは高々一つの制御端末を持つ。 で、制御端末を持っていると、その端末から ^C という文字で SIGINT を送ったりしてプロセスを制御できる。 でも、デーモンが不用意に制御端末を持ってしまうと、意図せずしてその端末から制御されてしまうかも知れない。 デーモンを制御する権限を持っていない人がそういう端末を持てるとこれは権限上昇になるので危険である。 ここで、プロセスが制御端末を得る方法は、たしか規格では決まっていないのだが、 伝統的には、制御端末を持っていないプロセスリーダーが端末を open することである。 (もっと条件があったかも?) したがって、端末を ~/public_html 下にシンボリックリンクして HTTP サーバに open させるなどの攻撃が 考えられる。 もし、daemon 関数が余計に fork していれば、プロセスがプロセスリーダではなくなるので大丈夫なのだが、 そうしてないわけで、daemon 関数でデーモンにした場合、大丈夫なのだろうか? と、疑問に思ったわけであるが、調べてみると、 4.4BSD で制御端末を得るには ioctl で TIOCSCTTY を使わなければならず、 open では行えない事がわかった。(つまり O_NOCTTY には効果が無く、マニュアルにも記載されていない) つまり、不用意に open するというのは考えられるが、 不用意に TIOCSCTTY するというのは考えられないので、どうも危険はなさそうである。 ところで、daemon は glibc にも移植されている。 int daemon(nochdir, noclose) int nochdir, noclose; { int fd; switch (__fork()) { case -1: return (-1); case 0: break; default: _exit(0); } if (__setsid() == -1) return (-1); if (!nochdir) (void)__chdir("/"); if (!noclose) { struct stat64 st; if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1 && (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) == 0)) { if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0 #if defined DEV_NULL_MAJOR && defined DEV_NULL_MINOR && (st.st_rdev == makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR)) #endif ) { (void)__dup2(fd, STDIN_FILENO); (void)__dup2(fd, STDOUT_FILENO); (void)__dup2(fd, STDERR_FILENO); if (fd > 2) (void)__close (fd); } else { /* We must set an errno value since no function call actually failed. */ close_not_cancel_no_status (fd); __set_errno (ENODEV); return -1; } } else { close_not_cancel_no_status (fd); return -1; } } return (0); } まぁ、関数名に _ が付いていたり、/dev/null をいろいろ検査してたりもするようであるが、 NetBSD のとよく似ている。 4.4BSD で問題なかったのだから glibc も問題ないかというとそこが問題である。 どのシステムコールが制御端末に影響するかというのはカーネル側の話なので、 4.4BSD カーネルではなく、Linux (や Hurd) の挙動を調べなければならない。 で、少なくとも Linux では open で制御端末を得られるような気がするのだが... いいんかね? なお、uClibc では、次のように、setsid の後に再度 fork している。 int daemon( int nochdir, int noclose ) { int fd; switch (fork()) { case -1: return(-1); case 0: break; default: _exit(0); } if (setsid() == -1) return(-1); /* Make certain we are not a session leader, or else we * might reacquire a controlling terminal */ if (fork()) _exit(0); if (!nochdir) chdir("/"); if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > 2) close(fd); } return(0); } http://www.uclibc.org/cgi-bin/viewcvs.cgi/trunk/uClibc/libc/unistd/daemon.c?rev=11757&view=auto ! Linux と Hurd 以外での glibc Linux と Hurd 以外で glibc が使われている事ってあるのかな? そっか、Ging があるか。 http://slashdot.jp/bsd/05/11/10/2128242.shtml ! glibc を cvs でとって来る方法 % cvs -z 9 -d :pserver:anoncvs@sources.redhat.com:/cvs/glibc co libc ! シェルスクリプトの伝統的脆弱性 * テンポラリファイル * IFS * setuid-script * 他には?
% google-count 風邪が{移る,写る,映る,うつる} 612 風邪が移る 3 風邪が写る 3 風邪が映る 564 風邪がうつる
飲み会があったと仮定しよう。
帰りがけに本屋に寄ったと仮定しよう。(飲み会の後にもあいてる本屋に幸いあれ)
スーパーダッシュ文庫の新刊を発見したと仮定しよう。
Holy☆Hearts! と蘭堂家の人々の新刊を見つけたにも関わらず折込広告では銀盤カレイドスコープの新刊も出ているはずなのに発見できないことを発見してしまったと仮定しよう。
そのときの気分はいかがばかりか。(酔っているという前提で)
パス名には名前の並びという側面がある。あくまでも側面であってそれが全てではないが。
名前の並びをバラすのに、dirname と basename が使えるかというとこれは難しい。basename はいいのだが、dirname はお節介が過ぎる。
php-5.1 は tzdata を直接読んでる?
むぅ、データ自体をソースに埋め込んでんのか?
<URL:http://cvs.php.net/php-src/ext/date/lib/timezonedb.h>
なかなか思い切ってるな
svn はメモリが足りないと abort する (SIGABRT を自分自身に送って終了する) ようだ。
そうなった場合、working directory は svn cleanup が必要になる。
64bit にすると、メモリがたくさん扱えるが、メモリをたくさん使ってしまうというのも確かではある
まぁ、ふたつの「たくさん」では、前者のほうが圧倒的に大きいのだが、それがいくら大きかろうが実メモリという都合もあるわけで
[latest]