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

[インデックス 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の値を取得しています。

  1. (byte*)info: siginfo_t*型のinfoポインタをbyte*型(バイトポインタ)にキャストします。これにより、ポインタ演算をバイト単位で行うことが可能になります。
  2. + 12: キャストされたinfoポインタに12バイトを加算します。これは、OpenBSD/386におけるsi_addrフィールドの正確なオフセットが12バイトであることを示しています。
  3. (uintptr*): 結果のポインタをuintptr*型にキャストします。これは、そのメモリアドレスにuintptr型の値が格納されていると解釈するためです。
  4. *: キャストされたポインタをデリファレンス(間接参照)します。これにより、オフセット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の値を取得しています。

  1. (byte*)info: siginfo_t*型のinfoポインタをbyte*型(バイトポインタ)にキャストします。これにより、ポインタ演算をバイト単位で行うことが可能になります。
  2. + 12: キャストされたinfoポインタに12バイトを加算します。これは、OpenBSD/386におけるsi_addrフィールドの正確なオフセットが12バイトであることを示しています。
  3. (uintptr*): 結果のポインタをuintptr*型にキャストします。これは、そのメモリアドレスにuintptr型の値が格納されていると解釈するためです。
  4. *: キャストされたポインタをデリファレンス(間接参照)します。これにより、オフセット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言語のランタイムに関する一般的な知識