Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1213] ファイルの概要

このコミットは、Go言語のランタイムにおけるパニックメッセージの表示方法に関する変更です。具体的には、パニック発生時に出力されるメッセージから、誤った行番号の表示を削除し、より正確な情報のみを表示するように修正しています。これにより、開発者がパニックメッセージから誤解を招く情報を得ることを防ぎ、デバッグの精度を向上させます。

コミット

commit 60db3d6d3ff1f306d889a24f22615469740995a9
Author: Rob Pike <r@golang.org>
Date:   Thu Nov 20 23:16:31 2008 -0800

    don't print (incorrect anyway) line numbers in panic.
    
    R=rsc
    DELTA=4  (0 added, 2 deleted, 2 changed)
    OCL=19757
    CL=19763

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/60db3d6d3ff1f306d889a24f22615469740995a9

元コミット内容

このコミットの目的は、「パニック時に(いずれにせよ不正確な)行番号を表示しない」ことです。

具体的には、Goランタイムのパニック処理において、パニックメッセージに含められていた行番号の表示を削除します。これは、表示される行番号が実際には正しくない場合があるため、誤解を招く情報を排除し、デバッグの妨げにならないようにするための修正です。

変更は主にsrc/runtime/runtime.cファイルで行われ、パニックメッセージのフォーマットが変更されています。また、この変更に伴い、テストの期待出力ファイルであるtest/golden.outも更新されています。

変更の背景

Go言語の初期段階において、ランタイムがパニック(プログラムの回復不可能なエラー)を検出した際に、デバッグ情報としてパニックが発生したソースコードの行番号を出力する機能がありました。しかし、この行番号の計算や取得方法に問題があり、多くの場合、出力される行番号が実際のパニック発生箇所と一致しない、あるいは誤った場所を指し示すことが判明しました。

このような不正確な情報は、開発者がバグの原因を特定しようとする際に混乱を招き、デバッグ作業を困難にする可能性があります。Rob Pike氏によるこのコミットは、この問題を認識し、誤った情報を表示するよりも、その情報を完全に削除する方が、開発者にとって有益であるという判断に基づいています。これにより、パニックメッセージはより簡潔になり、誤解の余地がなくなります。

前提知識の解説

Go言語のパニック (Panic)

Go言語における「パニック (panic)」は、プログラムが回復不可能なエラー状態に陥った際に発生するメカニズムです。これは、通常のエラーハンドリング(errorインターフェースを用いたもの)では対処できないような、予期せぬ致命的な状況(例: nilポインタのデリファレンス、配列の範囲外アクセスなど)で利用されます。

パニックが発生すると、現在のゴルーチン(Goにおける軽量スレッド)の実行は即座に停止し、遅延関数(defer文で登録された関数)が実行されながら、コールスタックを遡っていきます。もし、スタックの途中でrecover関数が呼び出されなければ、プログラム全体が終了し、パニックメッセージとスタックトレースが出力されます。このスタックトレースは、パニックが発生した時点までの関数呼び出しの履歴を示し、デバッグに非常に役立ちます。

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理する低レベルのシステムです。これには、ガベージコレクタ、スケジューラ(ゴルーチンの管理)、メモリ管理、システムコールインターフェース、そしてパニック処理などが含まれます。Goプログラムは、コンパイル時にGoランタイムとリンクされ、実行可能ファイルの一部となります。

src/runtime/runtime.cは、GoランタイムのC言語で書かれた部分です。Go言語自体はGoで書かれていますが、初期のランタイムの一部や、OSとのインタフェースに近い部分は、C言語やアセンブリ言語で実装されていました。これは、OSの低レベル機能へのアクセスや、パフォーマンスが特に要求される部分でC言語が適していたためです。このファイルには、パニック処理のような重要な低レベル機能の実装が含まれています。

test/golden.outファイル

test/golden.outのような「ゴールデンファイル(Golden File)」は、ソフトウェアテストにおいて、プログラムの出力が期待される正確な内容と一致するかどうかを検証するために使用されるファイルです。テスト実行時に生成される出力と、事前に用意されたゴールデンファイルの内容を比較することで、プログラムの動作が意図通りであることを確認します。

このコミットでは、パニックメッセージのフォーマットが変更されたため、パニックメッセージを含むテストの期待出力も更新する必要がありました。test/golden.outの変更は、この新しいパニックメッセージのフォーマットが、テストシステムによって正しく認識されるようにするためのものです。

技術的詳細

このコミットの技術的な核心は、Goランタイムのパニック処理ルーチンであるsys·panicl関数における出力フォーマットの変更です。

