[インデックス 16178] ファイルの概要
このコミットは、Go言語のランタイムがOpenBSD/386アーキテクチャ上で正しくビルドされるようにするための修正です。具体的には、シグナルハンドリングに関連するマクロ定義において、si_addr
フィールドへのアクセス方法を修正し、OpenBSD/386環境でのコンパイルエラーや不正な動作を防ぐことを目的としています。
コミット
- コミットハッシュ:
804ef381db6bef62a44ccbbb6a417728ad3bf01d
- 作者: Joel Sing jsing@google.com
- コミット日時: Mon Apr 15 10:20:24 2013 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/804ef381db6bef62a44ccbbb6a417728ad3bf01d
元コミット内容
runtime: fix build on openbsd/386
R=golang-dev, minux.ma, r
CC=golang-dev
https://golang.org/cl/8569043
変更の背景
Go言語のランタイムは、様々なオペレーティングシステム(OS)とアーキテクチャの組み合わせ(OS/Arch)をサポートしています。それぞれのOS/Archの組み合わせには、シグナルハンドリングやシステムコールなどの低レベルな処理において、OS固有の構造体やAPIの違いを吸収するためのプラットフォーム固有のコードが含まれています。
このコミットが行われた当時、GoのランタイムがOpenBSDオペレーティングシステムの386(Intel i386)アーキテクチャ上でビルドされる際に問題が発生していました。具体的には、シグナル情報構造体(siginfo_t
)のsi_addr
フィールドへのアクセス方法が、OpenBSD/386環境の期待するレイアウトと一致していなかったため、コンパイルエラーやランタイムエラーを引き起こす可能性がありました。
si_addr
は、シグナルが発生したアドレス(例えば、セグメンテーション違反が発生したメモリアドレス)を示すために使用される重要なフィールドです。このフィールドへのアクセスが正しくない場合、デバッグ情報の欠如や、シグナルハンドラが誤ったアドレスを処理しようとするなどの問題が発生し、プログラムの安定性やデバッグ可能性に影響を与えます。
この修正は、OpenBSD/386環境におけるGoランタイムの安定性と互換性を確保し、このプラットフォームでのGoプログラムのビルドと実行を可能にするために必要でした。
前提知識の解説
OpenBSD
OpenBSDは、セキュリティを重視して開発されているUNIX系オペレーティングシステムです。堅牢なセキュリティ機能、コードの品質、そして厳格な監査プロセスで知られています。様々なハードウェアアーキテクチャをサポートしており、その中にはIntel i386(32ビット)アーキテクチャも含まれます。
386アーキテクチャ (i386)
Intel 80386プロセッサに由来する32ビットの命令セットアーキテクチャです。現代のほとんどのデスクトップやサーバーは64ビットアーキテクチャ(x86-64)ですが、i386は古いシステムや組み込みシステムで依然として使用されることがあります。Go言語は、初期からこの32ビットアーキテクチャもサポートしていました。
Goランタイム (Go Runtime)
Go言語のプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。Goランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、そしてシグナルハンドリングなど、Goプログラムの実行に必要な低レベルな機能を提供します。OSとのインタフェース部分は、各OS/Archの組み合わせに特化したコードで実装されています。
シグナルハンドリング (Signal Handling)
シグナルは、UNIX系OSにおいてプロセスに非同期イベントを通知するメカニズムです。例えば、Ctrl+Cによる割り込み(SIGINT)、不正なメモリアクセス(SIGSEGV)、子プロセスの終了(SIGCHLD)などがあります。プログラムはシグナルハンドラを登録することで、これらのイベントに応答できます。
siginfo_t
構造体
シグナルハンドラに渡される情報を含む構造体です。siginfo_t
は、シグナルの種類、シグナルを送信したプロセスID、そしてシグナル固有の詳細情報(例えば、SIGSEGV
の場合は不正アクセスが発生したアドレス)など、様々な情報を含みます。この構造体の具体的なレイアウトは、OSやアーキテクチャによって異なる場合があります。
si_code
: シグナルの原因を示すコードです。例えば、SIGSEGV
の場合、SEGV_MAPERR
(アドレスがマップされていない)やSEGV_ACCERR
(アクセス権がない)などがあります。si_addr
: シグナルに関連するアドレスです。例えば、SIGSEGV
(セグメンテーション違反)やSIGBUS
(バスエラー)の場合、エラーが発生したメモリアドレスを示します。
uintptr
Go言語におけるuintptr
型は、ポインタを保持するのに十分な大きさの符号なし整数型です。これは、ポインタと整数の間で変換を行う際に使用され、特に低レベルなシステムプログラミングやOSとのインタフェースで役立ちます。
byte*
C言語の文脈では、byte*
はunsigned char*
と同義で、メモリ上のバイト列を指すポインタとして扱われます。これは、任意のデータ型をバイト単位で操作する際に便利です。
技術的詳細
このコミットの核心は、src/pkg/runtime/signal_openbsd_386.h
ファイル内のSIG_CODE1
マクロの定義変更です。
元の定義:
#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
修正後の定義:
#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
この変更は、siginfo_t
構造体のsi_addr
フィールドが、OpenBSD/386環境において、siginfo_t
構造体の先頭から12バイトのオフセットに位置しているという事実に基づいています。
一般的なUNIX系OSでは、siginfo_t
構造体は標準的なフィールド(si_signo
, si_errno
, si_code
など)を持ち、その後にシグナル固有の共用体(union)が続くことがよくあります。si_addr
はこの共用体の一部として定義されることが多いですが、その正確なオフセットはOSの実装やコンパイラのパディングによって異なります。
元のコードでは、info
ポインタが指すsiginfo_t
構造体から直接si_addr
フィールドにアクセスしようとしていました。これは、他のOS/Archの組み合わせでは正しく機能するかもしれませんが、OpenBSD/386ではsi_addr
が期待されるオフセットにないか、あるいは構造体の定義が異なるために、コンパイル時に不正なメモリアクセスとして扱われたり、実行時に誤った値を読み取ったりする可能性がありました。
修正後のコードでは、以下の手順でsi_addr
の値を取得しています。
(byte*)info
:siginfo_t*
型のinfo
ポインタをbyte*
型(バイトポインタ)にキャストします。これにより、ポインタ演算をバイト単位で行うことが可能になります。+ 12
: キャストされたinfo
ポインタに12バイトを加算します。これは、OpenBSD/386におけるsi_addr
フィールドの正確なオフセットが12バイトであることを示しています。(uintptr*)
: 結果のポインタをuintptr*
型にキャストします。これは、そのメモリアドレスにuintptr
型の値が格納されていると解釈するためです。*
: キャストされたポインタをデリファレンス(間接参照)します。これにより、オフセット12バイトの位置にあるuintptr
型の値(つまり、si_addr
の値)が取得されます。
この修正により、GoランタイムはOpenBSD/386環境でsi_addr
フィールドから正しいメモリアドレス情報を取得できるようになり、シグナルハンドリングが期待通りに機能するようになりました。これは、OS固有の構造体レイアウトの差異を吸収するための典型的な低レベルプログラミングのテクニックです。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/signal_openbsd_386.h
+++ b/src/pkg/runtime/signal_openbsd_386.h
@@ -20,4 +20,4 @@
#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
コアとなるコードの解説
変更された行は、src/pkg/runtime/signal_openbsd_386.h
ファイル内のSIG_CODE1
マクロの定義です。
-
変更前:
#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
- この行は、
info
ポインタが指すsiginfo_t
構造体から直接si_addr
フィールドにアクセスし、その値をuintptr
型にキャストしていました。これは、si_addr
が構造体内で直接アクセス可能なメンバーとして定義されており、かつそのオフセットがコンパイラによって適切に解決されることを前提としています。しかし、OpenBSD/386の特定のコンパイラやABI(Application Binary Interface)では、この直接アクセスが正しく機能しなかったと考えられます。
- この行は、
-
変更後:
#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
- この行は、
info
ポインタをまずbyte*
(バイトポインタ)にキャストし、そこから12バイトのオフセットを加算しています。これは、siginfo_t
構造体の先頭から12バイトの位置にsi_addr
フィールドが配置されているという、OpenBSD/386環境における具体的なメモリレイアウトをハードコードしたものです。 - オフセットされたポインタは、次に
uintptr*
にキャストされ、最後に*
演算子でデリファレンス(間接参照)されます。これにより、指定されたオフセットにあるメモリの内容がuintptr
型の値として読み取られます。 - この修正は、OSやアーキテクチャ固有の構造体パディングやフィールド配置の差異を明示的に扱うことで、GoランタイムがOpenBSD/386上でシグナル情報を正しく解釈できるようにします。
- この行は、
この修正は、Goランタイムが異なるプラットフォームの低レベルな詳細にどのように適応しているかを示す良い例です。
関連リンク
- Go Change-Id:
I804ef381db6bef62a44ccbbb6a417728ad3bf01d
(Goの内部変更リストID) - Go CL (Change List) 8569043: https://golang.org/cl/8569043 (Goのコードレビューシステムへのリンク)
参考にした情報源リンク
- Go言語のソースコード (
src/pkg/runtime/signal_openbsd_386.h
) - UNIX系OSのシグナルハンドリングに関する一般的なドキュメント (
siginfo_t
構造体など) - OpenBSDのシステムプログラミングに関するドキュメント (特に
siginfo_t
のレイアウトに関する情報) - Go言語のIssueトラッカーやメーリングリストでの関連議論 (もしあれば、CLリンクから辿れる可能性)
- Go言語のランタイムに関する一般的な知識# [インデックス 16178] ファイルの概要
このコミットは、Go言語のランタイムがOpenBSD/386アーキテクチャ上で正しくビルドされるようにするための修正です。具体的には、シグナルハンドリングに関連するマクロ定義において、si_addr
フィールドへのアクセス方法を修正し、OpenBSD/386環境でのコンパイルエラーや不正な動作を防ぐことを目的としています。
コミット
- コミットハッシュ:
804ef381db6bef62a44ccbbb6a417728ad3bf01d
- 作者: Joel Sing jsing@google.com
- コミット日時: Mon Apr 15 10:20:24 2013 -0700
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/804ef381db6bef62a44ccbbb6a417728ad3bf01d
元コミット内容
runtime: fix build on openbsd/386
R=golang-dev, minux.ma, r
CC=golang-dev
https://golang.org/cl/8569043
変更の背景
Go言語のプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。Goランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、そしてシグナルハンドリングなど、Goプログラムの実行に必要な低レベルな機能を提供します。OSとのインタフェース部分は、各OS/Archの組み合わせに特化したコードで実装されています。
このコミットが行われた当時、GoのランタイムがOpenBSDオペレーティングシステムの386(Intel i386)アーキテクチャ上でビルドされる際に問題が発生していました。具体的には、シグナル情報構造体(siginfo_t
)のsi_addr
フィールドへのアクセス方法が、OpenBSD/386環境の期待するレイアウトと一致していなかったため、コンパイルエラーやランタイムエラーを引き起こす可能性がありました。
si_addr
は、シグナルが発生したアドレス(例えば、セグメンテーション違反が発生したメモリアドレス)を示すために使用される重要なフィールドです。このフィールドへのアクセスが正しくない場合、デバッグ情報の欠如や、シグナルハンドラが誤ったアドレスを処理しようとするなどの問題が発生し、プログラムの安定性やデバッグ可能性に影響を与えます。
この修正は、OpenBSD/386環境におけるGoランタイムの安定性と互換性を確保し、このプラットフォームでのGoプログラムのビルドと実行を可能にするために必要でした。
前提知識の解説
OpenBSD
OpenBSDは、セキュリティを重視して開発されているUNIX系オペレーティングシステムです。堅牢なセキュリティ機能、コードの品質、そして厳格な監査プロセスで知られています。様々なハードウェアアーキテクチャをサポートしており、その中にはIntel i386(32ビット)アーキテクチャも含まれます。
386アーキテクチャ (i386)
Intel 80386プロセッサに由来する32ビットの命令セットアーキテクチャです。現代のほとんどのデスクトップやサーバーは64ビットアーキテクチャ(x86-64)ですが、i386は古いシステムや組み込みシステムで依然として使用されることがあります。Go言語は、初期からこの32ビットアーキテクチャもサポートしていました。
Goランタイム (Go Runtime)
Go言語のプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。Goランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、そしてシグナルハンドリングなど、Goプログラムの実行に必要な低レベルな機能を提供します。OSとのインタフェース部分は、各OS/Archの組み合わせに特化したコードで実装されています。
シグナルハンドリング (Signal Handling)
シグナルは、UNIX系OSにおいてプロセスに非同期イベントを通知するメカニズムです。例えば、Ctrl+Cによる割り込み(SIGINT)、不正なメモリアクセス(SIGSEGV)、子プロセスの終了(SIGCHLD)などがあります。プログラムはシグナルハンドラを登録することで、これらのイベントに応答できます。
siginfo_t
構造体
シグナルハンドラに渡される情報を含む構造体です。siginfo_t
は、シグナルの種類、シグナルを送信したプロセスID、そしてシグナル固有の詳細情報(例えば、SIGSEGV
の場合は不正アクセスが発生したアドレス)など、様々な情報を含みます。この構造体の具体的なレイアウトは、OSやアーキテクチャによって異なる場合があります。
si_code
: シグナルの原因を示すコードです。例えば、SIGSEGV
の場合、SEGV_MAPERR
(アドレスがマップされていない)やSEGV_ACCERR
(アクセス権がない)などがあります。si_addr
: シグナルに関連するアドレスです。例えば、SIGSEGV
(セグメンテーション違反)やSIGBUS
(バスエラー)の場合、エラーが発生したメモリアドレスを示します。
uintptr
Go言語におけるuintptr
型は、ポインタを保持するのに十分な大きさの符号なし整数型です。これは、ポインタと整数の間で変換を行う際に使用され、特に低レベルなシステムプログラミングやOSとのインタフェースで役立ちます。
byte*
C言語の文脈では、byte*
はunsigned char*
と同義で、メモリ上のバイト列を指すポインタとして扱われます。これは、任意のデータ型をバイト単位で操作する際に便利です。
技術的詳細
このコミットの核心は、src/pkg/runtime/signal_openbsd_386.h
ファイル内のSIG_CODE1
マクロの定義変更です。
元の定義:
#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
修正後の定義:
#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
この変更は、siginfo_t
構造体のsi_addr
フィールドが、OpenBSD/386環境において、siginfo_t
構造体の先頭から12バイトのオフセットに位置しているという事実に基づいています。
一般的なUNIX系OSでは、siginfo_t
構造体は標準的なフィールド(si_signo
, si_errno
, si_code
など)を持ち、その後にシグナル固有の共用体(union)が続くことがよくあります。si_addr
はこの共用体の一部として定義されることが多いですが、その正確なオフセットはOSの実装やコンパイラのパディングによって異なります。
元のコードでは、info
ポインタが指すsiginfo_t
構造体から直接si_addr
フィールドにアクセスしようとしていました。これは、他のOS/Archの組み合わせでは正しく機能するかもしれませんが、OpenBSD/386ではsi_addr
が期待されるオフセットにないか、あるいは構造体の定義が異なるために、コンパイル時に不正なメモリアクセスとして扱われたり、実行時に誤った値を読み取ったりする可能性がありました。
修正後のコードでは、以下の手順でsi_addr
の値を取得しています。
(byte*)info
:siginfo_t*
型のinfo
ポインタをbyte*
型(バイトポインタ)にキャストします。これにより、ポインタ演算をバイト単位で行うことが可能になります。+ 12
: キャストされたinfo
ポインタに12バイトを加算します。これは、OpenBSD/386におけるsi_addr
フィールドの正確なオフセットが12バイトであることを示しています。(uintptr*)
: 結果のポインタをuintptr*
型にキャストします。これは、そのメモリアドレスにuintptr
型の値が格納されていると解釈するためです。*
: キャストされたポインタをデリファレンス(間接参照)します。これにより、オフセット12バイトの位置にあるuintptr
型の値(つまり、si_addr
の値)が取得されます。
この修正により、GoランタイムはOpenBSD/386環境でsi_addr
フィールドから正しいメモリアドレス情報を取得できるようになり、シグナルハンドリングが期待通りに機能するようになりました。これは、OS固有の構造体レイアウトの差異を吸収するための典型的な低レベルプログラミングのテクニックです。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/signal_openbsd_386.h
+++ b/src/pkg/runtime/signal_openbsd_386.h
@@ -20,4 +20,4 @@
#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
コアとなるコードの解説
変更された行は、src/pkg/runtime/signal_openbsd_386.h
ファイル内のSIG_CODE1
マクロの定義です。
-
変更前:
#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
- この行は、
info
ポインタが指すsiginfo_t
構造体から直接si_addr
フィールドにアクセスし、その値をuintptr
型にキャストしていました。これは、si_addr
が構造体内で直接アクセス可能なメンバーとして定義されており、かつそのオフセットがコンパイラによって適切に解決されることを前提としています。しかし、OpenBSD/386の特定のコンパイラやABI(Application Binary Interface)では、この直接アクセスが正しく機能しなかったと考えられます。
- この行は、
-
変更後:
#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
- この行は、
info
ポインタをまずbyte*
(バイトポインタ)にキャストし、そこから12バイトのオフセットを加算しています。これは、siginfo_t
構造体の先頭から12バイトの位置にsi_addr
フィールドが配置されているという、OpenBSD/386環境における具体的なメモリレイアウトをハードコードしたものです。 - オフセットされたポインタは、次に
uintptr*
にキャストされ、最後に*
演算子でデリファレンス(間接参照)されます。これにより、指定されたオフセットにあるメモリの内容がuintptr
型の値として読み取られます。 - この修正は、OSやアーキテクチャ固有の構造体パディングやフィールド配置の差異を明示的に扱うことで、GoランタイムがOpenBSD/386上でシグナル情報を正しく解釈できるようにします。
- この行は、
この修正は、Goランタイムが異なるプラットフォームの低レベルな詳細にどのように適応しているかを示す良い例です。
関連リンク
- Go Change-Id:
I804ef381db6bef62a44ccbbb6a417728ad3bf01d
(Goの内部変更リストID) - Go CL (Change List) 8569043: https://golang.org/cl/8569043 (Goのコードレビューシステムへのリンク)
参考にした情報源リンク
- Go言語のソースコード (
src/pkg/runtime/signal_openbsd_386.h
) - UNIX系OSのシグナルハンドリングに関する一般的なドキュメント (
siginfo_t
構造体など) - OpenBSDのシステムプログラミングに関するドキュメント (特に
siginfo_t
のレイアウトに関する情報) - Go言語のIssueトラッカーやメーリングリストでの関連議論 (もしあれば、CLリンクから辿れる可能性)
- Go言語のランタイムに関する一般的な知識