[Contents] [Back] [Prev] [Up] [Next] [Forward]
バグ報告は、
GCCの信頼性を向上させるのに重要な役割を果しています。
バグを見つけた場合、
まずそれが既に発見されているバグかどうかを調べてください。
GCCの既知の不具合原因を参照してください。
発見されていないバグであれば、
その問題を報告する必要があります。
バグを報告することで、
その問題の解決につながることもありますし、
何の解決にもならないこともあるでしょう。
(解決しない場合は、
サービス・ディレクトリを調べてみてください。
GCCに関する援助の入手方法を参照してください。)
いずれの場合でも、
バグ報告の主な役割は、
次のバージョンのGCCをより良いものにすることによって、
コミュニティ全体を支援することにあります。
バグを報告することによって、
GCCの保守作業に貢献することになるのです。
保守作業は負荷が大きいので、
すべてのバグ報告に回答することはできません。
しかし、
バグがまだ修正されていない場合には、
バグの報告者にパッチを送付して、
バグが解消されるかどうか尋ねることになるでしょう。
バグ報告が、
その目的とするところを達成することができるようにするためには、
バグ修正を行うための情報を必ず提供しなければなりません。
発見した現象がバグかどうかよくわからない場合には、
以下のガイドラインを参照してください。
-
入力された情報が何であれ、
コンパイラが致命的なシグナルを受信するのであれば、
それはコンパイラのバグです。
信頼性のあるコンパイラは決してクラッシュなどしません。
-
(
asm
文は除外して)
入力がどのようなものであれ、
コンパイラが不正なアセンブリ・コードを生成してしまい、
かつ、
その際にコンパイラが、
通常はアセンブラが実行されるのを防いでくれる
(ただの警告ではない)
エラー報告を行わないのであれば、
それはコンパイラのバグです。
-
コンパイラが正当なアセンブリ・コードを生成したとしても、
そのアセンブリ・コードが、
入力ソース・コードに指定されていることを正しく実行しない場合、
それはコンパイラのバグです。
ただし、
バグであると判断する前に、
もう一度確認してください。
GNU Cと伝統的なC言語
(GCCの非互換性を参照)
との間の非互換性によるものかもしれないからです。
こうした非互換性は、
バグと考えられてしまいがちですが、
価値ある機能を提供するためには避けられないものなのです。
また、
使用しているプログラムの振る舞いが未定義であるような場合、
他のCやC++コンパイラとの組み合わせでは、
たまたま期待どおり動いているということもあるでしょう。
例えば、
多くの最適化されていないコンパイラでは、
関数の終わりに`return x;'ではなく`x;'を記述しても、
同じ結果を得ることができます。
しかし、
return
が省略されると、
関数の値は未定義となります。
この場合、
GCCが異なる結果を引き起こしたとしても、
バグではありません。
また、
f (*p++, *p++)
のように、
インクリメント演算子を2個持つ式に起因して問題の発生することもよくあります。
ユーザが以前に使用していたコンパイラが、
意図した通りにこの式を解釈していたとしても、
GCCは、
また別の方法でこれを解釈するかもしれません。
どちらのコンパイラも間違っているわけではありません。
バグはあなたのコードの中にあるのです。
エラーを発生させている場所がソースの中のどの行であるかをつきとめてしまえば、
こうしたことを確認するのは簡単になるはずです。
ユーザのプログラムが正しく、
きちんと定義されているものであれば、
コンパイラのバグを発見したことになります。
-
正当な入力に対してコンパイラがエラー・メッセージを出力するのであれば、
それはコンパイラのバグです。
-
不正な入力に対してコンパイラがエラー・メッセージを出力しないのであれば、
それはコンパイラのバグです。
ただし、
ユーザにとって「不正な入力」に思えるものが、
実は「拡張機能」であったり、
「伝統的な慣習のサポート」であったりすることもあります。
-
CやC++
(あるいは、FortranやObjective-C)
のコンパイラに精通したユーザからの、
GCCを改良するための提案は、
どのような場合でも歓迎します。
GNUコンパイラ・コレクション(GNU Compiler Collection)のバグは、
`gcc-bugs@gcc.gnu.org'に報告してください。
「foo」という名前のツールに対するバグ報告は`bug-foo@gnu.org'に送るという
GNU全体の慣習にしたがい、
`bug-gcc@gnu.org'というアドレスも使うことができるようになっています。
このアドレスに送られたメールは、
上記のアドレスに転送されます。
バグ報告を送信する前に、
`<URL:http://www.gnu.org/software/gcc/faq.html#bugreport>'
にある、
バグ報告に関する指示を読んでください。
メーリング・リストではなくニュースグループにバグ報告を流そうと考える人がよくいます。
これはうまく機能するように見えますが、
1つ重大な問題があります。
ニュースグループへの投稿では、
送信者へのメール・パスが分からないことがあります。
したがって、
もっと多くの情報が必要になったときに、
バグの報告者と連絡を取ることができません。
こういうことがあるので、
バグ報告は常にメーリング・リストに出すべきです。
最後の手段として、
バグ報告を紙に書いて下記に郵送するという方法があります。(20)
GNU Compiler Bugs
Free Software Foundation
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
バグの報告方法に関する追加情報や最新情報は、
`<URL:http://www.gnu.org/software/gcc/faq.html#bugreport>'
にあります。
役に立つバグ報告を行うための最も根本的な原則は、
すべての事実を報告することです。
ある事実を書くべきか省くべきかよく分からない場合は、
書くようにしてください。
事実が省略されてしまうことがよくありますが、
これはバグ報告者が自分には問題の原因は既に分かっていると考え、
いくつかの細かい点は関係がないと仮定してしまうからです。
したがって、
例の中で使った変数の名前などは重要ではないと、
報告者は考えます。
おそらくそうかもしれません。
しかし、
完全にそうであるとも言い切れません。
メモリの参照がデタラメな場所を指しているというバグで、
それがたまたまメモリ上においてその名前が置かれている箇所から値を取り出しているということがあるかもしれません。
名前が異なれば、
そこの内容は、
バグが存在するにもかかわらずコンパイラが正しく動作してしまうような値になるかもしれません。
このようなことがないよう、
特定の完全な実例を提供してください。
バグの報告者にとっては、
このようにするのが最も簡単なはずであり、
かつ、
それが最も役に立つのです。
バグ報告の目的は、
未知のバグを修正することができるようにするという点にあるということを頭に入れておいてください。
そのバグが既に発見されているものであればどうなるのかということは、
重要ではありません。
ですから、
バグ報告は常に、
そのバグは未知のものであると想定して書いてください。
ときどき、
2、3の大雑把な事実だけを記述して、
「何か思い当ることはありますか?」と聞いてくる人がいます。
このようなバグ報告をもらっても、
バグ・フィックスの助けにはなりません。
ですから、
このような報告は無駄です。
このような報告を受け取ると、
私たちは、
調査を行うために十分な詳細情報を送るよう、
報告者に返信します。
最初からこのような詳細情報を送ることによって、
処理をはかどらせることができるでしょう。
バグ報告にはすべての情報を含めるようにしてください。
私たちがさらに情報を要求することになった場合には、
返信の中に、
不足していた情報だけでなく、
以前に送った情報もすべて含めるのが最良の方法です。
バグは、
1つずつ別のメールで報告してください。
こうすることにより、
どのバグがフィックスされたか追跡したり、
バグ報告を保守担当者に転送することが容易になります。
バグを修正できるようにするためには、
報告者は以下の情報をすべて含めるべきです。
-
GCCのバージョン。
GCCのバージョンは、
`-v'オプションを付けて実行すると表示されます。
この情報がないと、
カレント・バージョンのGCCを使ってバグを探すことに意味があるのかどうかを知ることができません。
-
バグを再現することのできる、
完全な入力ファイル。
バグがCのプリプロセッサにある場合は、
ソース・ファイルと、
ソース・ファイルが必要とするヘッダ・ファイルも送ってください。
バグがコンパイラ(`cc1')固有のものである場合は、
コンパイル・コマンドに`-save-temps'オプション
(ユーザ・プログラムまたはGCCをデバッグするためのオプションを参照)
を追加することによって生成される、
プリプロセッサの出力を送ってください。
この場合、
実際のコンパイルに使用したのと同一の`-I'、
`-D'、
`-U'オプションを使用してください。
これによって生成される
input.iファイルまたはinput.iiファイルを送ってください。
単一の文だけでは、
例として十分ではありません。
コンパイルを行うためには、
その文を、
コンパイラの入力となる完全なファイルに組み込まなければなりません。
その組み込み方法の細かな点により、
バグが影響を受ける可能性があります。
コンパイルすることのできる実際の事例がなくては、
そのバグ報告については、
せいぜい幸運を祈ることくらいしかできません。
どうすればバグを発生させることができるかを推測して試してみるのは、
時間の無駄になります。
例えば、
レジスタ割り当てや再ローディングのバグは、
それが発生する関数の内部の、
あらゆる微細なことによって影響を受けることが多いのです。
コンパイルできない入力ファイルがGNUプログラムのものである場合でも、
完全なテスト・ケースを送る必要があります。
GCCの保守担当者に、
問題になっているプログラムを入手するという、
余分な作業をするよう求めないでください。
全員が既にたくさんの仕事を抱えているのです。
また、
報告者のシステム上のヘッダ・ファイルの内容に問題が依存していることもあります。
GCCの保守担当者にとって、
手元にあるヘッダ・ファイルを使用して問題を試してみるのは、
あてにならないことなのです。
CPPの出力結果を送ることにより、
不確実さの原因が取り除かれ、
雲をつかむような作業の何パーセントかを節約することができます。
-
バグを見つけた実例をコンパイルする際に、
GCCに渡したコマンド引数。
例えば、
`-O'オプションを使ったか否かなど。
何か重要な点を省いてしまうことがないよう、
すべてのオプションを記述してください。
私たちが、
引数が何であったのかを推測しようとしても、
おそらく誤った推測をしてしまうでしょう。
そうなると、
バグは再現しないかもしれません。
-
使っているマシンのタイプ、
オペレーティング・システムの名前とバージョン番号。
-
コンパイラのインストール時に、
configure
コマンドに渡したオペランド。
-
コンパイラのソースに加えた変更点の完全なリスト。
(変更が行われていないコンパイラで発生したバグでない場合は、
調査を約束することはできません。
かといって、
変更を行ったのにそれを知らせないのでは、
雲をつかむような作業に私たちを追い込むことになります。)
変更点は正確に知らせてください。
英語での説明だけでは不十分です。
コンテキスト付きの差分情報(context diff)も送ってください。
報告者自身の作成したファイル
(サポートされていないマシンのマシン記述など)
を追加することも、
コンパイラのソースへの変更になります。
-
GCCをインストールする際に、
標準的な手順とは異なる方法をとった場合、
その詳細。
-
発見された、
正しくないと思われる動作の説明。
例えば、
「コンパイラが致命的なシグナルを受信する」、
「出力結果の208行目にあるアセンブラ命令が正しくない」など。
もちろん、
コンパイラが致命的なシグナルを受信するというバグであれば、
誰でも間違いなくそれに気がつくでしょう。
しかし、
出力が正しくないというバグであれば、
紛れもない誤りでない限り、
保守担当者はそれに気付かないかもしれません。
命令が1つ誤っているかもしれないとひそかに予期して、
50行のCのプログラムから生成されたすべてのアセンブラ・コードを調べる時間のある人間は、
私たちの中には一人としていません。
それは、
報告者であるあなたが担当してください!
たとえ致命的なシグナルを受信するような問題であっても、
報告者はそのことを明示的に報告するべきです。
何か奇妙なことが起っていると仮定しましょう。
例えば、
報告者が使っているコンパイラにちぐはぐなところがあるとか、
報告者のシステム上にあるCライブラリのバグだった、
というような場合です。
(こういうことは、実際にありました!)
このような場合、
報告者のコンパイラはクラッシュしても、
私たちのところではクラッシュしません。
クラッシュするはずであると報告されていれば、
私たちのコンパイラがクラッシュしなくても、
「私たちのところではバグが発生しない」ということを知ることができます。
クラッシュするはずであるという報告がなければ、
バグが発生したのかどうかも知ることができません。
実際の現象から、
何も結論を引き出すことができないのです。
問題になっているのが、
ほかのコンパイラでGCCをコンパイルしているときに発生した診断メッセージであれば、
それが警告なのか、
エラーなのかを知らせてください。
多くの場合、
発見された症状は、
プログラム実行中の正しくない出力結果です。
不幸なことに、
プログラムが短く単純なものでない限り、
これだけでは十分な情報とはいえません。
ある大きなプログラムが正しくコンパイルされた場合にはどう動作するべきなのかを知るために、
それを調べる余裕のある人間は、
私たちの中には一人としていません。
ましてや、
そのプログラムのどの行が誤ってコンパイルされたのかを見つけ出したりする時間のある人間は皆無です。
ですから、
これは報告者の仕事です。
どのソース行が原因なのか、
その行が実行されると、
どのような正しくない結果が起こるのかを知らせてください。
プログラムを理解している人であれば、
プログラムのバグ自身を発見するのと同じぐらい簡単に、
このようなことを明らかにすることができます。
-
GCCからのアセンブラ・コードの出力を例として送る場合は、
makeする時に`-g'を使用してください。
デバッグ情報には、
出力に対応する入力を明らかにするために必須となる、
ソース行番号が含まれています。
-
GCCのソースの中の何かについて言及する場合も、
行番号に言及するのではなく、
コンテキストに言及してください。
私たちが開発中のソースの行番号は、
報告者の持っているソースの行番号とは一致しないでしょう。
報告者から見たソースの行番号は、
保守担当者にとって役に立つ情報を提供してはくれません。
-
デバッガからの追加情報は、
手元にないマシン上で発生した問題を発見する手段を与えてくれる可能性があります。
ただし、
収集した情報を役に立たせたいのであれば、
収集時によく考える必要があります。
例えば、
バックトレースだけを送ってくる人が多くいますが、
それだけで役に立つことはありません。
引数付きの単純なバックトレースは、
GCCについて、
ほとんど情報を提供してくれません。
なぜなら、
コンパイラは主としてデータ駆動(data-driven)であるからです。
異なるRTL insnに対して、
同一の関数が何度も呼び出されます。
この同一の関数が、
insnの詳細に依存して、
異なる処理を実行するのです。
バックトレースに記述される引数のほとんどは、
RTLリスト構造へのポインタであるため、
役に立ちません。
ポインタの数値は、
デバッガがバックトレース内に出力するもので、
少しの重要性も持ちません。
重要なのは、
ポイントされるオブジェクトの内容です
(ただし、
その内容のほとんどは、
別のポインタです)。
さらに、
コンパイラのほとんどのパスは、
RTL insnシーケンスをスキャンする1つ以上のループを持っています。
そうしたループに関する情報のうち最も重要な部分は、
どのinsnに到達したかということで、
この情報は通常、
引数の中にではなく、
ローカル変数の中にあります。
バックトレースに付け加えて提供しなければならないのは、
スタックを遡って見つかる、
いくつかのスタック・フレームにおけるローカル変数の値です。
ローカル変数や引数がRTXである場合、
まずその値を出力し、
次に、
GDBコマンドの
pr
を使用して、
それがポイントするRTL式を出力します。
(報告者のマシンでGDBが動作しない場合は、
使っているデバッガで、
RTXを引数としてdebug_rtx
関数を呼び出してください。)
一般的には、
ある変数がポインタである場合、
その値がポイントするデータがなければ、
その値自身は役に立ちません。
以下に、
バグ報告に必要ではない情報をいくつか列挙します。
-
バグの包括的な説明。
バグを見つけると、
多くの時間をかけて、
入力ファイルをどのように変更するとバグが発生しなくなり、
どのように変更した場合はバグが発生し続けるかを調べる人がよくいます。
これは多くの場合、
時間のかかる作業であり、
しかもあまり役に立ちません。
というのは、
私たちがバグを見つけるのは、
単一の実例をデバッガでブレイクポイントを使いながら実行させることによってであり、
一連の実例からの純粋な演繹によってではないからです。
時間を無駄にせず、
何かほかのことに使うほうがましでしょう。
もちろん、
一番最初にバグを見つけたときの実例の代わりとなる、
もっと単純な実例を見つけることができるのであれば、
私たちにとっても便利です。
出力におけるエラーはより発見しやすいものですし、
デバッガ配下で実行させる方が時間もかかりません。
GCCのバグのほとんどは、
ただ1つの関数に関連するものであるため、
実例を単純なものにする最も簡単な方法は、
バグが発生した個所を含む関数定義以外の、
すべての関数定義を削除してしまうことです。
問題の関数が、
ファイルの前の部分にある関数定義に依存している場合は、
それらの関数定義を外部宣言文に置き換えてもよいでしょう。
(例外:インライン関数は、
ファイルの後ろのほうで定義されている関数のコンパイルに影響する可能性があります。)
しかし、
単純化は絶対に必要というわけでもありません。
こういうことをしたくないのであれば、
バグを発見したときのテスト・ケース全体を送って、
バグの報告を行ってください。
-
取り除くとバグが発生しなくなるような`#ifdef BUG'条件を、
文のまわりに挿入する人がいます。
これはソースを乱雑にするだけであり、
いずれにしろ私たちは何の注意も払いません。
そもそも報告者はcpp出力を送るべきであり、
そこに条件文が入り込むことはありません。
-
バグに対するパッチ。
バグに対するパッチは、
それが良いものであれば、
役に立ちます。
しかし、
パッチがあれば十分であるとみなして、
テスト・ケースのような必要な情報を送るのを省かないでください。
提供されたパッチに問題があり、
別の方法で問題を修正することにする場合もありますし、
提供されたパッチを全く理解できないということもあるかもしれません。
GCCのような複雑なプログラムでは、
コード中のある特定のパスを通るような実例を作成するのは困難なことがあります。
報告者が実例を送ってくれなければ、
私たちには実例を作成することができず、
したがって、
バグが修正されたことを検証することができなくなってしまいます。
また、
報告者の送ってくれたパッチがどのような問題を修正しようとしているのか私たちに理解できない場合、
あるいは、
なぜそのパッチが改善になるのか私たちが理解できない場合、
そのパッチを組み込むことはしません。
テスト・ケースがひとつでもあれば、
そのようなことを理解する手助けになるでしょう。
報告者の提供したパッチの理解とインストールを容易にするための方法については、
GCCに対するパッチの送付を参照してください。
-
バグが何であるか、
あるいは、
何に依存しているかに関する推測。
このような推測は普通間違っているものです。
私ですら、
デバッガを使って事実を見出すまでは、
このような点に関して正しく推測することはできないのです。
-
コア・ダンプ・ファイル。
報告者が使っているマシンと同一のシステムを持っていない限り、
私たちには、
そのタイプのマシンのコア・ダンプを調べる方法がありません。
一方、
もし同一のマシンがあれば、
そのマシンでクラッシュを再現できるはずです。
GNU Cコンパイラのバグ修正や改良を進んでやってくれる人がいれば、
とても助かります。
提案する修正は、
パッチのメーリング・リストgcc-patches@gcc.gnu.org
に送ってください。
以下のガイドラインに従って送信してもらえれば、
私たちはパッチを効率的に調べることができます。
ガイドラインに従ってもらえなくても、
情報は役に立つでしょうが、
余分な作業を発生させることになります。
GNU Cの保守作業は、
最良の状況においてもたいへんな作業量ですので、
皆さんが手助けしようとする際に最善の努力を払ってくれるのでなければ、
続けていくことができません。
-
変更点に関して、
それがどのような問題を修正しているのか、
またはどのような改良をもたらすのかを、
説明して送信してください。
バグ修正の場合は、
バグ報告のコピーを付けて、
その変更によってなぜバグが修正されるのかを説明してください。
(バグ報告のことを引き合いに出すだけでは、
バグ報告のコピーを付けることと比較すると不十分です。
なぜなら、
バグ報告のコピーを探し出さなければならなくなるからです。
そのバグが修正済みである場合は、
バグ報告自体を削除してしまっている可能性もあります。)
-
修正したと思う問題の正確なバグ報告を常に付けてください。
私たちは、
その変更をインストールする前に、
それが正しいものであると確信する必要があるのです。
正しいものだとしても、
問題を再現する方法がない場合には、
その判断をするのが難しくなるかもしれません。
-
将来ソースを見る人が、
この変更が必要であった理由を理解できるように、
適切なコメントをすべて記述しておいてください。
-
異なる理由で行った変更を一緒にしないでください。
それぞれの変更は個別に送付してください。
報告者が別々の理由で2つの変更を行った場合に、
私たちが両方ともインストールすることはしたくないということがあるかもしれません。
つまり、
どちらかひとつだけをインストールしたいということがあるでしょう。
すべてが乱雑にひとつの差分情報の中に入って送付されてしまうと、
それを解きほぐし、
変更のどの部分がどの目的のためのものなのかを見つけ出すための、
余分な作業が発生してしまいます。
こうした作業を行う時間がない場合、
提案者からの変更点を全く無視せざるを得なくなるかもしれません。
1つの変更を書くたびに、
その説明を付けて送付してもらえれば、
2つの変更点を混同してしまうことはありません。
私たちも両者を解きほぐす余分な手間をかけることなく、
それぞれの変更点を正しく考慮することができます。
理想的には、
送られる個々の変更は、
私たちが別々に考慮したくなるような
より小さな要素に細分化できないようなものであるべきです。
そのためには、
各変更のどの要素も、
同じ変更の他の要素から誘導されるようになっているべきです。
-
それぞれの変更は、
完成したらすぐに送付してください。
多くの変更を蓄積し、
全部をまとめて送ることが、
私たちの手助けになると考えている人がいるようです。
上述のとおり、
まとめて送るのは、
間違いなく最悪の方法です。
変更を1つずつ送付しなければならないのですから、
即座に送ることになるでしょう。
そうしてもらえれば、
重要な変更であった場合には、
私たちも即座にインストールすることができるのです。
-
差分情報を作成するには、
`diff -c'を使用してください。
コンテキストなしの差分情報では、
確実にインストールすることが難しくなります。
それ以上に、
差分情報を調査して、
インストールすべきかどうかを判断することも難しくなります。
unidiffフォーマットは、
コンテキストなしの差分情報と比較すればまだましですが、
`-c'フォーマットほど読み易くはありません。
GNU diffがある場合は、
`diff -cp'を使用してください。
これにより、
それぞれの差分が発生した関数の名称が示されます。
-
変更点に関する変更ログ・エントリを記述してください。
送られてくる変更はたくさんありますので、
私たち自身には、
すべての変更ログを記述する余裕がありません。
`ChangeLog'ファイルを読んで、
記述すべき情報の種類と、
私たちが使っているスタイルを学び取ってください。
変更ログの目的は、
どの部分で何が変更されたかを他の人に示すことにあります。
ですから、
どの関数を変更したかを明示する必要があります。
大きな関数では、
関数のどの部分が変更されたかを示すと役に立つことがよくあります。
一方、
変更した場所を示すことさえすれば、
変更の目的を説明する必要はありません。
例えば、
新しい関数を1つ追加した場合、
それが新しいということだけを記述すれば事足ります。
目的を説明する必要があると感じるような場合は、
そうすることが多分必要なのでしょうが、
コード中にコメントとして入れておいた方が、
より役立つことになるでしょう。
変更者として自分の名前をヘッダ行に表示させたい場合は、
ヘッダ行を送付してください。
-
修正を記述する場合は、
他のシステムで問題を発生させるような変更はインストールできないということを覚えておいてください。
ある問題を修正するのに、
`toplev.c'のようなマシン非依存のファイルを、
特定のシステムが必要とする何か特殊なことを実行するように変更するよう提案する人がよくいます。
このような変更を加えると、
ほぼすべてのユーザのGCCで問題を発生させてしまうということが、
まったく明らかである場合があります。
こうした変更を加えることはどうしてもできません。
せいぜい、
こうした変更提案によって、
無難に問題を解決する別のパッチを記述する方法を教えられることもある、
というのが関の山です。
全般的な改良になると思われる修正を送付してくれる人もときにはいますが、
そのような修正であるという確信に至るのは難しいことです。
こうした変更は、
慎重に調査する必要があるので、
インストールするのが困難なのです。
もちろん、
その変更が正しいと判断した理由を良く説明したものがあれば、
私たちが確信するための一助となるでしょう。
最も安全な変更は、
特定のマシンのコンフィギュレーション・ファイルへの変更です。
これが安全である理由は、
他のマシン上で新たなバグを発生させることがないからです。
私たちの作業負荷を増やさないために、
パッチは、
うまくインストールできる形式に設計してください。
[Contents] [Back] [Prev] [Up] [Next] [Forward]