Goランタイムは、C言語で書かれた部分で、sys·paniclのような関数を通じて低レベルの操作を行います。

  • prints関数は、Goランタイム内部で文字列を出力するための関数です。これは標準Cライブラリのprintfとは異なり、ランタイムの初期化段階や、より低レベルなデバッグ出力のために使用されます。
  • sys·printint関数は、整数値を出力するためのランタイム内部関数です。
  • sys·printpc関数は、プログラムカウンタ(PC)の値、つまり現在実行中の命令のアドレスを出力するためのランタイム内部関数です。これは、パニック発生時の実行位置を特定する上で重要な情報です。

変更前は、sys·panicl関数内で以下のようなコードがありました。

prints("\npanic on line ");
sys·printint(lno); // lno は行番号
prints(" ");
sys·printpc(&lno);
prints("\n");

これにより、パニックメッセージは「panic on line [行番号] PC=xxx」のような形式で出力されていました。しかし、lno(行番号)の値が常に正確であるとは限らないという問題がありました。これは、コンパイラの最適化、インライン化、またはランタイムがソースコードの行番号を正確に追跡するためのメカニズムがまだ成熟していなかった初期のGoの制約によるものと考えられます。

このコミットでは、不正確な行番号の表示を削除するために、sys·printint(lno);とそれに付随するprints(" on line ");およびprints(" ");の呼び出しが削除されました。

変更後のコードは以下のようになります。

prints("\npanic ");
sys·printpc(&lno);
prints("\n");

これにより、パニックメッセージは「panic PC=xxx」という形式に簡略化され、誤解を招く可能性のある行番号の情報が排除されました。

コアとなるコードの変更箇所

src/runtime/runtime.c

--- a/src/runtime/runtime.c
+++ b/src/runtime/runtime.c
@@ -23,9 +23,7 @@ sys·panicl(int32 lno)
 {
 	uint8 *sp;

-	prints("\npanic on line ");
-	sys·printint(lno);
-	prints(" ");
+	prints("\npanic ");
 	sys·printpc(&lno);
 	prints("\n");
 	sp = (uint8*)&lno;

test/golden.out

--- a/test/golden.out
+++ b/test/golden.out
@@ -146,7 +146,7 @@ BUG: should compile
 =========== bugs/bug119.go
 3 74256

-panic on line 85 PC=xxx
+panic PC=xxx
 BUG: should not fail

 =========== bugs/bug120.go

コアとなるコードの解説

src/runtime/runtime.c の変更

このファイルはGoランタイムのC言語部分であり、sys·panicl関数はパニック処理の核心を担っています。

  • 削除された行:

    • prints("\npanic on line ");
    • sys·printint(lno);
    • prints(" "); これらの行は、パニックメッセージの一部として「panic on line [行番号] 」という文字列と、lno変数に格納された行番号を出力していました。コミットメッセージにあるように、このlnoが「incorrect anyway(いずれにせよ不正確)」であったため、これらの出力が削除されました。
  • 変更された行:

    • prints("\npanic "); この行は、以前の「\npanic on line 」から「\npanic 」へと変更されました。これにより、行番号に関する記述が完全に削除され、パニックメッセージが簡潔になります。

この変更により、パニックメッセージは「panic PC=xxx」という形式になり、プログラムカウンタ(PC)のみが正確な情報として提供されるようになります。PCは、パニックが発生した時点での命令ポインタの値であり、デバッグ時にアセンブリレベルでの実行位置を特定するのに役立ちます。

test/golden.out の変更

このファイルは、テストの期待出力を記録するゴールデンファイルです。

  • 変更された行:
    • -panic on line 85 PC=xxx
    • +panic PC=xxx この変更は、src/runtime/runtime.cにおけるパニックメッセージのフォーマット変更を反映したものです。以前のテストでは「panic on line 85 PC=xxx」という出力が期待されていましたが、ランタイムの変更により行番号が出力されなくなったため、期待出力も「panic PC=xxx」に更新されました。これにより、テストが新しいパニックメッセージフォーマットと一致し、引き続き正しく機能することが保証されます。

関連リンク

  • Go言語のパニックとリカバリーに関する公式ドキュメントやチュートリアル(当時のものに直接アクセスすることは難しいですが、現在のGoのドキュメントで概念を理解できます)
  • Go言語の初期のランタイム設計に関する議論やメーリングリストのアーカイブ(Goの歴史的な文脈を理解するのに役立つ可能性があります)

参考にした情報源リンク