続GLOBALがブロックしているっぽい件。

どうもです。


シンボルが存在してデバッグできるバイナリができるまで,
global のバージョンを落としながら,確認してました。
こういうときには,2分探索使えばいいだよねって気づいたのは,
かなりあとになってからの話。
どうやら,5.7 系までは,シンボルが存在してる。
5.8 系になると,シンボルがなくなっている。
nmコマンドで確認してもなかったし。
ほいで,-c オプションと,-iオプションが同居できるようになったのも,
5.8 系から。ま,それは本来の目的でないけど。


収穫はあった。5.7.7 でも,GTAGSなどのタグファイルが存在しないと,
10秒くらい待たされることがわかった。
ほいで,gdbで追っていったら,どうやら,libutil/test.c:94 の test()という
関数っぽい。
ほいで,そこまで来て,testに渡される引数の3番目が,"//GTAGS"になっている
ことを発見した。

Breakpoint 3, gtagsexist (candidate=0x4224b0 "/", dbpath=0x4214a0 "", size=4096, verbose=0) at getdbpath.c:147
147             if (makeobjdir == NULL)
(gdb) si
141     {
(gdb) n
147             if (makeobjdir == NULL)
(gdb) 
141     {
(gdb) 
147             if (makeobjdir == NULL)
(gdb) 
150             snprintf(path, sizeof(path), "%s/%s", candidate, dbname(GTAGS));
(gdb) 
151             if (verbose)
(gdb) 
153             if (test("fr", path)) {
(gdb) si
0x00404e61      153             if (test("fr", path)) {
(gdb) si
0x00404e68      153             if (test("fr", path)) {
(gdb) si
test (flags=0x41cd31 "fr", path=0x22abab "//GTAGS") at test.c:94
94      {
(gdb) 


ほいで,

	if (path != NULL)
		if (stat(path, &sb) < 0)
			return 0;

の stat() で阿呆みたい時間がかかっている。
つまり,stat() に "//GTAGS" を渡していて,そこでまごついているとこまでわかった。


で,timeコマンドで経過時間を計ってみた。

% /usr/bin/time global foo
global: GTAGS not found.
Command exited with non-zero status 3
0.03user 0.03system 0:09.04elapsed 0%CPU (0avgtext+0avgdata 353792maxresident)k
0inputs+0outputs (1380major+0minor)pagefaults 0swaps

という結果に。
ほらー,9秒以上かかってるじゃん。
深いパスから実行すると,11秒かかったこともあったよ。

次の手

stat(2) に"//"を渡していることが原因っぽいので,
下のようなプログラムを書いて実行してみる。
最初,10.0で6回割っていたが,かっこわるいので,調べてみたら,
なんていうの? scientific notation ? にした方がかっこいいので,それに。

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  struct stat sb;
  struct timeval tv;
  double t1, t2;

  gettimeofday(&tv, NULL);
  t1 = tv.tv_sec + tv.tv_usec * 1e-6;
  // 「//」を指定した場合
  if (stat("//HOGE", &sb) < 0) {
    printf("ouch!!\n");
  }
  gettimeofday(&tv, NULL);
  t2 = tv.tv_sec + tv.tv_usec * 1e-6;
  printf("//HOGE: %f\n", t2 - t1);

  gettimeofday(&tv, NULL);
  t1 = tv.tv_sec + tv.tv_usec * 1e-6;
  // 「/」を指定した場合
  if (stat("/HOGE", &sb) < 0) {
    printf("ouch!!\n");
  }
  gettimeofday(&tv, NULL);
  t2 = tv.tv_sec + tv.tv_usec * 1e-6;

  printf("/HOGE: %f\n", t2 - t1);

  return 0;

実行結果。

% ./tmp
ouch!!
//HOGE: 4.506000
ouch!!
/HOGE: 0.000000

ほらー。やっぱり,阿呆みたいに時間がかかっている。
stat(2)のよくこと知らないけど,予想で書くと,
「//」渡されるとネットワーク的なところを調べたりする?
ほら,Windowsだと,たしか,ネットワーク上のパスを「\\」指定したりしたような
記憶があるので。


ということはですね,これは,globalの方のバグということでいいのではないでしょうか?
タグファイルを探すために,ディレクトツリーをのぼっていって,
最後は,「/GTAGS」に対して,stat(2)をかますはずだけど,
まちがって,「//GTAGS」にかましてしまっているから,というのがその理由。

まとめ

どうしたもんでしょ?
Linuxとかだと,どうなるんだろ?
あと,こういうのってどっかに報告するべきなのでしょうか?
それとも,またまた,オイラの勘違い?


また,5.8 以降のバージョンについては,
シンボルがなくなっているように見えるのが,謎のままだ。
こっちの方もかなり気になる。
適当に書いたプログラムだとちゃんとデバッグできるのは確認した。

あぁ,忘れてた。

環境は,WindowsXP SP3,Cygwin1.7.7 です。