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

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

このコミットは、Goランタイムのスタックトレース表示に関する改善です。具体的には、パニック発生時にruntime.panicフレームがスタックトレースに常に表示されるように変更することで、デバッグ時の情報量を増やし、パニックの発生源をより明確に理解できるようにすることを目的としています。

コミット

commit fa4984d535b23c0d2b14650a8842d63083893af3
Author: Russ Cox <rsc@golang.org>
Date:   Wed Sep 11 11:59:19 2013 -0400

    runtime: show runtime.panic frame in traceback

    Otherwise, if panic starts running deferred functions,
    the code that panicked appears to be calling those
    functions directly, which is not the case and can be
    confusing.

    For example:

    main.Two()
            /Users/rsc/x.go:12 +0x2a
    runtime.panic(0x20dc0, 0x2100cc010)
            /Users/rsc/g/go/src/pkg/runtime/panic.c:248 +0x106
    main.One()
            /Users/rsc/x.go:8 +0x55

    This makes clear(er) that main.Two is being called during
    a panic, not as a direct call from main.One.

    Fixes #5832.

    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/13302051

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

https://github.com/golang/go/commit/fa4984d535b23c0d2b14650a8842d63083893af3

元コミット内容

このコミットの元の内容は、Goランタイムが生成するスタックトレースにおいて、runtime.panic関数呼び出しのフレームを常に表示するように変更することです。これにより、パニックが発生し、遅延関数(deferred functions)が実行される際に、スタックトレースが誤解を招くような表示になる問題を解決します。

具体的には、パニックが遅延関数を実行し始めると、パニックを引き起こしたコードが、あたかもそれらの遅延関数を直接呼び出しているかのように見えてしまうことがありました。これは実際にはそうではないため、混乱を招く可能性がありました。

コミットメッセージの例では、main.Two()がパニックを引き起こし、その後にruntime.panicが呼ばれ、さらにmain.One()がスタックトレースに現れるケースが示されています。この変更により、runtime.panicフレームが明示的に表示されることで、main.Twoがパニック中に呼び出されているのであって、main.Oneからの直接の呼び出しではないことがより明確になります。

この変更は、GoのIssue #5832を修正するものです。

変更の背景

Go言語では、プログラムの実行中に予期せぬエラーが発生した場合、panicメカニズムが使用されます。panicが発生すると、通常のプログラムフローは中断され、現在のゴルーチン(goroutine)の遅延関数が実行され始めます。その後、スタックが巻き戻され(unwind)、最終的にプログラムがクラッシュするか、recover関数によってパニックが捕捉されない限り、プログラムは終了します。

このパニック処理の過程で、スタックトレースが生成され、開発者は問題の原因を特定するための重要な情報を得ることができます。しかし、このコミットが導入される以前は、runtime.panic関数自体がスタックトレースから省略されることがありました。

この省略は、特に遅延関数が複雑な処理を行う場合や、複数の関数呼び出しが絡む場合に、スタックトレースの解釈を困難にしていました。パニックを引き起こした真の関数が、あたかも遅延関数を直接呼び出しているかのように見えてしまうため、デバッグ時に誤った推論をしてしまう可能性があったのです。

Issue #5832では、この問題が具体的に報告されており、runtime.panicフレームの欠落がスタックトレースの可読性を損ね、デバッグ体験を悪化させていることが指摘されていました。このコミットは、このデバッグ上の課題を解決し、より正確で理解しやすいスタックトレースを提供することを目的としています。

前提知識の解説

Go言語のパニックとリカバリー (Panic and Recover)

  • Panic: Go言語におけるランタイムエラーの一種で、プログラムの異常終了を引き起こします。panic関数を明示的に呼び出すこともできますし、ゼロポインタ参照や配列の範囲外アクセスなどのランタイムエラーによって暗黙的に発生することもあります。panicが発生すると、現在の関数の実行は即座に停止し、その関数に登録されているdefer関数が実行されます。その後、呼び出し元の関数へとスタックが巻き戻され、各関数のdefer関数が順に実行されます。このプロセスがゴルーチンのスタックの最上位まで続くと、プログラムはクラッシュします。
  • Defer: defer文は、その関数がリターンする直前(またはパニックによってスタックが巻き戻される直前)に実行される関数を登録するために使用されます。リソースの解放(ファイルのクローズ、ロックの解除など)や、パニックからの回復(recoverの使用)によく利用されます。
  • Recover: recover関数は、defer関数内で呼び出された場合にのみ有効です。recoverが呼び出されると、現在のゴルーチンで発生しているパニックを捕捉し、パニックの値を返します。これにより、パニックによるプログラムのクラッシュを防ぎ、通常の実行フローを再開させることができます。recoverdefer関数以外で呼び出された場合、またはパニックが発生していないときに呼び出された場合、nilを返します。

