[インデックス 15786] ファイルの概要
このコミットは、Go言語のランタイムにおいて、GOTRACEBACK
環境変数にcrash
という新しいオプションを追加するものです。これにより、パニック発生時に通常のトレースバック出力に加えて、オペレーティングシステム固有の方法でプログラムをクラッシュさせ、コアダンプを生成できるようになります。これは、特に本番環境でのデバッグにおいて、詳細なメモリ状態を分析するために非常に有用な機能です。
コミット
commit 5146a93e72e870b06150c5419e1b83056ecc697b
Author: Russ Cox <rsc@golang.org>
Date: Fri Mar 15 01:11:03 2013 -0400
runtime: accept GOTRACEBACK=crash to mean 'crash after panic'
This provides a way to generate core dumps when people need them.
The settings are:
GOTRACEBACK=0 no traceback on panic, just exit
GOTRACEBACK=1 default - traceback on panic, then exit
GOTRACEBACK=2 traceback including runtime frames on panic, then exit
GOTRACEBACK=crash traceback including runtime frames on panic, then crash
Fixes #3257.
R=golang-dev, devon.odell, r, daniel.morsing, ality
CC=golang-dev
https://golang.org/cl/7666044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5146a93e72e870b06150c5419e1b83056ecc697b
元コミット内容
Goランタイムにおいて、GOTRACEBACK=crash
という設定を受け入れるように変更しました。これは「パニック後にクラッシュする」ことを意味します。
この変更は、ユーザーがコアダンプを必要とする場合に、それを生成する手段を提供します。GOTRACEBACK
の設定は以下の通りです。
GOTRACEBACK=0
: パニック時にトレースバックを出力せず、すぐに終了します。GOTRACEBACK=1
: デフォルト設定。パニック時にトレースバックを出力し、その後終了します。GOTRACEBACK=2
: パニック時にランタイムフレームを含むトレースバックを出力し、その後終了します。GOTRACEBACK=crash
: パニック時にランタイムフレームを含むトレースバックを出力し、その後クラッシュします。
この変更は、Issue #3257 を修正するものです。
変更の背景
Goプログラムがパニック(予期せぬエラー)を起こして終了する際、通常はスタックトレースが出力されます。しかし、このスタックトレースだけでは、複雑な問題やメモリ破損などの根本原因を特定するのが難しい場合があります。特に、本番環境で発生する再現性の低いバグや、デッドロック、メモリリークといった問題のデバッグには、プログラムがクラッシュした時点のメモリ状態を完全に記録した「コアダンプ」が不可欠です。
従来のGOTRACEBACK
設定では、トレースバックの冗長性を制御できましたが、プログラムを意図的にクラッシュさせてコアダンプを生成する直接的な手段がありませんでした。開発者は、Goプログラムがパニックした際に、より詳細なデバッグ情報を得るためにコアダンプを生成したいというニーズを抱えていました。
このコミットは、Issue #3257 で議論されたこのニーズに応えるもので、GOTRACEBACK=crash
という新しいオプションを導入することで、パニック発生時にOSレベルでのクラッシュ(通常はSIGABRTシグナルを発生させることによる)をトリガーし、コアダンプの生成を可能にすることを目的としています。これにより、Goプログラムのデバッグ能力が大幅に向上し、特に本番環境での問題解決に貢献します。
前提知識の解説
1. Go言語のパニックとリカバリ (Panic and Recover)
Go言語には、プログラムの異常終了を扱うためのpanic
とrecover
という組み込み関数があります。
panic
: 実行時エラーやプログラマが意図的に呼び出すことで、現在のゴルーチン(軽量スレッド)の通常の実行フローを中断させます。パニックが発生すると、そのゴルーチンはスタックを巻き戻し(unwind)、遅延関数(defer
で登録された関数)が実行されます。もし、recover
によってパニックが捕捉されなければ、プログラム全体が終了します。recover
:defer
関数内で呼び出されることで、パニックを捕捉し、そのゴルーチンの実行を再開させることができます。これにより、プログラムの異常終了を防ぎ、エラーハンドリングを行うことが可能です。
このコミットは、recover
されずにプログラム全体が終了するパニックに焦点を当てています。
2. スタックトレース (Stack Trace)
プログラムがパニックやエラーで終了する際に、その時点での関数呼び出しの履歴(コールスタック)を表示したものです。これにより、どの関数がどの関数を呼び出し、最終的にどこでエラーが発生したのかを追跡できます。GoのGOTRACEBACK
環境変数は、このスタックトレースの表示レベルを制御します。
3. コアダンプ (Core Dump)
プログラムがクラッシュした時点のメモリイメージをファイルに保存したものです。このファイルには、プログラムの実行中に使用されていたすべてのメモリ内容(変数、スタック、ヒープなど)が含まれます。コアダンプは、デバッガ(例: GDB、LLDB)で開くことができ、クラッシュ時のプログラムの状態を詳細に分析するために使用されます。メモリ破損、ポインタの不正アクセス、デッドロックなど、スタックトレースだけでは原因特定が難しい複雑なバグの解析に不可欠です。
4. シグナル (Signals)
Unix系OSにおけるプロセス間通信(IPC)の一種で、ソフトウェア割り込みのようなものです。OSがプロセスに対して特定のイベント(例: 割り込み、エラー、終了要求)を通知するために使用します。
- SIGABRT (Abort Signal): プロセス自身が異常終了を要求する際に送信されるシグナルです。通常、
abort()
関数を呼び出すことで発生し、デフォルトではコアダンプを生成してプロセスを終了させます。 - SIGPIPE (Broken Pipe Signal): パイプやソケットへの書き込み中に、読み込み側がクローズされた場合に発生するシグナルです。デフォルトではプロセスを終了させます。このコミットでは、既存の
raisesigpipe
関数がより汎用的なraise
関数に置き換えられ、SIGABRTを送信するために利用されます。
5. 環境変数 GOTRACEBACK
Goプログラムの実行時に、パニック発生時のトレースバックの挙動を制御する環境変数です。
GOTRACEBACK=0
: トレースバックを完全に抑制します。GOTRACEBACK=1
(デフォルト): ランタイム内部のフレームを除外したトレースバックを表示します。GOTRACEBACK=2
: ランタイム内部のフレームを含む完全なトレースバックを表示します。GOTRACEBACK=crash
(このコミットで追加): ランタイム内部のフレームを含む完全なトレースバックを表示した後、OS固有の方法でプログラムをクラッシュさせ、コアダンプを生成します。
技術的詳細
このコミットの主要な技術的変更点は、GOTRACEBACK
環境変数にcrash
オプションを追加し、Goランタイムがパニック時にOSレベルでのクラッシュをトリガーするメカニズムを導入したことです。
-
GOTRACEBACK
値の解析の拡張:src/pkg/runtime/runtime.c
内のruntime·gotraceback
関数が変更されました。- この関数は、以前は
GOTRACEBACK
の値(0, 1, 2)を整数として解析していましたが、新たに"crash"
という文字列も認識するようになりました。 runtime·gotraceback
関数は、bool *crash
という新しい引数を受け取るようになりました。GOTRACEBACK="crash"
が設定されている場合、このcrash
ポインタが指す値がtrue
に設定されます。これにより、呼び出し元はパニック後にクラッシュ処理を行うべきかどうかを判断できます。
-
runtime·crash
関数の導入:runtime·crash
という新しい関数が導入されました。この関数は、OS固有の方法でプログラムをクラッシュさせる責任を負います。- Unix系システム(Linux, FreeBSD, NetBSD, OpenBSD, Darwin)では、
src/pkg/runtime/signal_unix.c
にruntime·crash
が実装されています。この実装では、まずSIGABRT
シグナルのハンドラをデフォルトに戻し(runtime·setsig(SIGABRT, SIG_DFL, false)
)、その後SIGABRT
シグナルを自身に送信します(runtime·raise(SIGABRT)
)。SIGABRT
のデフォルトの挙動はコアダンプを生成して終了することです。 - macOS (Darwin) の64-bitシステムでは、コアダンプが非常に大きくなる(128GB以上)可能性があるため、
runtime·crash
関数は意図的に何もしないように実装されています。これは、ユーザーが誤って巨大なコアダンプを生成し、システムリソースを消費するのを防ぐための配慮です。 - Windowsシステムでは、
src/pkg/runtime/os_windows.c
にruntime·crash
のスタブが追加されています。コメントには「Goがシグナルをインターセプトしない場合と同様に、Windowsプログラムをアボート/クラッシュさせるために必要なことを行うべき」と記載されており、この時点ではまだ具体的な実装は行われていませんが、将来的な拡張の余地が残されています。
-
シグナルハンドラとパニック処理の変更:
src/pkg/runtime/panic.c
内のruntime·dopanic
関数や、各OSのシグナルハンドラ(例:src/pkg/runtime/os_plan9_386.c
、src/pkg/runtime/signal_386.c
など)が変更されました。- これらの関数は、
runtime·gotraceback
を呼び出す際に、crash
フラグを受け取るように修正されました。 - トレースバックの出力後、もし
crash
フラグがtrue
であれば、runtime·crash()
関数が呼び出され、プログラムが意図的にクラッシュさせられます。
-
runtime·raisesigpipe
からruntime·raise
への汎用化:- 以前は
SIGPIPE
シグナルを発生させるためのruntime·raisesigpipe
という関数がありましたが、これがより汎用的なruntime·raise(int32 sig)
関数に置き換えられました。 - この
runtime·raise
関数は、引数として任意のシグナル番号を受け取り、そのシグナルを現在のプロセス(またはスレッド)に送信します。これにより、runtime·crash
関数がSIGABRT
を送信するためにこの汎用関数を利用できるようになりました。 - 各OS/アーキテクチャ固有のアセンブリファイル(例:
src/pkg/runtime/sys_darwin_386.s
、src/pkg/runtime/sys_linux_amd64.s
など)で、runtime·raisesigpipe
の実装がruntime·raise
の実装に置き換えられ、引数としてシグナル番号を受け取るように変更されています。
- 以前は
これらの変更により、Goプログラムはパニック時に開発者が望む形でコアダンプを生成できるようになり、デバッグの選択肢が広がりました。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと、その変更の概要は以下の通りです。
-
src/pkg/runtime/extern.go
:GOTRACEBACK
環境変数の説明が更新され、crash
オプションが追加されました。
-
src/pkg/runtime/runtime.c
:runtime·gotraceback
関数のシグネチャがint32 runtime·gotraceback(bool *crash)
に変更され、crash
ポインタを介してGOTRACEBACK="crash"
が設定されたかどうかを呼び出し元に通知するようになりました。GOTRACEBACK="crash"
の場合に*crash = true
を設定し、トレースバックレベルとして2
(ランタイムフレームを含む)を返すロジックが追加されました。
-
src/pkg/runtime/runtime.h
:runtime·gotraceback
関数のプロトタイプが更新され、bool *crash
引数が追加されました。runtime·crash
関数のプロトタイプが追加されました。
-
src/pkg/runtime/panic.c
:runtime·dopanic
関数内でruntime·gotraceback
を呼び出す際に、crash
フラグを受け取るように変更されました。- トレースバック出力後、
crash
フラグがtrue
の場合にruntime·crash()
を呼び出すロジックが追加されました。
-
src/pkg/runtime/proc.c
:runtime·tracebackothers
関数内でruntime·gotraceback
を呼び出す際に、nil
を渡すように変更されました(このコンテキストではクラッシュは不要なため)。
-
src/pkg/runtime/signal_unix.c
:runtime·crash
関数が実装されました。この関数は、SIGABRT
シグナルのハンドラをデフォルトに戻し、runtime·raise(SIGABRT)
を呼び出してプロセスをクラッシュさせます。- macOS (Darwin) の64-bitシステムでは、巨大なコアダンプを避けるために
runtime·crash
が何もしないように実装されています。 os·sigpipe
関数内でruntime·raisesigpipe()
の代わりにruntime·raise(SIGPIPE)
が呼び出されるように変更されました。
-
src/pkg/runtime/signal_unix.h
:runtime·raisesigpipe
のプロトタイプが削除され、runtime·raise(int32)
のプロトタイプが追加されました。
-
src/pkg/runtime/os_plan9.c
,src/pkg/runtime/os_plan9_386.c
,src/pkg/runtime/os_plan9_amd64.c
:- Plan 9 向けの
runtime·crash
関数が追加されました。 - シグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- Plan 9 向けの
-
src/pkg/runtime/os_windows.c
,src/pkg/runtime/os_windows_386.c
,src/pkg/runtime/os_windows_amd64.c
:- Windows 向けの
runtime·crash
関数のスタブが追加されました。 - シグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- Windows 向けの
-
src/pkg/runtime/signal_386.c
,src/pkg/runtime/signal_amd64.c
,src/pkg/runtime/signal_arm.c
:- 各アーキテクチャのシグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- 各アーキテクチャのシグナルハンドラ内で
-
src/pkg/runtime/symtab.c
:runtime·showframe
関数内でruntime·gotraceback
を呼び出す際に、nil
を渡すように変更されました。
-
src/pkg/runtime/sys_darwin_386.s
,src/pkg/runtime/sys_darwin_amd64.s
,src/pkg/runtime/sys_freebsd_*.s
,src/pkg/runtime/sys_linux_*.s
,src/pkg/runtime/sys_netbsd_*.s
,src/pkg/runtime/sys_openbsd_*.s
:- 各OS/アーキテクチャ固有のアセンブリファイルで、
runtime·raisesigpipe
の実装がruntime·raise
の実装に置き換えられ、引数としてシグナル番号を受け取るように変更されました。
- 各OS/アーキテクチャ固有のアセンブリファイルで、
コアとなるコードの解説
runtime·gotraceback
関数の変更 (src/pkg/runtime/runtime.c
)
// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
// GOTRACEBACK=0 suppress all tracebacks
// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
// GOTRACEBACK=2 show tracebacks including runtime frames
// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
int32
runtime·gotraceback(bool *crash)
{
byte *p;
if(crash != nil)
*crash = false;
p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
if(runtime·strcmp(p, (byte*)"crash") == 0) {
if(crash != nil)
*crash = true;
return 2; // extra information
}
return runtime·atoi(p);
}
この関数は、GOTRACEBACK
環境変数の値を読み取り、パニック時のトレースバックの挙動を決定します。
変更点として、bool *crash
という新しい引数が追加されました。これは、呼び出し元がパニック後にクラッシュ処理を行うべきかどうかを知るためのフラグです。
GOTRACEBACK
が設定されていないか空の場合、デフォルトの1
(トレースバック表示)を返します。GOTRACEBACK
が"crash"
と設定されている場合、crash
ポインタがnil
でなければ*crash
をtrue
に設定し、トレースバックレベルとして2
(ランタイムフレームを含む)を返します。- それ以外の場合、環境変数の値を整数として解析して返します。
runtime·crash
関数の実装 (src/pkg/runtime/signal_unix.c
- Unix系OSの場合)
void
runtime·crash(void)
{
#ifdef GOOS_darwin
// OS X core dumps are linear dumps of the mapped memory,
// from the first virtual byte to the last, with zeros in the gaps.
// Because of the way we arrange the address space on 64-bit systems,
// this means the OS X core file will be >128 GB and even on a zippy
// workstation can take OS X well over an hour to write (uninterruptible).
// Save users from making that mistake.
if(sizeof(void*) == 8)
return;
#endif
runtime·setsig(SIGABRT, SIG_DFL, false);
runtime·raise(SIGABRT);
}
このruntime·crash
関数は、GoプログラムをOSレベルでクラッシュさせるための主要なロジックを含んでいます。
- macOS (Darwin) 64-bitの特殊処理:
GOOS_darwin
が定義されており、かつポインタサイズが8バイト(64-bitシステム)の場合、関数はすぐにリターンします。これは、macOSのコアダンプの特性(マッピングされたメモリの線形ダンプであり、64-bitシステムでは非常に巨大なファイルになる)を考慮し、ユーザーが意図せず巨大なコアダンプを生成してしまうのを防ぐためのものです。 - SIGABRTの送信: それ以外のUnix系OSでは、まず
SIGABRT
シグナルのハンドラをデフォルト(SIG_DFL
)に戻します。これにより、Goランタイムが設定したカスタムシグナルハンドラが解除され、OSがSIGABRT
を処理する際のデフォルトの挙動(通常はコアダンプの生成とプロセス終了)が有効になります。 runtime·raise(SIGABRT)
: その後、runtime·raise
関数を呼び出して自身にSIGABRT
シグナルを送信します。これにより、プログラムはクラッシュし、コアダンプが生成されます。
runtime·raise
関数の導入と各OS/アーキテクチャのアセンブリ変更
以前はruntime·raisesigpipe
という特定のシグナル(SIGPIPE)を発生させる関数がありましたが、このコミットでruntime·raise(int32 sig)
という汎用的な関数に置き換えられました。この関数は、引数として渡されたシグナル番号を現在のプロセス/スレッドに送信します。
例えば、src/pkg/runtime/sys_darwin_amd64.s
では、以下のように変更されています。
// Old: TEXT runtime·raisesigpipe(SB),7,$24
// Old: ... (SIGPIPEを送信するロジック)
// New:
TEXT runtime·raise(SB),7,$24
MOVL $(0x2000000+20), AX // getpid
SYSCALL
MOVQ AX, DI // arg 1 - pid
MOVL sig+0(FP), SI // arg 2 - signal (引数から取得)
MOVL $(0x2000000+37), AX // kill
SYSCALL
RET
このアセンブリコードは、macOS (amd64) においてkill
システムコールを使用して指定されたシグナルを送信する処理を示しています。sig+0(FP)
は、関数に渡されたsig
引数の値(シグナル番号)をレジスタにロードしています。これにより、runtime·crash
関数がruntime·raise(SIGABRT)
を呼び出すことで、OSがコアダンプを生成するような形でプログラムを終了させることが可能になります。
これらの変更により、GoランタイムはGOTRACEBACK=crash
設定に応じて、OSの機能を利用して意図的にコアダンプを生成するメカニズムを確立しました。
関連リンク
- Go Issue #3257: runtime: GOTRACEBACK=crash to mean 'crash after panic'
- Go CL 7666044: runtime: accept GOTRACEBACK=crash to mean 'crash after panic'
- Go Documentation:
runtime
package (Environment Variables section)- https://pkg.go.dev/runtime (現在のドキュメントでは
GOTRACEBACK
の詳細が記載されています)
- https://pkg.go.dev/runtime (現在のドキュメントでは
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Unix/Linuxシグナルに関する一般的な情報源 (例:
man 7 signal
) - コアダンプに関する一般的な情報源
- GDB (GNU Debugger) のドキュメント (コアダンプの分析方法について)
- https://github.com/golang/go/issues/3257
- https://golang.org/cl/7666044
- https://pkg.go.dev/runtime# [インデックス 15786] ファイルの概要
このコミットは、Go言語のランタイムにおいて、GOTRACEBACK
環境変数にcrash
という新しいオプションを追加するものです。これにより、パニック発生時に通常のトレースバック出力に加えて、オペレーティングシステム固有の方法でプログラムをクラッシュさせ、コアダンプを生成できるようになります。これは、特に本番環境でのデバッグにおいて、詳細なメモリ状態を分析するために非常に有用な機能です。
コミット
commit 5146a93e72e870b06150c5419e1b83056ecc697b
Author: Russ Cox <rsc@golang.org>
Date: Fri Mar 15 01:11:03 2013 -0400
runtime: accept GOTRACEBACK=crash to mean 'crash after panic'
This provides a way to generate core dumps when people need them.
The settings are:
GOTRACEBACK=0 no traceback on panic, just exit
GOTRACEBACK=1 default - traceback on panic, then exit
GOTRACEBACK=2 traceback including runtime frames on panic, then exit
GOTRACEBACK=crash traceback including runtime frames on panic, then crash
Fixes #3257.
R=golang-dev, devon.odell, r, daniel.morsing, ality
CC=golang-dev
https://golang.org/cl/7666044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5146a93e72e870b06150c5419e1b83056ecc697b
元コミット内容
Goランタイムにおいて、GOTRACEBACK=crash
という設定を受け入れるように変更しました。これは「パニック後にクラッシュする」ことを意味します。
この変更は、ユーザーがコアダンプを必要とする場合に、それを生成する手段を提供します。GOTRACEBACK
の設定は以下の通りです。
GOTRACEBACK=0
: パニック時にトレースバックを出力せず、すぐに終了します。GOTRACEBACK=1
: デフォルト設定。パニック時にトレースバックを出力し、その後終了します。GOTRACEBACK=2
: パニック時にランタイムフレームを含むトレースバックを出力し、その後終了します。GOTRACEBACK=crash
: パニック時にランタイムフレームを含むトレースバックを出力し、その後クラッシュします。
この変更は、Issue #3257 を修正するものです。
変更の背景
Goプログラムがパニック(予期せぬエラー)を起こして終了する際、通常はスタックトレースが出力されます。しかし、このスタックトレースだけでは、複雑な問題やメモリ破損などの根本原因を特定するのが難しい場合があります。特に、本番環境で発生する再現性の低いバグや、デッドロック、メモリリークといった問題のデバッグには、プログラムがクラッシュした時点のメモリ状態を完全に記録した「コアダンプ」が不可欠です。
従来のGOTRACEBACK
設定では、トレースバックの冗長性を制御できましたが、プログラムを意図的にクラッシュさせてコアダンプを生成する直接的な手段がありませんでした。開発者は、Goプログラムがパニックした際に、より詳細なデバッグ情報を得るためにコアダンプを生成したいというニーズを抱えていました。
このコミットは、Issue #3257 で議論されたこのニーズに応えるもので、GOTRACEBACK=crash
という新しいオプションを導入することで、パニック発生時にOSレベルでのクラッシュ(通常はSIGABRTシグナルを発生させることによる)をトリガーし、コアダンプの生成を可能にすることを目的としています。これにより、Goプログラムのデバッグ能力が大幅に向上し、特に本番環境での問題解決に貢献します。
前提知識の解説
1. Go言語のパニックとリカバリ (Panic and Recover)
Go言語には、プログラムの異常終了を扱うためのpanic
とrecover
という組み込み関数があります。
panic
: 実行時エラーやプログラマが意図的に呼び出すことで、現在のゴルーチン(軽量スレッド)の通常の実行フローを中断させます。パニックが発生すると、そのゴルーチンはスタックを巻き戻し(unwind)、遅延関数(defer
で登録された関数)が実行されます。もし、recover
によってパニックが捕捉されなければ、プログラム全体が終了します。recover
:defer
関数内で呼び出されることで、パニックを捕捉し、そのゴルーチンの実行を再開させることができます。これにより、プログラムの異常終了を防ぎ、エラーハンドリングを行うことが可能です。
このコミットは、recover
されずにプログラム全体が終了するパニックに焦点を当てています。
2. スタックトレース (Stack Trace)
プログラムがパニックやエラーで終了する際に、その時点での関数呼び出しの履歴(コールスタック)を表示したものです。これにより、どの関数がどの関数を呼び出し、最終的にどこでエラーが発生したのかを追跡できます。GoのGOTRACEBACK
環境変数は、このスタックトレースの表示レベルを制御します。
3. コアダンプ (Core Dump)
プログラムがクラッシュした時点のメモリイメージをファイルに保存したものです。このファイルには、プログラムの実行中に使用されていたすべてのメモリ内容(変数、スタック、ヒープなど)が含まれます。コアダンプは、デバッガ(例: GDB、LLDB)で開くことができ、クラッシュ時のプログラムの状態を詳細に分析するために使用されます。メモリ破損、ポインタの不正アクセス、デッドロックなど、スタックトレースだけでは原因特定が難しい複雑なバグの解析に不可欠です。
4. シグナル (Signals)
Unix系OSにおけるプロセス間通信(IPC)の一種で、ソフトウェア割り込みのようなものです。OSがプロセスに対して特定のイベント(例: 割り込み、エラー、終了要求)を通知するために使用します。
- SIGABRT (Abort Signal): プロセス自身が異常終了を要求する際に送信されるシグナルです。通常、
abort()
関数を呼び出すことで発生し、デフォルトではコアダンプを生成してプロセスを終了させます。 - SIGPIPE (Broken Pipe Signal): パイプやソケットへの書き込み中に、読み込み側がクローズされた場合に発生するシグナルです。デフォルトではプロセスを終了させます。このコミットでは、既存の
raisesigpipe
関数がより汎用的なraise
関数に置き換えられ、SIGABRTを送信するために利用されます。
5. 環境変数 GOTRACEBACK
Goプログラムの実行時に、パニック発生時のトレースバックの挙動を制御する環境変数です。
GOTRACEBACK=0
: トレースバックを完全に抑制します。GOTRACEBACK=1
(デフォルト): ランタイム内部のフレームを除外したトレースバックを表示します。GOTRACEBACK=2
: ランタイム内部のフレームを含む完全なトレースバックを表示します。GOTRACEBACK=crash
(このコミットで追加): ランタイム内部のフレームを含む完全なトレースバックを表示した後、OS固有の方法でプログラムをクラッシュさせ、コアダンプを生成します。
技術的詳細
このコミットの主要な技術的変更点は、GOTRACEBACK
環境変数にcrash
オプションを追加し、Goランタイムがパニック時にOSレベルでのクラッシュをトリガーするメカニズムを導入したことです。
-
GOTRACEBACK
値の解析の拡張:src/pkg/runtime/runtime.c
内のruntime·gotraceback
関数が変更されました。- この関数は、以前は
GOTRACEBACK
の値(0, 1, 2)を整数として解析していましたが、新たに"crash"
という文字列も認識するようになりました。 runtime·gotraceback
関数は、bool *crash
という新しい引数を受け取るようになりました。GOTRACEBACK="crash"
が設定されている場合、このcrash
ポインタが指す値がtrue
に設定されます。これにより、呼び出し元はパニック後にクラッシュ処理を行うべきかどうかを判断できます。
-
runtime·crash
関数の導入:runtime·crash
という新しい関数が導入されました。この関数は、OS固有の方法でプログラムをクラッシュさせる責任を負います。- Unix系システム(Linux, FreeBSD, NetBSD, OpenBSD, Darwin)では、
src/pkg/runtime/signal_unix.c
にruntime·crash
が実装されています。この実装では、まずSIGABRT
シグナルのハンドラをデフォルトに戻し(runtime·setsig(SIGABRT, SIG_DFL, false)
)、その後SIGABRT
シグナルを自身に送信します(runtime·raise(SIGABRT)
)。SIGABRT
のデフォルトの挙動はコアダンプを生成して終了することです。 - macOS (Darwin) の64-bitシステムでは、コアダンプが非常に大きくなる(128GB以上)可能性があるため、
runtime·crash
関数は意図的に何もしないように実装されています。これは、ユーザーが誤って巨大なコアダンプを生成し、システムリソースを消費するのを防ぐための配慮です。 - Windowsシステムでは、
src/pkg/runtime/os_windows.c
にruntime·crash
のスタブが追加されています。コメントには「Goがシグナルをインターセプトしない場合と同様に、Windowsプログラムをアボート/クラッシュさせるために必要なことを行うべき」と記載されており、この時点ではまだ具体的な実装は行われていませんが、将来的な拡張の余地が残されています。
-
シグナルハンドラとパニック処理の変更:
src/pkg/runtime/panic.c
内のruntime·dopanic
関数や、各OSのシグナルハンドラ(例:src/pkg/runtime/os_plan9_386.c
、src/pkg/runtime/signal_386.c
など)が変更されました。- これらの関数は、
runtime·gotraceback
を呼び出す際に、crash
フラグを受け取るように修正されました。 - トレースバックの出力後、もし
crash
フラグがtrue
であれば、runtime·crash()
関数が呼び出され、プログラムが意図的にクラッシュさせられます。
-
runtime·raisesigpipe
からruntime·raise
への汎用化:- 以前は
SIGPIPE
シグナルを発生させるためのruntime·raisesigpipe
という関数がありましたが、これがより汎用的なruntime·raise(int32 sig)
関数に置き換えられました。 - この
runtime·raise
関数は、引数として任意のシグナル番号を受け取り、そのシグナルを現在のプロセス(またはスレッド)に送信します。これにより、runtime·crash
関数がSIGABRT
を送信するためにこの汎用関数を利用できるようになりました。 - 各OS/アーキテクチャ固有のアセンブリファイル(例:
src/pkg/runtime/sys_darwin_386.s
、src/pkg/runtime/sys_linux_amd64.s
など)で、runtime·raisesigpipe
の実装がruntime·raise
の実装に置き換えられ、引数としてシグナル番号を受け取るように変更されています。
- 以前は
これらの変更により、Goプログラムはパニック時に開発者が望む形でコアダンプを生成できるようになり、デバッグの選択肢が広がりました。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと、その変更の概要は以下の通りです。
-
src/pkg/runtime/extern.go
:GOTRACEBACK
環境変数の説明が更新され、crash
オプションが追加されました。
-
src/pkg/runtime/runtime.c
:runtime·gotraceback
関数のシグネチャがint32 runtime·gotraceback(bool *crash)
に変更され、crash
ポインタを介してGOTRACEBACK="crash"
が設定されたかどうかを呼び出し元に通知するようになりました。GOTRACEBACK="crash"
の場合に*crash = true
を設定し、トレースバックレベルとして2
(ランタイムフレームを含む)を返すロジックが追加されました。
-
src/pkg/runtime/runtime.h
:runtime·gotraceback
関数のプロトタイプが更新され、bool *crash
引数が追加されました。runtime·crash
関数のプロトタイプが追加されました。
-
src/pkg/runtime/panic.c
:runtime·dopanic
関数内でruntime·gotraceback
を呼び出す際に、crash
フラグを受け取るように変更されました。- トレースバック出力後、
crash
フラグがtrue
の場合にruntime·crash()
を呼び出すロジックが追加されました。
-
src/pkg/runtime/proc.c
:runtime·tracebackothers
関数内でruntime·gotraceback
を呼び出す際に、nil
を渡すように変更されました(このコンテキストではクラッシュは不要なため)。
-
src/pkg/runtime/signal_unix.c
:runtime·crash
関数が実装されました。この関数は、SIGABRT
シグナルのハンドラをデフォルトに戻し、runtime·raise(SIGABRT)
を呼び出してプロセスをクラッシュさせます。- macOS (Darwin) の64-bitシステムでは、巨大なコアダンプを避けるために
runtime·crash
が何もしないように実装されています。 os·sigpipe
関数内でruntime·raisesigpipe()
の代わりにruntime·raise(SIGPIPE)
が呼び出されるように変更されました。
-
src/pkg/runtime/signal_unix.h
:runtime·raisesigpipe
のプロトタイプが削除され、runtime·raise(int32)
のプロトタイプが追加されました。
-
src/pkg/runtime/os_plan9.c
,src/pkg/runtime/os_plan9_386.c
,src/pkg/runtime/os_plan9_amd64.c
:- Plan 9 向けの
runtime·crash
関数が追加されました。 - シグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- Plan 9 向けの
-
src/pkg/runtime/os_windows.c
,src/pkg/runtime/os_windows_386.c
,src/pkg/runtime/os_windows_amd64.c
:- Windows 向けの
runtime·crash
関数のスタブが追加されました。 - シグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- Windows 向けの
-
src/pkg/runtime/signal_386.c
,src/pkg/runtime/signal_amd64.c
,src/pkg/runtime/signal_arm.c
:- 各アーキテクチャのシグナルハンドラ内で
runtime·gotraceback
の呼び出しとruntime·crash
の呼び出しが追加されました。
- 各アーキテクチャのシグナルハンドラ内で
-
src/pkg/runtime/symtab.c
:runtime·showframe
関数内でruntime·gotraceback
を呼び出す際に、nil
を渡すように変更されました。
-
src/pkg/runtime/sys_darwin_386.s
,src/pkg/runtime/sys_darwin_amd64.s
,src/pkg/runtime/sys_freebsd_*.s
,src/pkg/runtime/sys_linux_*.s
,src/pkg/runtime/sys_netbsd_*.s
,src/pkg/runtime/sys_openbsd_*.s
:- 各OS/アーキテクチャ固有のアセンブリファイルで、
runtime·raisesigpipe
の実装がruntime·raise
の実装に置き換えられ、引数としてシグナル番号を受け取るように変更されました。
- 各OS/アーキテクチャ固有のアセンブリファイルで、
コアとなるコードの解説
runtime·gotraceback
関数の変更 (src/pkg/runtime/runtime.c
)
// The GOTRACEBACK environment variable controls the
// behavior of a Go program that is crashing and exiting.
// GOTRACEBACK=0 suppress all tracebacks
// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
// GOTRACEBACK=2 show tracebacks including runtime frames
// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
int32
runtime·gotraceback(bool *crash)
{
byte *p;
if(crash != nil)
*crash = false;
p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
if(runtime·strcmp(p, (byte*)"crash") == 0) {
if(crash != nil)
*crash = true;
return 2; // extra information
}
return runtime·atoi(p);
}
この関数は、GOTRACEBACK
環境変数の値を読み取り、パニック時のトレースバックの挙動を決定します。
変更点として、bool *crash
という新しい引数が追加されました。これは、呼び出し元がパニック後にクラッシュ処理を行うべきかどうかを知るためのフラグです。
GOTRACEBACK
が設定されていないか空の場合、デフォルトの1
(トレースバック表示)を返します。GOTRACEBACK
が"crash"
と設定されている場合、crash
ポインタがnil
でなければ*crash
をtrue
に設定し、トレースバックレベルとして2
(ランタイムフレームを含む)を返します。- それ以外の場合、環境変数の値を整数として解析して返します。
runtime·crash
関数の実装 (src/pkg/runtime/signal_unix.c
- Unix系OSの場合)
void
runtime·crash(void)
{
#ifdef GOOS_darwin
// OS X core dumps are linear dumps of the mapped memory,
// from the first virtual byte to the last, with zeros in the gaps.
// Because of the way we arrange the address space on 64-bit systems,
// this means the OS X core file will be >128 GB and even on a zippy
// workstation can take OS X well over an hour to write (uninterruptible).
// Save users from making that mistake.
if(sizeof(void*) == 8)
return;
#endif
runtime·setsig(SIGABRT, SIG_DFL, false);
runtime·raise(SIGABRT);
}
このruntime·crash
関数は、GoプログラムをOSレベルでクラッシュさせるための主要なロジックを含んでいます。
- macOS (Darwin) 64-bitの特殊処理:
GOOS_darwin
が定義されており、かつポインタサイズが8バイト(64-bitシステム)の場合、関数はすぐにリターンします。これは、macOSのコアダンプの特性(マッピングされたメモリの線形ダンプであり、64-bitシステムでは非常に巨大なファイルになる)を考慮し、ユーザーが意図せず巨大なコアダンプを生成してしまうのを防ぐためのものです。 - SIGABRTの送信: それ以外のUnix系OSでは、まず
SIGABRT
シグナルのハンドラをデフォルト(SIG_DFL
)に戻します。これにより、Goランタイムが設定したカスタムシグナルハンドラが解除され、OSがSIGABRT
を処理する際のデフォルトの挙動(通常はコアダンプの生成とプロセス終了)が有効になります。 runtime·raise(SIGABRT)
: その後、runtime·raise
関数を呼び出して自身にSIGABRT
シグナルを送信します。これにより、プログラムはクラッシュし、コアダンプが生成されます。
runtime·raise
関数の導入と各OS/アーキテクチャのアセンブリ変更
以前はruntime·raisesigpipe
という特定のシグナル(SIGPIPE)を発生させる関数がありましたが、このコミットでruntime·raise(int32 sig)
という汎用的な関数に置き換えられました。この関数は、引数として渡されたシグナル番号を現在のプロセス/スレッドに送信します。
例えば、src/pkg/runtime/sys_darwin_amd64.s
では、以下のように変更されています。
// Old: TEXT runtime·raisesigpipe(SB),7,$24
// Old: ... (SIGPIPEを送信するロジック)
// New:
TEXT runtime·raise(SB),7,$24
MOVL $(0x2000000+20), AX // getpid
SYSCALL
MOVQ AX, DI // arg 1 - pid
MOVL sig+0(FP), SI // arg 2 - signal (引数から取得)
MOVL $(0x2000000+37), AX // kill
SYSCALL
RET
このアセンブリコードは、macOS (amd64) においてkill
システムコールを使用して指定されたシグナルを送信する処理を示しています。sig+0(FP)
は、関数に渡されたsig
引数の値(シグナル番号)をレジスタにロードしています。これにより、runtime·crash
関数がruntime·raise(SIGABRT)
を呼び出すことで、OSがコアダンプを生成するような形でプログラムを終了させることが可能になります。
これらの変更により、GoランタイムはGOTRACEBACK=crash
設定に応じて、OSの機能を利用して意図的にコアダンプを生成するメカニズムを確立しました。
関連リンク
- Go Issue #3257: runtime: GOTRACEBACK=crash to mean 'crash after panic'
- Go CL 7666044: runtime: accept GOTRACEBACK=crash to mean 'crash after panic'
- Go Documentation:
runtime
package (Environment Variables section)- https://pkg.go.dev/runtime (現在のドキュメントでは
GOTRACEBACK
の詳細が記載されています)
- https://pkg.go.dev/runtime (現在のドキュメントでは
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Unix/Linuxシグナルに関する一般的な情報源 (例:
man 7 signal
) - コアダンプに関する一般的な情報源
- GDB (GNU Debugger) のドキュメント (コアダンプの分析方法について)
- https://github.com/golang/go/issues/3257
- https://golang.org/cl/7666044
- https://pkg.go.dev/runtime