バグの報告に関して
- どのようにして役立つバグレポートを提出するのですか?
- gtk-gnutella の挙動がおかしい、または想定外の動作をします。
- gtk-gnutella をコンパイルできません!
- gtk-gnutella がクラッシュしました! 何をすればいいですか?
- バグレポートを提出するのに最適な場所はどこですか?
どのようにして役立つバグレポートを提出するのですか?
開発者は良くまとまったバグレポートを受け取るのが大好きです。残念ながら、様々な理由から彼らは全く役に立たないレポートをよく受け取ります。ここにバグレポートを作成する上でのいくつかのヒントを載せようと思います。これは gtk-gnutella をより良いものにするのに役立つでしょう。理想的なバグレポートは、必要とされる - それ以上でもそれ以下でもない - 情報をあますことなく含んでいます、心を込めて手作りされた修正パッチもきっとそうでしょう。パッチを寄せたいなら、開発および開発者への HOWTO のページを御覧になって下さい。 私達の大半は、しかしながら、gtk-gnutella を修正する時間と/または技術がありません。大丈夫です、それでも手伝うことはできます。
開発者が興味を持つのは最新のリリース・バージョンか現在の SVN で作成したものからのバグレポートだけだという事に留意して下さい。開発者が gtk-gnutella のコードを書くのは、金銭的な利益のためではなく、興味から来る趣味であったり、オープンソース・コミュニティに何か恩返ししたいと思っているからなのです。開発者達をまるであなたが代金を支払った企業のように、従ってサービスを受けるのが当然であるかのように扱わないで下さい。 古いバージョンのサポートは "been there, done that, boring" に分類されてしまいます、また新しいバージョンは一般的にあなたにとってより良いものであると同時に Gnutella ネットワークにとってもより良いものになります。
人々がよく犯す間違いは、レポートに少なすぎる情報しか含めないことです。こういった場合はむしろ開発者自身が隅々までバグレポートを調べて、全くない時よりかは、必要とする情報を見つけるでしょう。しかし、彼らには利用者から少しずつ情報を引き出すだけの時間がありません。ですから、確信がない情報でも含めるようにして下さい。一度レポートを出したら、もっと多くの情報を伝えてくれるよう開発者からの要望があると思いますので、そのまま忘れずにいて下さい。開発者がより詳しい内容を尋ねてきたら、彼らの質問すべてに答えるのを忘れないで下さい、答えが "知りません" であってもです。あなたのプログラムにバグがあると知っているのに、それを修正するだけ十分な情報がない事ほど苛立たしいものはありません。
開発者がまず最初に知りたいことはバグに遭遇した gtk-gnutella のバージョンです。そうすれば、どのバージョンのソースコードが問題を抱えているか、またバグが既に修復されているかを知ることができます。この情報はポップアップ・ウィンドウこのプログラムについてからコピーできます。例えば:
gtk-gnutella/0.92 (15/06/2003; X11; Linux 2.4.21 i586)
配布パッケージなら、どれを、そしてどこで手に入れたか教えて下さい。 例えば:
私は gtk-gnutella ウェブサイトからダウンロードした GTK2-gtk-gnutella_0.92.0-0_i386.deb を使っています。
CVS バージョンなら
ident
を使用するか gtk-gnutella-current/src/CVS/Entries
を
見て報告内容に最後のコミットエントリーを貼り付けて下さい。例えば:
/support-glade2.c/1.5/Sat Jun 14 17:54:28 2003//
自分自身でコンパイルしたなら、どの ./Configure
オプションを
使用したか教えて下さい。例えば:
./Configure -Dprefix=/usr -Dccflags="-g -Wall" -Doptimize="-O2" -Dgtkversion=2 -ders
どのディストリビューション、バージョンおよびどのアーキテクチャで実行して いるか教えて下さい。例えば:
compaq alpha 上で debian 2.2.22 を使っています
すべてのバグ報告に関連するバージョン情報を含めて下さい。
gtk-gnutella の挙動がおかしい、または想定外の動作をします。
もし gtk-gnutella がプログラマーが意図した通りに振る舞っていて、けれどもあなたはそれとは異なる振る舞いを望むなら、恐らくバグレポートというよりはむしろ新機能のリクエストに要望を出す方が良いでしょう。もちろん例外はあります - その振る舞いは一部の予期しないやり方、あるいは標準に準拠していない場合で有害になる可能性があります。その上、何が開発者の意図かを知るのは困難ですので、バグ vs 機能に関する伝統的な混乱が必然不可避に起こります。
これをバグだと決めるなら、gtk-gnutella の振る舞いの何が悪いのか、どのように振る舞うべきなのかを明確に説明して下さい。他の誰かがあなたの報告からそのバグを再現できるよう、十二分に細かく解説される必要があります。あなたはどのペインにいて、どのオプションを選択していましたか? バグに至るまでの正確な動作は何ですか? 忘れてしまう前に簡単なノートを付けておくと役立つかもしれません。
gtk-gnutella をコンパイルできません!
gtk-gnutella に関してそう多くの問題は報告されていません。Linux, OS X および FreeBSD と gcc でコンパイルできることが判っています。問題があるなら、最後のコンパイラ・コマンドを貼り付けて下さい。例えば:
gcc -DHAVE_CONFIG_H -I. -I. -I.. -I/usr/include/gtk-1.2
-I/usr/include/glib-1.2 -I/usr/lib/glib/include -I/usr/X11R6/include
-I/usr/include/libxml2 -g -O2 -Wall -c nodes.c
それに発生したエラーをバージョン、および上で述べたコンフィグ・オプションと共にあなたの報告に入れて下さい。
gtk-gnutella クラッシュしました! 何をすればいいですか?
クラッシュした gtk-gnutella のバグを解析するには、この実行ファイルがバグ解析用のシンボルをそのまま残していることが必要になります。残念な事ですが、ハードディスクやメモリの領域を節約するために、配布パッケージが作成される際にはバグ解析用のシンボルが gtk-gnutella から取り除かれます。ダウンロードサイトにある RPM, Debian, Slackware パッケージは皆これらのシンボルが取り除かれているので、バグ解析には役立ちません。ですが、どれかのパッケージを使用している最中にクラッシュする場合でもバグは報告する方がよいでしょう。この際、他の人がバグ解析シンボルが取り除かれていない実行ファイルでそのバグを再現できるように正確なエラーを報告して下さい。
xterm のようなターミナルから gtk-gnutella を走らせれば、そのターミナル・ウィンドウにエラーメッセージが出ているのを見つけられるでしょう (少し前にスクロールする必要があるかもしれません) 。アイコンあるいはメニューから gtk-gnutella を起動する場合は X のエラーログがある場所で見つけられます。エラーメッセージ全部とその 10 行くらい前までのメッセージをバグレポートに貼り付けて下さい。疑り深いと (結局のところ、これらはあなたが理解できる範囲外にあるのですから) ファイル名をますます分かり難くさせてしまいます。gtk-gnutella が 異常中断
する場合にのみエラーを見つけるでしょう、セグメント違反
を起こした場合は違いますので、どちらのケースを適用するのか言うべきでしょう。
gtk-gnutella がクラッシュする最もありがちな原因は "アサーション (表明)" の失敗です。アサーションとはプログラマがバグを見つけるのを助けるため、コード中に意図的に配置される論理文のことです。これらはコードの実行における特定の箇所で、特定の条件が必ず満たされているか、あるいはプログラムが開発者の意図通りに振る舞っていないかを "表明" します。例えばアサーションは、ある変数が少なくともある値を持つべきであると述べるかもしれません。すなわち、その値は NULL ではない: g_assert(header != NULL);
であったり、その値は何らかの数値の範囲内にあるべきである: g_assert(parq_ul->position > 0);
というようになります。このアサーションが失敗すると、プログラムはアサーションに失敗しましたというエラーメッセージと共に異常中断 (abort) します。これは正にそのアサーションが配置されたコードにおいて発生します。例えば:
** ERROR **: file parq.c: line 1138 (parq_upload_free): assertion failed: (parq_ul->by_ip->uploading <= parq_ul->by_ip->total)
次に開発者はこの値を調査して、うまく行けば不正な値をもたらすバグがどこにあるのかを理解するかもしれません。あるいは問題が隔離されるまで、さらに多くのものを返すようコードにより多くのアサーションを追加するかもしれません。gtk-gnutella のコードには 500 以上のアサーションがありますので、なぜ開発者がファイルや行番号を含む正確なエラーメッセージを提供するよう求めるのか分かってもらえると思います。
あるパッケージ、またはバグ解析シンボルが取り除かれた gtk-gnutella を使用しているのでしたら、再コンパイルしてバグを再現しない限り、クラッシュから得られる情報はそれほど多くありません。そうしたくなければ、これまでに書かれている情報を提供して下さい。一般的に、それらは問題を解決するのに十分ではありませんが、少なくともバグが存在することは喚起できます。必要十分な説明ができるなら、他の誰かがバグ解析版の gtk-gnutella でそのバグを再現できるかもしれません。
gtk-gnutella をあなた自身でコンパイルするなら、標準ではコンパイラに -O
オプションが渡されてコンパイルされます。加えて make install
は実行ファイルからシンボルを取り除いてしまいます。バグを報告するにはバグ解析用のシンボルを組み込んで最適化のレベルを下げるために -g3 -O0
でコンパイルするのがよいでしょう。例えば:
./Configure -O -Dccflags="-g3 -Wall" -Doptimize="-O0" -ders
今のところ実行ファイルからバグ解析シンボルを取り除かないよう make install
に伝える方法がありませんので、インストールされているバージョンの上にコピーする必要があります。例えば:
su -c 'install -m 555 src/gtk-gnutella /usr/local/bin/gtk-gnutella'
gtk-gnutella がクラッシュすると、利用していたメモリのイメージを含む "core" というファイルを廃棄します。メモリには、その時の RAM に確保されていたすべての値が含まれています。次にこのファイルは、クラッシュした時の gtk-gnutella の状態を調査するために、gdb デバッガーの内部で読み込まれます。しかしながら、大方のディストリビューションは標準ではコアを廃棄しないようになっています。シェルコマンド ulimit -S -c unlimited
を使用すると、コアを廃棄するようになります。これはそのターミナルでしか影響しません、あるいはあなたの環境全般でコアを廃棄するようにするために、このコマンドをシェルの設定ファイル (例、~/.profile
または ~/.cshrc
) に記述することができます。新しいコアファイルは古いものを上書きしてしまいますので、安全な場所に移動する必要があります。ターミナルから gtk-gnutella を呼び出したのなら、コアファイルはあなたのホームディレクトリか現在いるディレクトリにあるでしょう。本気でバグを追ってみることを考えているなら、始めるにあたって以下のようなスクリプトを使ってみるのもよいかもしれません。もちろんあなたのシステムに合うよう変更する必要があるでしょう。例えば、コアファイルの名前は "core", "gtk-gnutella.core", "core.[PID]" 等になるかもしれません。
#!/bin/sh
# これは設定ファイルが保存される場所です。
#export GTK_GNUTELLA_DIR=$HOME/.gtk gnutella
# コアの生成を有効にして古いコアとログを削除します。
ulimit -S -c unlimited
rm -f core gtk-gnutella.log
# gtk-gnutella を実行して出力をログファイルにリダイレクトします
# 稼働時間が長いとログが巨大にる可能性があります。
# 出力をただターミナルに出し続けるには、代わりに:
# gtk-gnutella
# として他のログ・リファレンスを削除して下さい。
gtk-gnutella >gtk-gnutella.log 2>&1
# If a core is dumped, create a uniquely named directory
# to save the core, log and executable
if [ -e core ] ; then
Core_Save_Dir=$(date "+core%Y.%m.%d.%H.%M.%S")
mkdir $Core_Save_Dir
cp $(which gtk-gnutella) $Core_Save_Dir
cp core $Core_Save_Dir
cp gtk-gnutella.log $Core_Save_Dir
fi
さて、これであなたの手元にはバグ解析シンボルが取り除かれていない実行ファイルとコアファイルがあるはずです。バックトレースを作成するには gdb
デバッガーを使用します。この例では gtk-gnutella の実行ファイルとコアファイルが同じディレクトリにある事に注意して下さい。
~/src/test/core2003.06.12.18.01.40> gdb -c core ./gtk-gnutella
GNU gdb 5.2
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-slackware-linux"...
Core was generated by `gtk-gnutella'.
Program terminated with signal 6, Aborted.
Reading symbols from /usr/lib/libgtk-1.2.so.0...done.
Loaded symbols for /usr/lib/libgtk-1.2.so.0
Reading symbols from /usr/lib/libgdk-1.2.so.0...done.
Loaded symbols for /usr/lib/libgdk-1.2.so.0
Reading symbols from /usr/lib/libgmodule-1.2.so.0...done.
Loaded symbols for /usr/lib/libgmodule-1.2.so.0
Reading symbols from /usr/lib/libglib-1.2.so.0...done.
Loaded symbols for /usr/lib/libglib-1.2.so.0
Reading symbols from /lib/libdl.so.2...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /usr/X11R6/lib/libXext.so.6...done.
Loaded symbols for /usr/X11R6/lib/libXext.so.6
Reading symbols from /usr/X11R6/lib/libX11.so.6...done.
Loaded symbols for /usr/X11R6/lib/libX11.so.6
Reading symbols from /lib/libm.so.6...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /usr/lib/libz.so.1...done.
Loaded symbols for /usr/lib/libz.so.1
Reading symbols from /usr/lib/libxml2.so.2...done.
Loaded symbols for /usr/lib/libxml2.so.2
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Reading symbols from /usr/X11R6/lib/X11/locale/common/xlcDef.so.2...done.
Loaded symbols for /usr/X11R6/lib/X11/locale/common/xlcDef.so.2
Reading symbols from /usr/X11R6/lib/X11/locale/common/ximcp.so.2...done.
Loaded symbols for /usr/X11R6/lib/X11/locale/common/ximcp.so.2
Reading symbols from /lib/libnss_compat.so.2...done.
Loaded symbols for /lib/libnss_compat.so.2
Reading symbols from /lib/libnsl.so.1...done.
Loaded symbols for /lib/libnsl.so.1
Reading symbols from /lib/libnss_db.so.2...done.
Loaded symbols for /lib/libnss_db.so.2
Reading symbols from /lib/libnss_files.so.2...done.
Loaded symbols for /lib/libnss_files.so.2
Reading symbols from /lib/libdb-3.1.so...done.
Loaded symbols for /lib/libdb-3.1.so
#0 0x4036b2f1 in kill () from /lib/libc.so.6
(gdb)
さあ、完全なバックトレースを取りましょう:
(gdb) bt full
#0 0x4036b2f1 in kill () from /lib/libc.so.6
No symbol table info available.
#1 0x4036afbc in raise () from /lib/libc.so.6
No symbol table info available.
#2 0x4036c7cb in abort () from /lib/libc.so.6
No symbol table info available.
#3 0x4018f9de in g_logv () from /usr/lib/libglib-1.2.so.0
No symbol table info available.
#4 0x4018fa91 in g_log () from /usr/lib/libglib-1.2.so.0
No symbol table info available.
#5 0x0814efda in parq_upload_free (parq_ul=0x8d62328) at parq.c:1138
No locals.
#6 0x0814d696 in parq_close () at parq.c:416
queues = (GList *) 0x0
dl = (GList *) 0x0
sl = (GSList *) 0x8a20040
remove = (GSList *) 0x8a204b8
removeq = (GSList *) 0x8a204c0
#7 0x0811f3a4 in gtk_gnutella_exit (n=0) at main.c:113
now = 1055466099
tick = 143511256
#8 0x080d7eba in quit (force=0) at main_cb.c:44
confirm = 0
#9 0x080d7f04 in on_button_quit_clicked (button=0x8358d44, user_data=0x0) at main_cb.c:62
No locals.
#10 0x400b10d5 in gtk_marshal_NONE__NONE () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#11 0x400e091c in gtk_signal_remove_emission_hook () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#12 0x400dfd85 in gtk_signal_set_funcs () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#13 0x400dde63 in gtk_signal_emit () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#14 0x401149be in gtk_widget_activate () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#15 0x400b9534 in gtk_menu_shell_activate_item () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#16 0x400b87ba in gtk_menu_shell_deactivate () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#17 0x400b0d5f in gtk_marshal_BOOL__POINTER () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#18 0x400dfdc3 in gtk_signal_set_funcs () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#19 0x400dde63 in gtk_signal_emit () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#20 0x4011487b in gtk_widget_event () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#21 0x400b0ca5 in gtk_propagate_event () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#22 0x400afe0e in gtk_main_do_event () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#23 0x4015f047 in gdk_wm_protocols_filter () from /usr/lib/libgdk-1.2.so.0
No symbol table info available.
#24 0x4018d258 in g_main_dispatch () from /usr/lib/libglib-1.2.so.0
No symbol table info available.
#25 0x4018d863 in g_main_iterate () from /usr/lib/libglib-1.2.so.0
No symbol table info available.
#26 0x4018d9fc in g_main_run () from /usr/lib/libglib-1.2.so.0
No symbol table info available.
#27 0x400af707 in gtk_main () from /usr/lib/libgtk-1.2.so.0
No symbol table info available.
#28 0x080d7cf2 in main_gui_run () at main_gui.c:650
coord = {0, 0, 1276, 965}
#29 0x0811fc2b in main (argc=1, argv=0xbffff924, env=0xbffff92c) at main.c:463
i = 256
#30 0x4035a17d in __libc_start_main () from /lib/libc.so.6
No symbol table info available.
このバックトレースをバグレポートに貼り付けて下さい。
開発者は恐らくもう少し情報を必要とするでしょうが、バックトレースおよび他の情報を送ったのなら、取り掛かりは彼らが見つけるでしょう。その後あなたのところに戻って、再び gdb の中でコアを読み込んで必要とする特定の値を表示してほしいと、要望して来るかもしれません。しかしながら、彼らの要求を先取りすることができます。C を理解できるなら、コードを覗いて何を含めるのかを決められます、C を知らなくてもそのアサーションを眺めて推測することはできるでしょう。この例では、エラーメッセージは以下のようでした:
** ERROR **: file parq.c: line 1138 (parq_upload_free): assertion failed: (parq_ul->by_ip->uploading <= parq_ul->by_ip->total)
このバックトレースを眺めてみると、#5 parq.c:1138
に問題があるのが分かると思います、アサーションが配置されている場所と同じ行です。そこで、このフレームのいくつかの値を調査してみましょう:
(gdb) frame 5
#5 0x0814efda in parq_upload_free (parq_ul=0x8d62328) at parq.c:1138
1138 g_assert(parq_ul->by_ip->uploading <= parq_ul->by_ip->total);
まず最初に、parq_ul
のメンバーの値を表示させてみましょう。
(gdb) p * parq_ul
$1 = {magic = 1782120609, flags = 10, position = 1735, relative_position = 1, has_slot = 0, had_slot = 0, eta = 81,
expire = 1055465788, retry = 1055465787, enter = 1055465787, updated = 1055465787, ban_timeout = 1055466387,
disc_timeout = 0, last_queue_sent = 0, queue_sent = 0, queue_refused = 0, is_alive = 0,
id = 0x8a15af8 "6cad90dc1f0edd94f5d0e991cc89f25e",
ip_and_name = 0x8a16578 "3521280541 Somethingorother.mp3",
name = 0x8a16583 "Somethingorother.mp3", remote_ip = 3521280541, file_size = 2652639,
chunk_size = 1005329, ip = 0, port = 0, major = 0, minor = 0, queue = 0x84f85c8, by_ip = 0x86259e8}
リストされている最後のメンバーが by_ip = 0x86259e8
である事に気付いて下さい。このアサーションは parq_ul->by_ip
のメンバーの二つを比較しています、この値を表示させてみましょう。
(gdb) p * parq_ul->by_ip
$2 = {uploading = 2, total = 1, ip = 3521280551, list = 0x8bb639c}
これが開発者が探していた値です:
parq_ul->by_ip->uploading
= 2 と parq_ul->by_ip->total
= 1 です。というのも 2 <= 1
は偽だからです、このためにアサーションが失敗しました。これで開発者は何が支障を来たしたかを理解することができます。
バグレポートを提出するのに最適な場所はどこですか?
SourceForge.net のバグ追跡システムを利用するか、あるいは報告を gtk-gnutella-devel メーリングリストにメールしてバグを報告できます。Freenode ネットワーク の IRC チャンネル #gtk-gnutella でも開発者と連絡を取ることができます。
もしこのチャンネルで開発者と連絡がつくなら、IRC は素早い返答をもらうのに便利かもしれません、けれどもそこでのみ報告されるならバグは簡単に忘れられます。あなたの問題が実際にバグなのかどうかよく分からなければ、ここは訪れるのに良い場所かもしれません。あなたがすでにメーリングリストやバグ追跡システムにレポートを出していて、開発者があなたからもっと詳しい情報を必要としているかどうかを知りたければ、ここはまさにうってつけの場所になります。この文書が書かれた時点では、すべての開発者は中央ヨーロッパ時間 (CET) の時間帯 (UTC+1) に住んでいました。手短な質問をするため、仕事が始まる前の朝の時間帯に開発者を捕まえられるかもしれませんが、最適な時間は夕方か週末です。このチャンネルにいつ人がいるかを知るためにIRC ログを見みることができます。
開発者用のメーリングリストはクラッシュのような致命的なバグを報告するのに適した場所です。もっとも、これらのバグはバグ追跡システムに報告することもできます。ただ、リストの場合はバグ追跡システムよりも多くの人がバグレポートを読むことになるでしょうし、恐らくバックトレース等を読むのに少しだけ便利かもしれません。その一方で、このリストへのバグ報告はバグ追跡システムに提出されたものより忘れられ易くなるかもしれません。gtk-gnutella-devel に加わるには SourceForge で登録する必要がありますが、メッセージを投稿するだけならこのリストに加入する必要はありません。このメーリングリストに加入せずにメッセージを投稿する場合は、あなたのメールアドレスかあなたは加入していないという記述が Reply-To: ヘッダに追加されます。
バグを届けるのに最適な場所は SourceForge のバグ追跡システムです。とどのつまり、そのために設計されたのですから。一通り眺めて見てあなたのバグと似たようなものが既に報告されているか確認して下さい、もしあるのなら新しいバグとして提出せずに、あなたの報告をコメントとしてそこに追加して下さい。バグを提出する前に SourceForge に登録してログインする必要があります。
一度レポートを出したらその事を忘れないで下さい。あなたのバグレポートはその後に開発者が投げかける質問に回答しない限り完結しません。その質問に返事を返さないバグ報告者は開発者にとって大きな頭痛の種です。ソフトウェアのバグ解析作業は開発者にとってストレスになる場合がありますが、よいバグレポートはちょっとだけましなフリーソフトウェアを書く手助けになります。