スタックトレース (Stack Trace)

スタックトレースは、プログラムの実行中に特定の時点(通常はエラーやパニックが発生した時点)で、現在実行中の関数とその呼び出し元の関数がどのように連鎖しているかを示すリストです。各エントリ(フレーム)は、関数名、ファイル名、行番号、およびプログラムカウンタ(PC)オフセットなどの情報を含みます。スタックトレースは、問題の根本原因を特定し、プログラムの実行パスを理解するために不可欠なデバッグツールです。

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクタ、スケジューラ(ゴルーチンの管理)、メモリ管理、プリミティブな同期メカニズム、そしてパニック処理などが含まれます。Goプログラムがコンパイルされると、ランタイムのコードが実行可能バイナリにリンクされます。このコミットで変更されているsrc/pkg/runtime/symtab.cは、Goランタイムの一部であり、スタックトレースのシンボル解決や表示ロジックに関わるC言語のソースファイルです。

m->throwing (Goランタイム内部変数)

Goランタイムの内部では、mはM(Machine)構造体を指し、OSのスレッドを表します。m->throwingは、このMが現在パニック処理中であるかどうかを示すフラグです。このコミットでは、m->throwingが単なる真偽値ではなく、パニックの深度を示すカウンタとして扱われるようになったため、m->throwing > 0というチェックに変更されています。これは、複数のパニックが同時に発生するような稀なケース(例えば、defer関数内でさらにパニックが発生するような場合)に対応するため、または単に内部的な表現の変更によるものです。

技術的詳細

このコミットの技術的な核心は、Goランタイムのスタックトレース生成ロジック、特にruntime·showframe関数の変更にあります。

runtime·showframe関数は、スタックトレースを生成する際に、特定のフレームを表示するかどうかを決定する役割を担っています。Goのスタックトレースは、デバッグの関連性を高めるために、一部の内部ランタイム関数フレームを省略することがあります。しかし、runtime.panicフレームの省略は、パニックの発生源を曖昧にするという副作用がありました。

変更前は、m->throwingが真(パニック処理中)の場合、特定のフレーム(おそらくはパニック処理に関連する内部フレーム)を表示しないロジックがありました。このコミットでは、この条件がm->throwing > 0に変更されています。これは、m->throwingが単なるブール値ではなく、パニックの深度を示す整数値になったことを示唆しています。

最も重要な変更は、以下の新しい条件文の追加です。

// Special case: always show runtime.panic frame, so that we can
// see where a panic started in the middle of a stack trace.
// See golang.org/issue/5832.
if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
    return 1;

このコードスニペットは、runtime·showframe関数が、現在処理しているフレームの名前が"runtime.panic"であるかどうかをチェックしています。

  • name.len == 7+1+5: これは文字列"runtime.panic"の長さをチェックしています。"runtime"が7文字、.が1文字、"panic"が5文字で、合計13文字です。このハードコードされた長さチェックは、関数名の正確なマッチングを保証するための最適化または安全策です。
  • hasprefix(name, "runtime.panic"): これは、フレームの名前が文字列"runtime.panic"で始まるかどうかをチェックします。

もし現在のフレームがruntime.panic関数のものであると判断された場合、return 1;が実行されます。これは、runtime·showframe関数が1を返すことで、そのフレームをスタックトレースに含めるべきであることをランタイムに指示します。

この変更により、runtime.panicフレームは、他の省略される可能性のあるランタイムフレームとは異なり、常にスタックトレースに明示的に表示されるようになります。これにより、パニックがどの時点で、どの関数呼び出しのコンテキストで発生したのかが、デバッグ時に一目でわかるようになります。特に、遅延関数が実行されている最中にスタックトレースを分析する際に、パニックの起点と遅延関数の実行パスを区別する上で非常に役立ちます。

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

