11/13/2011

GNU coreutils の yes(1) を読む(後編)

GNU coreutils の yes(1) を読む(前編) の続き、yes.c の残りは次のようになっている。
     75   if (argc <= optind)
     76     {
     77       optind = argc;
     78       argv[argc++] = bad_cast ("y");
     79     }
     80
     81   for (;;)
     82     {
     83       int i;
     84       for (i = optind; i < argc; i++)
     85         if (fputs (argv[i], stdout) == EOF
     86             || putchar (i == argc - 1 ? '\n' : ' ') == EOF)
     87           {
     88             error (0, errno, _("standard output"));
     89             exit (EXIT_FAILURE);
     90           }
     91     }
最初の if 文は、引数の数(argc)が argv の中で次に処理されるべき要素を示すインデックス(optind)以下の場合に実行される、ということで、典型的には yes(1) が引数無しで呼ばれたときに if 文の中に入る。if 文の bad_cast() は、src/system.h で定義されていて、const char * を引数にして、char * で返す関数。const だったものを強引に const 外すから、bad_ なのかな。

次の while 文が、yes(1) の出力処理を実行してる。argv の optind から順に fputs していって、最後の要素を fputs したら改行文字を putchar(3) する。というわけで、

$ yes a b c
のように実行すると、"a b c" が出力されるわけだ。
$ yes
みたく、引数がない場合は、argv[optind] に "y" が設定されるから、"y" が連続して出力される。

この yes.c を読んで気になったのは、78行目、
     78       argv[argc++] = bad_cast ("y");
の部分。これ、メモリ破壊起こすんじゃないのかな....argv の要素数は argc で与えられているわけで、argv[argc] は与えられた領域を超えちゃってるような。ググって調べてみたけど、78行目みたいなことができる根拠がわからなかった。。誰か教えて!!

argc <= optind になる場合とか、そのほかいろんな制約がわかってないけど、たとえば、↓のようになってればすっきりするんだけど。。
@@ -74,8 +74,8 @@

   if (argc <= optind)
     {
-      optind = argc;
-      argv[argc++] = bad_cast ("y");
+      optind = argc - 1;
+      argv[optind] = bad_cast ("y");
     }
ま、いいやっ!

0 件のコメント:

コメントを投稿