[インデックス 18705] ファイルの概要
コミット
このコミットは、GoランタイムにおけるFreeBSD環境でのSIGSYS
シグナルの扱いを変更するものです。具体的には、SIGSYS
シグナルが「通知可能 (notifiable)」になるように更新されています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d9fc789df2a97137a56d305c61513cd33b1c910a
元コミット内容
commit d9fc789df2a97137a56d305c61513cd33b1c910a
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Mon Mar 3 07:08:44 2014 +0900
runtime: make SIGSYS notifiable on FreeBSD
Update #7186
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/70490043
変更の背景
この変更は、Go Issue #7186 に関連しています。SIGSYS
シグナルは、プログラムが不正なシステムコールを試みた際にカーネルによって送信されるシグナルです。FreeBSD環境において、GoランタイムがこのSIGSYS
シグナルを適切に処理できるよう、そのシグナルハンドリングの挙動を調整する必要がありました。
Goランタイムは、プログラムの安定性とデバッグ可能性を確保するために、様々なシグナルに対して独自のハンドリングロジックを持っています。特に、予期せぬシステムコールエラーが発生した場合に、プログラムが即座に終了するのではなく、より制御された方法でエラーを報告したり、デバッグ情報を提供したりすることが望ましい場合があります。このコミットは、FreeBSD上でのSIGSYS
の扱いを、他のプラットフォームや他のシグナルと同様に、ランタイムがその発生を「通知」できるようにすることで、この制御を改善することを目的としています。
前提知識の解説
シグナル (Signals)
シグナルは、Unix系オペレーティングシステムにおいて、プロセスに対して非同期的にイベントを通知するソフトウェア割り込みの一種です。シグナルは、様々な状況で生成されます。例えば、ユーザーがCtrl+Cを押した場合(SIGINT
)、不正なメモリアクセスが発生した場合(SIGSEGV
)、子プロセスが終了した場合(SIGCHLD
)などです。
各シグナルには、デフォルトの動作が定義されています。これには、プロセスの終了、コアダンプの生成、シグナルの無視、シグナルハンドラ関数の実行などがあります。プログラムは、signal()
やsigaction()
といったシステムコールを使用して、特定のシグナルに対するデフォルトの動作を変更し、カスタムのシグナルハンドラを設定することができます。
SIGSYS
シグナル
SIGSYS
(Signal System Call) は、プロセスが不正なシステムコールを試みた際にカーネルによって送信されるシグナルです。これは通常、存在しないシステムコール番号を呼び出したり、システムコールに無効な引数を渡したりした場合に発生します。セキュリティメカニズム(例: seccomp
)によって、特定のシステムコールの実行が禁止されている場合にも発生することがあります。
デフォルトでは、SIGSYS
を受け取ったプロセスは終了します。しかし、デバッグや特定のセキュリティポリシーの実装のために、このシグナルを捕捉してカスタムの処理を行うことが望ましい場合があります。
Goランタイムとシグナルハンドリング
Goプログラムは、Goランタイムによって管理されます。Goランタイムは、ガベージコレクション、スケジューリング、ネットワークI/O、そしてシグナルハンドリングなど、多くの低レベルなタスクを処理します。Goランタイムは、オペレーティングシステムから受け取ったシグナルを捕捉し、Goのゴルーチンモデルと統合された方法で処理します。これにより、Goプログラムは、OSレベルのシグナルを直接扱うことなく、より高レベルなos/signal
パッケージを通じてシグナルイベントを処理できます。
Goランタイム内部では、各シグナルに対して、そのシグナルが「終了 (Terminate)」、「無視 (Ignore)」、「コアダンプ (Core Dump)」、「停止 (Stop)」、「通知 (Notify)」のいずれのカテゴリに属するかを定義するテーブルを持っています。
- T (Terminate): シグナルを受け取るとプロセスが終了する。
- P (Core Dump): シグナルを受け取るとプロセスが終了し、コアダンプを生成する。
- I (Ignore): シグナルを無視する。
- S (Stop): シグナルを受け取るとプロセスが停止する。
- N (Notify): シグナルを受け取ると、Goランタイムがそのシグナルを捕捉し、
os/signal
パッケージを通じてユーザーゴルーチンに通知する。
このコミットの文脈では、SIGSYS
がT
(終了)からN
(通知)に変更されることが重要です。
技術的詳細
このコミットの核心は、FreeBSDにおけるSIGSYS
シグナルのGoランタイム内での分類を変更することです。変更前は、SIGSYS
はT
(Terminate)として扱われていました。これは、GoプログラムがFreeBSD上で不正なシステムコールを試みた場合、ランタイムがそのシグナルを捕捉しても、最終的にはプロセスを終了させるという挙動を意味します。
変更後は、SIGSYS
がN
(Notify)として扱われるようになります。これにより、GoランタイムはSIGSYS
シグナルを捕捉し、そのシグナルイベントをos/signal
パッケージを通じてGoプログラム内のユーザーゴルーチンに通知できるようになります。つまり、Go開発者はos/signal
パッケージを使用してSIGSYS
シグナルを捕捉し、プログラム内でカスタムのハンドリングロジックを実装できるようになります。これにより、不正なシステムコールが発生した場合でも、プログラムが即座にクラッシュするのではなく、より柔軟なエラー処理やデバッグが可能になります。
この変更は、特にサンドボックス環境や、特定のシステムコールが意図的にブロックされるような環境でGoプログラムを実行する際に重要になります。例えば、seccomp
のようなメカニズムを使用してシステムコールを制限している場合、許可されていないシステムコールを呼び出すとSIGSYS
が発生します。この変更により、Goプログラムはそのようなイベントを捕捉し、適切に対応できるようになります。
コアとなるコードの変更箇所
変更は、src/pkg/runtime/signals_freebsd.h
ファイル内のSigTab
配列の定義にあります。
--- a/src/pkg/runtime/signals_freebsd.h
+++ b/src/pkg/runtime/signals_freebsd.h
@@ -21,7 +21,7 @@ SigTab runtime·sigtab[] = {
/* 9 */ 0, "SIGKILL: kill",
/* 10 */ P, "SIGBUS: bus error",
/* 11 */ P, "SIGSEGV: segmentation violation",
- /* 12 */ T, "SIGSYS: bad system call",
+ /* 12 */ N, "SIGSYS: bad system call",
/* 13 */ N, "SIGPIPE: write to broken pipe",
/* 14 */ N, "SIGALRM: alarm clock",
/* 15 */ N+K, "SIGTERM: termination",
コアとなるコードの解説
src/pkg/runtime/signals_freebsd.h
ファイルは、FreeBSDプラットフォームにおけるGoランタイムのシグナルハンドリング設定を定義しています。
SigTab runtime·sigtab[]
は、Goランタイムが認識するシグナルとそのデフォルトの動作を定義するテーブルです。各エントリは、シグナル番号(コメントで示されている)、シグナルの種類を示すフラグ(T
, P
, N
など)、およびシグナルの説明文字列で構成されています。
このコミットでは、SIGSYS
に対応する行が以下のように変更されています。
- 変更前:
/* 12 */ T, "SIGSYS: bad system call",
- これは、シグナル番号12(
SIGSYS
)がT
(Terminate)として扱われることを意味していました。つまり、SIGSYS
を受け取ると、Goプログラムはデフォルトで終了します。
- これは、シグナル番号12(
- 変更後:
/* 12 */ N, "SIGSYS: bad system call",
- これは、シグナル番号12(
SIGSYS
)がN
(Notify)として扱われることを意味します。これにより、GoランタイムはSIGSYS
を捕捉し、os/signal
パッケージを通じてGoプログラムに通知できるようになります。
- これは、シグナル番号12(
この小さな変更により、FreeBSD上でのGoプログラムのSIGSYS
シグナルに対する挙動が根本的に変わり、より柔軟なシグナルハンドリングが可能になります。
関連リンク
- Go Issue #7186: https://github.com/golang/go/issues/7186 (このコミットが解決するIssue)
- Go Code Review: https://golang.org/cl/70490043 (このコミットのコードレビューページ)
参考にした情報源リンク
- Go言語の公式ドキュメント (シグナルハンドリングに関する一般的な情報)
- Unix/Linuxシグナルに関する一般的なドキュメント (SIGSYSの定義など)
- FreeBSDのシグナルに関するドキュメント (FreeBSD固有のシグナル挙動)
- Goランタイムのソースコード (signals_freebsd.hのコンテキスト理解のため)
- Go Issue #7186の議論 (変更の背景と目的の理解のため)