変更は、src/pkg/runtime/symtab.cファイルのruntime·showframe関数内で行われています。

--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -317,10 +317,17 @@ runtime·showframe(Func *f, G *gp)
  	static int32 traceback = -1;
  	String name;

-	if(m->throwing && gp != nil && (gp == m->curg || gp == m->caughtsig))
+	if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig))
  		return 1;
  	if(traceback < 0)
  		traceback = runtime·gotraceback(nil);
  	name = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+\
+	// Special case: always show runtime.panic frame, so that we can
+	// see where a panic started in the middle of a stack trace.
+	// See golang.org/issue/5832.
+	if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
+		return 1;
+\
  	return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");
  }

コアとなるコードの解説

  • if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig)):

    • この行は、Goランタイムの内部状態をチェックしています。m->throwingは、現在のM(OSスレッド)がパニック処理中であるかどうかを示すフラグです。以前は単なる真偽値でしたが、このコミットで> 0というチェックに変わったことから、パニックの深度を示すカウンタになった可能性が高いです。
    • gp != nilは、現在のゴルーチンポインタがnilでないことを確認します。
    • (gp == m->curg || gp == m->caughtsig)は、現在のゴルーチンが、Mが現在実行中のゴルーチンであるか、またはシグナルによって捕捉されたゴルーチンであるかを確認します。
    • これらの条件が真の場合、return 1;が実行され、現在のフレームはスタックトレースに表示されます。これは、パニック処理中に特定の重要なランタイムフレームを表示するための既存のロジックの一部です。
  • 新しい追加ブロック:

    // Special case: always show runtime.panic frame, so that we can
    // see where a panic started in the middle of a stack trace.
    // See golang.org/issue/5832.
    if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
        return 1;
    
    • このブロックがこのコミットの主要な変更点です。
    • コメントは、このコードの目的を明確に説明しています。「runtime.panicフレームを常に表示する特別なケース」であり、「スタックトレースの途中でパニックがどこで始まったかを確認できるようにする」ためであると述べています。また、関連するIssue #5832も参照しています。
    • nameは、現在処理中のスタックフレームに対応する関数の名前(String型)です。
    • name.len == 7+1+5: これは、関数名"runtime.panic"の正確な長さをチェックしています(runtimeが7文字、.が1文字、panicが5文字で合計13文字)。これは、文字列比較の効率化や、意図しない部分文字列マッチを防ぐためのガード条件として機能します。
    • hasprefix(name, "runtime.panic"): これは、関数名が正確に"runtime.panic"であるかどうかをチェックします。
    • これらの条件が両方とも真の場合(つまり、現在のフレームがruntime.panic関数のものである場合)、return 1;が実行されます。これにより、runtime.panicフレームは、他のフレームの表示条件にかかわらず、常にスタックトレースに含まれることが保証されます。
  • return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");:

    • これは、runtime·showframe関数の元の最後のreturn文です。
    • traceback > 1は、トレースバックレベルが特定の閾値を超えている場合にフレームを表示することを示します。
    • f != nilは、関数ポインタが有効であることを確認します。
    • contains(name, ".")は、関数名にドット(.)が含まれていることをチェックします。これは通常、パッケージ名と関数名を区切るために使用されるため、ユーザー定義の関数やエクスポートされた関数を示唆します。
    • !hasprefix(name, "runtime.")は、関数名が"runtime."で始まらないことをチェックします。これは、通常、内部のランタイム関数をスタックトレースから省略するための一般的なルールです。
    • この最後のreturn文は、runtime.panicフレームを常に表示するという新しいロジックが適用された後に評価されます。

