[インデックス 15451] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるファイルディスクリプタ(FD)の受け渡しに関するバグ修正です。特にFreeBSDとNetBSDというUnix系OS上での挙動に焦点を当て、コントロールメッセージ(Cmsg
)のデータ部分へのポインタ計算におけるアライメントの問題を解決しています。これにより、これらのOSでソケット経由でのFD受け渡しが正しく機能するようになります。
コミット
commit 98d44d140d7abde9fdfbdbf7adec5be7bb0892ce
Author: Dave Cheney <dave@cheney.net>
Date: Wed Feb 27 09:13:15 2013 +1100
syscall: fix FD passing on FreeBSD and NetBSD
Fixes #3348.
R=devon.odell, minux.ma, bradfitz, mdempsky
CC=golang-dev
https://golang.org/cl/7406050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/98d44d140d7abde9fdfbdbf7adec5be7bb0892ce
元コミット内容
syscall: fix FD passing on FreeBSD and NetBSD
Fixes #3348.
R=devon.odell, minux.ma, bradfitz, mdempsky
CC=golang-dev
https://golang.org/cl/7406050
変更の背景
Go言語のsyscall
パッケージは、OSのシステムコールをGoプログラムから呼び出すためのインターフェースを提供します。ファイルディスクリプタ(FD)の受け渡しは、プロセス間通信(IPC)において、あるプロセスがオープンしているファイルやソケットのFDを別のプロセスに安全に渡すための重要な機能です。これは通常、Unixドメインソケットを介してコントロールメッセージ(SCM_RIGHTS
)として行われます。
Goの初期バージョンでは、FreeBSDやNetBSDといった一部のUnix系OSにおいて、このFD受け渡し機能が正しく動作しないというバグ(Issue #3348)が報告されていました。この問題は、コントロールメッセージの構造体(Cmsghdr
)の後に続くデータ部分のアライメント(メモリ配置の制約)が、OSによって異なるために発生していました。特に、FreeBSDやNetBSDでは、データ部分が特定のバイト境界にアライメントされている必要がありましたが、Goの既存の実装ではこのアライメントが考慮されていなかったため、不正なメモリアクセスやデータの破損が発生し、FDの受け渡しが失敗していました。
このコミットは、このFD受け渡しに関するバグを修正し、GoプログラムがFreeBSDおよびNetBSD上でも安定してFDをやり取りできるようにすることを目的としています。
前提知識の解説
1. ファイルディスクリプタ(File Descriptor, FD)
ファイルディスクリプタは、Unix系OSにおいて、プロセスがファイル、ソケット、パイプなどのI/Oリソースを識別するために使用する整数値です。プロセスはFDを通じてこれらのリソースにアクセスします。
2. プロセス間通信(Inter-Process Communication, IPC)
異なるプロセス間でデータや情報を交換するメカニズムの総称です。FDの受け渡しは、IPCの一種であり、特に特権を伴うリソースの共有に利用されます。
3. Unixドメインソケット
同じホスト上のプロセス間での通信に特化したソケットの一種です。ネットワークソケットとは異なり、ファイルシステム上のパス名で識別されます。高速で安全なIPC手段として広く利用されます。
4. コントロールメッセージ(Control Message)
ソケット通信において、通常のデータとは別に、補助的な情報(例: ファイルディスクリプタ、認証情報、帯域外データ)をやり取りするためのメカニズムです。sendmsg()
やrecvmsg()
システムコールで送受信されます。
5. Cmsghdr
構造体
コントロールメッセージのヘッダ部分を定義する構造体です。メッセージのタイプ(例: SCM_RIGHTS
)、長さ、レベルなどの情報を含みます。このヘッダの直後に、実際のコントロールデータ(例: 渡されるFDのリスト)が続きます。
6. SCM_RIGHTS
ファイルディスクリプタをコントロールメッセージとして送受信する際に使用されるコントロールメッセージタイプです。
7. メモリアライメント(Memory Alignment)
コンピュータのメモリ上でデータが配置される際の、特定のバイト境界への制約です。CPUは、特定のデータ型(例: 整数、ポインタ)が特定のバイト境界(例: 4バイト、8バイト)に配置されている場合に、より効率的にアクセスできます。アライメントが正しくないと、パフォーマンスの低下や、最悪の場合、不正なメモリアクセスによるプログラムのクラッシュを引き起こす可能性があります。特に、異なるアーキテクチャやOSでは、アライメントの要件が異なることがあります。
8. unsafe
パッケージ(Go言語)
Go言語のunsafe
パッケージは、型安全性をバイパスして、ポインタ演算や型変換を可能にする機能を提供します。これは、C言語との相互運用や、低レベルのシステムプログラミング(syscall
パッケージなど)で必要となることがありますが、誤用するとメモリ破壊や未定義動作を引き起こす可能性があるため、慎重に使用する必要があります。
unsafe.Pointer
: 任意の型のポインタを保持できる汎用ポインタ。uintptr
: ポインタを整数として扱うことができる型。ポインタ演算を行う際に使用されます。
技術的詳細
このコミットの核心は、Cmsghdr
構造体の直後に続くコントロールデータのアドレス計算にあります。Unix系OSでは、Cmsghdr
のサイズは固定ですが、その後に続くデータ部分が特定のバイト境界にアライメントされている必要があります。このアライメント要件はOSによって異なり、単にCmsghdr
のサイズを足すだけでは不十分な場合があります。
元のコードでは、cmsgData
関数がコントロールデータの開始アドレスを計算する際に、Cmsghdr
のサイズ(SizeofCmsghdr
)を単純に現在のポインタに加算していました。
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
しかし、FreeBSDやNetBSDのようなシステムでは、Cmsghdr
の直後のデータが、そのシステムのポインタサイズやデータ型の最大アライメント要件に合わせてパディングされる必要があります。このパディングを考慮しないと、データ部分の開始アドレスが不正なアライメントになり、FDの受け渡しが失敗する原因となります。
修正後のコードでは、cmsgAlignOf
という新しい関数が導入され、SizeofCmsghdr
をこのアライメント関数に通すことで、OSが要求する適切なアライメントを考慮したオフセットを計算しています。
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
cmsgAlignOf
関数は、おそらくOS固有のアライメント要件(例えば、CMSG_ALIGN
マクロに相当するロジック)をカプセル化しており、与えられたサイズを次の適切なアライメント境界に切り上げる役割を果たします。これにより、Cmsghdr
の直後のデータが常に正しくアライメントされたアドレスから始まることが保証され、FDの受け渡しが安定して行われるようになります。
また、passfd_test.go
のビルドタグにfreebsd
とnetbsd
が追加されたことは、この修正がこれらのOSでテストされることを意味しており、修正の有効性を確認するための重要なステップです。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は以下の2ファイルです。
src/pkg/syscall/passfd_test.go
src/pkg/syscall/sockcmsg_unix.go
src/pkg/syscall/passfd_test.go
--- a/src/pkg/syscall/passfd_test.go
+++ b/src/pkg/syscall/passfd_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux darwin
+// +build linux darwin freebsd netbsd
package syscall_test
src/pkg/syscall/sockcmsg_unix.go
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -37,7 +37,7 @@ func CmsgSpace(datalen int) int {
}
func cmsgData(h *Cmsghdr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}
// SocketControlMessage represents a socket control message.
コアとなるコードの解説
src/pkg/syscall/passfd_test.go
の変更
このファイルは、ファイルディスクリプタの受け渡し機能をテストするためのコードを含んでいます。変更前はlinux
とdarwin
(macOS)でのみビルドされるように指定されていました。
// +build linux darwin
この行が以下のように変更されました。
// +build linux darwin freebsd netbsd
これは、passfd_test.go
に含まれるテストコードが、今後はFreeBSDとNetBSD上でもコンパイルされ、実行されるべきであることを示しています。これにより、今回のFD受け渡しに関する修正が、これらのOSで正しく機能するかどうかを自動的に検証できるようになります。これは、クロスプラットフォームな互換性を確保するための重要なステップです。
src/pkg/syscall/sockcmsg_unix.go
の変更
このファイルは、Unix系OSにおけるソケットコントロールメッセージ(Cmsg
)の処理に関連する関数を含んでいます。特に注目すべきはcmsgData
関数の変更です。
cmsgData
関数は、Cmsghdr
構造体のポインタh
を受け取り、そのヘッダの直後に続くコントロールデータの開始アドレスを計算して返します。
変更前のコード:
func cmsgData(h *Cmsghdr) unsafe.Pointer {
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
}
このコードでは、Cmsghdr
のポインタh
をuintptr
に変換し、それにCmsghdr
のサイズ(SizeofCmsghdr
)を単純に加算していました。これは、ヘッダの直後にデータが連続して配置されているという前提に基づいています。しかし、前述の通り、一部のOSではCmsghdr
とデータの間に追加のパディングが必要となる場合があります。
変更後のコード:
func cmsgData(h *Cmsghdr) unsafe.Pointer {
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}
この変更では、SizeofCmsghdr
を直接加算する代わりに、cmsgAlignOf
という関数を介して計算されたオフセットを使用しています。cmsgAlignOf
関数は、引数として与えられたサイズ(ここではSizeofCmsghdr
)を、OSが要求する適切なアライメント境界に切り上げる役割を担います。例えば、もしOSが8バイトアライメントを要求し、SizeofCmsghdr
が28バイトだった場合、cmsgAlignOf(28)
は32を返すかもしれません。これにより、Cmsghdr
の直後のデータが常に正しくアライメントされたアドレスから始まることが保証されます。
この修正により、FreeBSDやNetBSDといったOS固有のアライメント要件が満たされ、ソケット経由でのファイルディスクリプタの受け渡しが安定して行われるようになります。
関連リンク
- Go Issue #3348: https://code.google.com/p/go/issues/detail?id=3348 (古いGoogle Codeのリンクですが、コミットメッセージに記載されています)
- Go CL 7406050: https://golang.org/cl/7406050 (GoのコードレビューシステムGerritのリンク)
参考にした情報源リンク
- UnixドメインソケットとFD受け渡しに関する一般的な情報:
- Go言語の
unsafe
パッケージに関するドキュメント: - FreeBSDの
cmsg
関連マクロ(参考):- https://www.freebsd.org/cgi/man.cgi?query=cmsg&sektion=3&format=html (特に
CMSG_ALIGN
やCMSG_SPACE
などの概念)
- https://www.freebsd.org/cgi/man.cgi?query=cmsg&sektion=3&format=html (特に
- NetBSDの
cmsg
関連マクロ(参考):- https://man.netbsd.org/cmsg.3# [インデックス 15451] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるファイルディスクリプタ(FD)の受け渡しに関するバグ修正です。特にFreeBSDとNetBSDというUnix系OS上での挙動に焦点を当て、コントロールメッセージ(Cmsg
)のデータ部分へのポインタ計算におけるアライメントの問題を解決しています。これにより、これらのOSでソケット経由でのFD受け渡しが正しく機能するようになります。
コミット
commit 98d44d140d7abde9fdfbdbf7adec5be7bb0892ce
Author: Dave Cheney <dave@cheney.net>
Date: Wed Feb 27 09:13:15 2013 +1100
syscall: fix FD passing on FreeBSD and NetBSD
Fixes #3348.
R=devon.odell, minux.ma, bradfitz, mdempsky
CC=golang-dev
https://golang.org/cl/7406050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/98d44d140d7abde9fdfbdbf7adec5be7bb0892ce
元コミット内容
syscall: fix FD passing on FreeBSD and NetBSD
Fixes #3348.
R=devon.odell, minux.ma, bradfitz, mdempsky
CC=golang-dev
https://golang.org/cl/7406050
変更の背景
Go言語のsyscall
パッケージは、OSのシステムコールをGoプログラムから呼び出すためのインターフェースを提供します。ファイルディスクリプタ(FD)の受け渡しは、プロセス間通信(IPC)において、あるプロセスがオープンしているファイルやソケットのFDを別のプロセスに安全に渡すための重要な機能です。これは通常、Unixドメインソケットを介してコントロールメッセージ(SCM_RIGHTS
)として行われます。
Goの初期バージョンでは、FreeBSDやNetBSDといった一部のUnix系OSにおいて、このFD受け渡し機能が正しく動作しないというバグ(Issue #3348)が報告されていました。この問題は、コントロールメッセージの構造体(Cmsghdr
)の後に続くデータ部分のアライメント(メモリ配置の制約)が、OSによって異なるために発生していました。特に、FreeBSDやNetBSDでは、データ部分が特定のバイト境界にアライメントされている必要がありましたが、Goの既存の実装ではこのアライメントが考慮されていなかったため、不正なメモリアクセスやデータの破損が発生し、FDの受け渡しが失敗していました。
このコミットは、このFD受け渡しに関するバグを修正し、GoプログラムがFreeBSDおよびNetBSD上でも安定してFDをやり取りできるようにすることを目的としています。
前提知識の解説
1. ファイルディスクリプタ(File Descriptor, FD)
ファイルディスクリプタは、Unix系OSにおいて、プロセスがファイル、ソケット、パイプなどのI/Oリソースを識別するために使用する整数値です。プロセスはFDを通じてこれらのリソースにアクセスします。
2. プロセス間通信(Inter-Process Communication, IPC)
異なるプロセス間でデータや情報を交換するメカニズムの総称です。FDの受け渡しは、IPCの一種であり、特に特権を伴うリソースの共有に利用されます。
3. Unixドメインソケット
同じホスト上のプロセス間での通信に特化したソケットの一種です。ネットワークソケットとは異なり、ファイルシステム上のパス名で識別されます。高速で安全なIPC手段として広く利用されます。
4. コントロールメッセージ(Control Message)
ソケット通信において、通常のデータとは別に、補助的な情報(例: ファイルディスクリプタ、認証情報、帯域外データ)をやり取りするためのメカニズムです。sendmsg()
やrecvmsg()
システムコールで送受信されます。
5. Cmsghdr
構造体
コントロールメッセージのヘッダ部分を定義する構造体です。メッセージのタイプ(例: SCM_RIGHTS
)、長さ、レベルなどの情報を含みます。このヘッダの直後に、実際のコントロールデータ(例: 渡されるFDのリスト)が続きます。
6. SCM_RIGHTS
ファイルディスクリプタをコントロールメッセージとして送受信する際に使用されるコントロールメッセージタイプです。
7. メモリアライメント(Memory Alignment)
コンピュータのメモリ上でデータが配置される際の、特定のバイト境界への制約です。CPUは、特定のデータ型(例: 整数、ポインタ)が特定のバイト境界(例: 4バイト、8バイト)に配置されている場合に、より効率的にアクセスできます。アライメントが正しくないと、パフォーマンスの低下や、最悪の場合、不正なメモリアクセスによるプログラムのクラッシュを引き起こす可能性があります。特に、異なるアーキテクチャやOSでは、アライメントの要件が異なることがあります。
8. unsafe
パッケージ(Go言語)
Go言語のunsafe
パッケージは、型安全性をバイパスして、ポインタ演算や型変換を可能にする機能を提供します。これは、C言語との相互運用や、低レベルのシステムプログラミング(syscall
パッケージなど)で必要となることがありますが、誤用するとメモリ破壊や未定義動作を引き起こす可能性があるため、慎重に使用する必要があります。
unsafe.Pointer
: 任意の型のポインタを保持できる汎用ポインタ。uintptr
: ポインタを整数として扱うことができる型。ポインタ演算を行う際に使用されます。
技術的詳細
このコミットの核心は、Cmsghdr
構造体の直後に続くコントロールデータのアドレス計算にあります。Unix系OSでは、Cmsghdr
のサイズは固定ですが、その後に続くデータ部分が特定のバイト境界にアライメントされている必要があります。このアライメント要件はOSによって異なり、単にCmsghdr
のサイズを足すだけでは不十分な場合があります。
元のコードでは、cmsgData
関数がコントロールデータの開始アドレスを計算する際に、Cmsghdr
のサイズ(SizeofCmsghdr
)を単純に加算していました。
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
しかし、FreeBSDやNetBSDのようなシステムでは、Cmsghdr
の直後のデータが、そのシステムのポインタサイズやデータ型の最大アライメント要件に合わせてパディングされる必要があります。このパディングを考慮しないと、データ部分の開始アドレスが不正なアライメントになり、FDの受け渡しが失敗する原因となります。
修正後のコードでは、cmsgAlignOf
という新しい関数が導入され、SizeofCmsghdr
をこのアライメント関数に通すことで、OSが要求する適切なアライメントを考慮したオフセットを計算しています。
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
cmsgAlignOf
関数は、おそらくOS固有のアライメント要件(例えば、CMSG_ALIGN
マクロに相当するロジック)をカプセル化しており、与えられたサイズを次の適切なアライメント境界に切り上げる役割を果たします。これにより、Cmsghdr
の直後のデータが常に正しくアライメントされたアドレスから始まることが保証され、FDの受け渡しが安定して行われるようになります。
また、passfd_test.go
のビルドタグにfreebsd
とnetbsd
が追加されたことは、この修正がこれらのOSでテストされることを意味しており、修正の有効性を確認するための重要なステップです。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は以下の2ファイルです。
src/pkg/syscall/passfd_test.go
src/pkg/syscall/sockcmsg_unix.go
src/pkg/syscall/passfd_test.go
--- a/src/pkg/syscall/passfd_test.go
+++ b/src/pkg/syscall/passfd_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux darwin
+// +build linux darwin freebsd netbsd
package syscall_test
src/pkg/syscall/sockcmsg_unix.go
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -37,7 +37,7 @@ func CmsgSpace(datalen int) int {
}
func cmsgData(h *Cmsghdr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}
// SocketControlMessage represents a socket control message.
コアとなるコードの解説
src/pkg/syscall/passfd_test.go
の変更
このファイルは、ファイルディスクリプタの受け渡し機能をテストするためのコードを含んでいます。変更前はlinux
とdarwin
(macOS)でのみビルドされるように指定されていました。
// +build linux darwin
この行が以下のように変更されました。
// +build linux darwin freebsd netbsd
これは、passfd_test.go
に含まれるテストコードが、今後はFreeBSDとNetBSD上でもコンパイルされ、実行されるべきであることを示しています。これにより、今回のFD受け渡しに関する修正が、これらのOSで正しく機能するかどうかを自動的に検証できるようになります。これは、クロスプラットフォームな互換性を確保するための重要なステップです。
src/pkg/syscall/sockcmsg_unix.go
の変更
このファイルは、Unix系OSにおけるソケットコントロールメッセージ(Cmsg
)の処理に関連する関数を含んでいます。特に注目すべきはcmsgData
関数の変更です。
cmsgData
関数は、Cmsghdr
構造体のポインタh
を受け取り、そのヘッダの直後に続くコントロールデータの開始アドレスを計算して返します。
変更前のコード:
func cmsgData(h *Cmsghdr) unsafe.Pointer {
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
}
このコードでは、Cmsghdr
のポインタh
をuintptr
に変換し、それにCmsghdr
のサイズ(SizeofCmsghdr
)を単純に加算していました。これは、ヘッダの直後にデータが連続して配置されているという前提に基づいています。しかし、前述の通り、一部のOSではCmsghdr
とデータの間に追加のパディングが必要となる場合があります。
変更後のコード:
func cmsgData(h *Cmsghdr) unsafe.Pointer {
return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
}
この変更では、SizeofCmsghdr
を直接加算する代わりに、cmsgAlignOf
という関数を介して計算されたオフセットを使用しています。cmsgAlignOf
関数は、引数として与えられたサイズ(ここではSizeofCmsghdr
)を、OSが要求する適切なアライメント境界に切り上げる役割を担います。例えば、もしOSが8バイトアライメントを要求し、SizeofCmsghdr
が28バイトだった場合、cmsgAlignOf(28)
は32を返すかもしれません。これにより、Cmsghdr
の直後のデータが常に正しくアライメントされたアドレスから始まることが保証されます。
この修正により、FreeBSDやNetBSDといったOS固有のアライメント要件が満たされ、ソケット経由でのファイルディスクリプタの受け渡しが安定して行われるようになります。
関連リンク
- Go Issue #3348: https://code.google.com/p/go/issues/detail?id=3348 (古いGoogle Codeのリンクですが、コミットメッセージに記載されています)
- Go CL 7406050: https://golang.org/cl/7406050 (GoのコードレビューシステムGerritのリンク)
参考にした情報源リンク
- UnixドメインソケットとFD受け渡しに関する一般的な情報:
- Go言語の
unsafe
パッケージに関するドキュメント: - FreeBSDの
cmsg
関連マクロ(参考):- https://www.freebsd.org/cgi/man.cgi?query=cmsg&sektion=3&format=html (特に
CMSG_ALIGN
やCMSG_SPACE
などの概念)
- https://www.freebsd.org/cgi/man.cgi?query=cmsg&sektion=3&format=html (特に
- NetBSDの
cmsg
関連マクロ(参考):