この変更により、Goのデバッグ体験が向上し、パニックの根本原因を特定するプロセスがより効率的になりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Panic and Recover): https://go.dev/blog/defer-panic-and-recover
  • Goランタイムのソースコード (symtab.c): https://github.com/golang/go/blob/master/src/runtime/symtab.go (Go 1.1以降はsymtab.goに移行しているが、当時のCコードのロジックを理解するために参照)
  • Goのスタックトレースに関する議論やドキュメント (一般的な情報源)
  • GoのIssueトラッカー (Issue #5832の詳細)
  • Goのコードレビューシステム (CL 13302051の詳細)

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

このコミットは、Goランタイムのスタックトレース表示に関する改善です。具体的には、パニック発生時にruntime.panicフレームがスタックトレースに常に表示されるように変更することで、デバッグ時の情報量を増やし、パニックの発生源をより明確に理解できるようにすることを目的としています。

コミット

commit fa4984d535b23c0d2b14650a8842d63083893af3
Author: Russ Cox <rsc@golang.org>
Date:   Wed Sep 11 11:59:19 2013 -0400

    runtime: show runtime.panic frame in traceback

    Otherwise, if panic starts running deferred functions,
    the code that panicked appears to be calling those
    functions directly, which is not the case and can be
    confusing.

    For example:

    main.Two()
            /Users/rsc/x.go:12 +0x2a
    runtime.panic(0x20dc0, 0x2100cc010)
            /Users/rsc/g/go/src/pkg/runtime/panic.c:248 +0x106
    main.One()
            /Users/rsc/x.go:8 +0x55

    This makes clear(er) that main.Two is being called during
    a panic, not as a direct call from main.One.

    Fixes #5832.

    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/13302051

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

https://github.com/golang/go/commit/fa4984d535b23c0d2b14650a8842d63083893af3

元コミット内容

このコミットの元の内容は、Goランタイムが生成するスタックトレースにおいて、runtime.panic関数呼び出しのフレームを常に表示するように変更することです。これにより、パニックが発生し、遅延関数(deferred functions)が実行される際に、スタックトレースが誤解を招くような表示になる問題を解決します。

具体的には、パニックが遅延関数を実行し始めると、パニックを引き起こしたコードが、あたかもそれらの遅延関数を直接呼び出しているかのように見えてしまうことがありました。これは実際にはそうではないため、混乱を招く可能性がありました。

コミットメッセージの例では、main.Two()がパニックを引き起こし、その後にruntime.panicが呼ばれ、さらにmain.One()がスタックトレースに現れるケースが示されています。この変更により、runtime.panicフレームが明示的に表示されることで、main.Twoがパニック中に呼び出されているのであって、main.Oneからの直接の呼び出しではないことがより明確になります。

この変更は、GoのIssue #5832を修正するものです。

変更の背景

Go言語では、プログラムの実行中に予期せぬエラーが発生した場合、panicメカニズムが使用されます。panicが発生すると、通常のプログラムフローは中断され、現在のゴルーチン(goroutine)の遅延関数が実行され始めます。その後、スタックが巻き戻され(unwind)、最終的にプログラムがクラッシュするか、recover関数によってパニックが捕捉されない限り、プログラムは終了します。

このパニック処理の過程で、スタックトレースが生成され、開発者は問題の原因を特定するための重要な情報を得ることができます。しかし、このコミットが導入される以前は、runtime.panic関数自体がスタックトレースから省略されることがありました。

この省略は、特に遅延関数が複雑な処理を行う場合や、複数の関数呼び出しが絡む場合に、スタックトレースの解釈を困難にしていました。パニックを引き起こした真の関数が、あたかも遅延関数を直接呼び出しているかのように見えてしまうため、デバッグ時に誤った推論をしてしまう可能性があったのです。

Issue #5832では、この問題が具体的に報告されており、runtime.panicフレームの欠落がスタックトレースの可読性を損ね、デバッグ体験を悪化させていることが指摘されていました。このコミットは、このデバッグ上の課題を解決し、より正確で理解しやすいスタックトレースを提供することを目的としています。

前提知識の解説

Go言語のパニックとリカバリー (Panic and Recover)

  • Panic: Go言語におけるランタイムエラーの一種で、プログラムの異常終了を引き起こします。panic関数を明示的に呼び出すこともできますし、ゼロポインタ参照や配列の範囲外アクセスなどのランタイムエラーによって暗黙的に発生することもあります。panicが発生すると、現在の関数の実行は即座に停止し、その関数に登録されているdefer関数が実行されます。その後、呼び出し元の関数へとスタックが巻き戻され、各関数のdefer関数が順に実行されます。このプロセスがゴルーチンのスタックの最上位まで続くと、プログラムはクラッシュします。
  • Defer: defer文は、その関数がリターンする直前(またはパニックによってスタックが巻き戻される直前)に実行される関数を登録するために使用されます。リソースの解放(ファイルのクローズ、ロックの解除など)や、パニックからの回復(recoverの使用)によく利用されます。
  • Recover: recover関数は、defer関数内で呼び出された場合にのみ有効です。recoverが呼び出されると、現在のゴルーチンで発生しているパニックを捕捉し、パニックの値を返します。これにより、パニックによるプログラムのクラッシュを防ぎ、通常の実行フローを再開させることができます。recoverdefer関数以外で呼び出された場合、またはパニックが発生していないときに呼び出された場合、nilを返します。

スタックトレース (Stack Trace)

スタックトレースは、プログラムの実行中に特定の時点(通常はエラーやパニックが発生した時点)で、現在実行中の関数とその呼び出し元の関数がどのように連鎖しているかを示すリストです。各エントリ(フレーム)は、関数名、ファイル名、行番号、およびプログラムカウンタ(PC)オフセットなどの情報を含みます。スタックトレースは、問題の根本原因を特定し、プログラムの実行パスを理解するために不可欠なデバッグツールです。

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクタ、スケジューラ(ゴルーチンの管理)、メモリ管理、プリミティブな同期メカニズム、そしてパニック処理などが含まれます。Goプログラムがコンパイルされると、ランタイムのコードが実行可能バイナリにリンクされます。このコミットで変更されているsrc/pkg/runtime/symtab.cは、Goランタイムの一部であり、スタックトレースのシンボル解決や表示ロジックに関わるC言語のソースファイルです。

m->throwing (Goランタイム内部変数)

Goランタイムの内部では、mはM(Machine)構造体を指し、OSのスレッドを表します。m->throwingは、このMが現在パニック処理中であるかどうかを示すフラグです。このコミットでは、m->throwingが単なる真偽値ではなく、パニックの深度を示すカウンタとして扱われるようになったため、m->throwing > 0というチェックに変更されています。これは、複数のパニックが同時に発生するような稀なケース(例えば、defer関数内でさらにパニックが発生するような場合)に対応するため、または単に内部的な表現の変更によるものです。

技術的詳細

このコミットの技術的な核心は、Goランタイムのスタックトレース生成ロジック、特にruntime·showframe関数の変更にあります。

runtime·showframe関数は、スタックトレースを生成する際に、特定のフレームを表示するかどうかを決定する役割を担っています。Goのスタックトレースは、デバッグの関連性を高めるために、一部の内部ランタイム関数フレームを省略することがあります。しかし、runtime.panicフレームの省略は、パニックの発生源を曖昧にするという副作用がありました。

変更前は、m->throwingが真(パニック処理中)の場合、特定のフレーム(おそらくはパニック処理に関連する内部フレーム)を表示しないロジックがありました。このコミットでは、この条件がm->throwing > 0に変更されています。これは、m->throwingが単なるブール値ではなく、パニックの深度を示す整数値になったことを示唆しています。

最も重要な変更は、以下の新しい条件文の追加です。

// Special case: always show runtime.panic frame, so that we can
// see where a panic started in the middle of a stack trace.
// See golang.org/issue/5832.
if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
    return 1;

このコードスニペットは、runtime·showframe関数が、現在処理しているフレームの名前が"runtime.panic"であるかどうかをチェックしています。

  • name.len == 7+1+5: これは文字列"runtime.panic"の長さをチェックしています。"runtime"が7文字、.が1文字、"panic"が5文字で、合計13文字です。このハードコードされた長さチェックは、関数名の正確なマッチングを保証するための最適化または安全策です。
  • hasprefix(name, "runtime.panic"): これは、フレームの名前が文字列"runtime.panic"で始まるかどうかをチェックします。

もし現在のフレームがruntime.panic関数のものであると判断された場合、return 1;が実行されます。これは、runtime·showframe関数が1を返すことで、そのフレームをスタックトレースに含めるべきであることをランタイムに指示します。

この変更により、runtime.panicフレームは、他の省略される可能性のあるランタイムフレームとは異なり、常にスタックトレースに明示的に表示されるようになります。これにより、パニックがどの時点で、どの関数呼び出しのコンテキストで発生したのかが、デバッグ時に一目でわかるようになります。特に、遅延関数が実行されている最中にスタックトレースを分析する際に、パニックの起点と遅延関数の実行パスを区別する上で非常に役立ちます。

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

変更は、src/pkg/runtime/symtab.cファイルのruntime·showframe関数内で行われています。

--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -317,10 +317,17 @@ runtime·showframe(Func *f, G *gp)
  	static int32 traceback = -1;
  	String name;

-	if(m->throwing && gp != nil && (gp == m->curg || gp == m->caughtsig))
+	if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig))
  		return 1;
  	if(traceback < 0)
  		traceback = runtime·gotraceback(nil);
  	name = runtime·gostringnocopy((uint8*)runtime·funcname(f));
+\
+	// Special case: always show runtime.panic frame, so that we can
+	// see where a panic started in the middle of a stack trace.
+	// See golang.org/issue/5832.
+	if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
+		return 1;
+\
  	return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");
  }

コアとなるコードの解説

  • if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig)):

    • この行は、Goランタイムの内部状態をチェックしています。m->throwingは、現在のM(OSスレッド)がパニック処理中であるかどうかを示すフラグです。以前は単なる真偽値でしたが、このコミットで> 0というチェックに変わったことから、パニックの深度を示すカウンタになった可能性が高いです。
    • gp != nilは、現在のゴルーチンポインタがnilでないことを確認します。
    • (gp == m->curg || gp == m->caughtsig)は、現在のゴルーチンが、Mが現在実行中のゴルーチンであるか、またはシグナルによって捕捉されたゴルーチンであるかを確認します。
    • これらの条件が真の場合、return 1;が実行され、現在のフレームはスタックトレースに表示されます。これは、パニック処理中に特定の重要なランタイムフレームを表示するための既存のロジックの一部です。
  • 新しい追加ブロック:

    // Special case: always show runtime.panic frame, so that we can
    // see where a panic started in the middle of a stack trace.
    // See golang.org/issue/5832.
    if(name.len == 7+1+5 && hasprefix(name, "runtime.panic"))
        return 1;
    
    • このブロックがこのコミットの主要な変更点です。
    • コメントは、このコードの目的を明確に説明しています。「runtime.panicフレームを常に表示する特別なケース」であり、「スタックトレースの途中でパニックがどこで始まったかを確認できるようにする」ためであると述べています。また、関連するIssue #5832も参照しています。
    • nameは、現在処理中のスタックフレームに対応する関数の名前(String型)です。
    • name.len == 7+1+5: これは、関数名"runtime.panic"の正確な長さをチェックしています(runtimeが7文字、.が1文字、panicが5文字で合計13文字)。これは、文字列比較の効率化や、意図しない部分文字列マッチを防ぐためのガード条件として機能します。
    • hasprefix(name, "runtime.panic"): これは、関数名が正確に"runtime.panic"であるかどうかをチェックします。
    • これらの条件が両方とも真の場合(つまり、現在のフレームがruntime.panic関数のものである場合)、return 1;が実行されます。これにより、runtime.panicフレームは、他のフレームの表示条件にかかわらず、常にスタックトレースに含まれることが保証されます。
  • return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime.");:

    • これは、runtime·showframe関数の元の最後のreturn文です。
    • traceback > 1は、トレースバックレベルが特定の閾値を超えている場合にフレームを表示することを示します。
    • f != nilは、関数ポインタが有効であることを確認します。
    • contains(name, ".")は、関数名にドット(.)が含まれていることをチェックします。これは通常、パッケージ名と関数名を区切るために使用されるため、ユーザー定義の関数やエクスポートされた関数を示唆します。
    • !hasprefix(name, "runtime.")は、関数名が"runtime."で始まらないことをチェックします。これは、通常、内部のランタイム関数をスタックトレースから省略するための一般的なルールです。
    • この最後のreturn文は、runtime.panicフレームを常に表示するという新しいロジックが適用された後に評価されます。

この変更により、Goのデバッグ体験が向上し、パニックの根本原因を特定するプロセスがより効率的になりました。

関連リンク

参考にした情報源リンク