[インデックス 19242] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、DragonFly BSDオペレーティングシステム上でのソケット制御メッセージ(cmsg
)のハンドリングに関するバグを修正するものです。具体的には、64ビットのDragonFly BSDカーネルがネットワークサブシステムに対して32ビットのアライメントを要求するという特殊な要件に対応するため、cmsgAlignOf
関数におけるアライメント計算ロジックを更新しています。これにより、DragonFly BSD環境でのソケット通信の安定性と正確性が向上します。
コミット
commit d844d6982ebd3ea2a1a146d753581018f977c6ec
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Sun Apr 27 22:28:41 2014 +0900
syscall: fix handling socket control messages on dragonfly
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/91860043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d844d6982ebd3ea2a1a146d753581018f977c6ec
元コミット内容
syscall: fix handling socket control messages on dragonfly
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/91860043
変更の背景
この変更の背景には、特定のオペレーティングシステム(OS)におけるメモリアライメントの特殊な要件があります。Go言語のsyscall
パッケージは、OSのシステムコールを直接呼び出すためのインターフェースを提供しており、ネットワーク通信など低レベルな操作を行う際に利用されます。ソケットを介したデータ送受信では、補助データ(control messages、cmsg
)をやり取りすることがあります。この補助データは、ファイルディスクリプタの受け渡しや、IPヘッダ情報の取得など、通常のデータとは異なるメタ情報を伝達するために使用されます。
問題は、64ビットシステムにおいて、一部のOSカーネルがネットワーク関連のデータ構造(特にsockaddr
構造体やcmsg
データ)に対して、期待される64ビットアライメントではなく、32ビットアライメントを要求する場合があることです。以前のGoのsyscall
パッケージでは、64ビットのDarwin(macOS)カーネルが同様の要件を持つことが知られており、これに対応するための修正が既に導入されていました。
しかし、DragonFly BSDという別のBSD系OSの64ビットカーネルも、同様にネットワークサブシステムに対して32ビットアライメントを要求するという特殊な振る舞いをすることが判明しました。Goのランタイムがこの要件を考慮せずにcmsg
データを処理しようとすると、メモリアライメントの不一致が発生し、データ破損やクラッシュといった予期せぬ動作を引き起こす可能性がありました。このコミットは、DragonFly BSD環境でのソケット制御メッセージの正しいハンドリングを保証するために、既存のDarwin向けのアライメント修正をDragonFly BSDにも拡張することを目的としています。
前提知識の解説
1. ソケット制御メッセージ (Control Messages, cmsg
)
ソケット制御メッセージは、通常のデータストリームとは別に、ソケットを介して補助的な情報を送受信するためのメカニズムです。sendmsg
やrecvmsg
といったシステムコールで使用され、msghdr
構造体内のmsg_control
およびmsg_controllen
フィールドを通じてアクセスされます。
一般的な用途としては以下のようなものがあります。
- ファイルディスクリプタの受け渡し (SCM_RIGHTS): プロセス間でファイルディスクリプタを渡すことができます。
- IPヘッダ情報の取得 (IP_PKTINFO): 受信したIPパケットの送信元アドレスやインターフェースインデックスなどの情報を取得します。
- ユーザー認証情報 (SCM_CREDENTIALS): 送信元のユーザーID、グループID、プロセスIDなどの情報を取得します。
cmsg
データは、cmsghdr
構造体に続いて実際のデータが格納される形式を取ります。この構造体は、メッセージのタイプ、レベル、そしてデータの長さを定義します。
2. sockaddr
構造体とメモリアライメント
sockaddr
は、ソケットアドレスを表現するための汎用的な構造体です。具体的なアドレス形式(例: IPv4, IPv6, Unixドメイン)に応じて、sockaddr_in
, sockaddr_in6
, sockaddr_un
などの派生構造体が使用されます。これらの構造体は、ネットワークアドレスやポート番号などの情報を含みます。
メモリアライメントとは、データがメモリ上で特定のバイト境界に配置されることを指します。CPUは、特定のデータ型(例: 32ビット整数、64ビットポインタ)を効率的に読み書きするために、そのデータ型のサイズと同じか、それ以上の境界にデータが配置されていることを期待します。例えば、4バイトの整数は4バイト境界(アドレスが4の倍数)に、8バイトのポインタは8バイト境界に配置されるのが一般的です。
アライメントが正しくない場合(アライメントされていないアクセス)、CPUはデータを読み書きするために複数のメモリアクセスを行う必要があり、パフォーマンスが低下したり、最悪の場合、アライメント違反例外(segmentation faultなど)が発生してプログラムがクラッシュしたりすることがあります。
3. cmsgAlignOf
関数の役割
cmsgAlignOf
関数は、ソケット制御メッセージのデータ部分(sockaddr
などの構造体)がメモリ上で適切にアライメントされるように、その長さを調整(パディング)するために使用されます。OSカーネルが特定のデータ構造に対して特殊なアライメント要件を持つ場合、この関数はその要件を満たすように長さを「切り上げ」ます。
例えば、64ビットシステムでポインタサイズが8バイトであっても、カーネルが32ビットアライメント(4バイト境界)を要求する場合、cmsgAlignOf
はデータの長さを4バイトの倍数に調整します。
4. sizeofPtr
sizeofPtr
は、Goのランタイムが認識するポインタのサイズ(バイト単位)を表す定数です。32ビットシステムでは通常4、64ビットシステムでは通常8になります。これは、Goプログラムが実行されているアーキテクチャのポインタサイズを反映します。
5. DragonFly BSD
DragonFly BSDは、FreeBSD 4.8からフォークして開発されたオープンソースのUnix系オペレーティングシステムです。高性能とスケーラビリティを重視しており、特にSMP(Symmetric Multiprocessing)システムでの効率的な動作を目指しています。独自のファイルシステムであるHAMMERや、軽量カーネルスレッド(LWKT)などの特徴的な技術を持っています。
一部のBSD系OS(特に古いカーネルや特定のサブシステム)では、64ビット環境であっても、互換性や設計上の理由から、ネットワーク関連のデータ構造に対して32ビットアライメントを要求する場合があります。これは、カーネル内部のデータ構造が32ビットワードで設計されているため、64ビットのポインタやデータが32ビット境界に配置されることを前提としているためです。
6. Goのsyscall
パッケージ
Go言語のsyscall
パッケージは、低レベルなOSプリミティブへのアクセスを提供します。これには、ファイル操作、プロセス管理、ネットワーク通信など、OSが提供するシステムコールを直接呼び出す機能が含まれます。Goの標準ライブラリの多くの部分(例: os
, net
パッケージ)は、内部的にこのsyscall
パッケージを利用してOSと対話しています。異なるOS間で移植性を保ちつつ、OS固有の機能にアクセスするために重要なパッケージです。
技術的詳細
このコミットの技術的な核心は、Goのsyscall
パッケージがソケット制御メッセージを処理する際に、DragonFly BSDの64ビットカーネルが持つ特殊なメモリアライメント要件を認識し、それに対応することです。
既存のコードでは、cmsgAlignOf
関数がsockaddr
構造体の長さを適切にアライメントするために使用されていました。この関数は、デフォルトではポインタサイズ(sizeofPtr
)に基づいてアライメントを行いますが、64ビットのDarwinカーネルがネットワークサブシステムに対して32ビットアライメント(4バイト境界)を要求するという既知の問題に対応するため、darwin64Bit
というフラグが導入されていました。darwin64Bit
が真の場合、salign
(アライメント境界)はsizeofPtr
(8)ではなく4
に設定され、32ビットアライメントが強制されます。
このコミットでは、同様の要件がDragonFly BSDの64ビットカーネルにも存在することが確認されたため、cmsgAlignOf
関数内の条件式にdragonfly64Bit
という新しいフラグを追加しています。
具体的には、以下の変更が行われました。
-
dragonfly64Bit
定数の追加:src/pkg/syscall/syscall_unix.go
ファイルに、dragonfly64Bit
という新しいブール定数が追加されました。この定数は、GoがDragonFly BSD上で動作しており、かつポインタサイズが8バイト(すなわち64ビットシステム)である場合にtrue
となります。dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
ここで、
runtime.GOOS
はGoプログラムが実行されているOSの名前(例: "darwin", "linux", "dragonfly")を返すGoの組み込み定数です。 -
cmsgAlignOf
関数の条件式の更新:src/pkg/syscall/sockcmsg_unix.go
ファイル内のcmsgAlignOf
関数において、アライメント境界を決定する条件式が更新されました。 変更前:if darwin64Bit { salign = 4 }
変更後:
if darwin64Bit || dragonfly64Bit { salign = 4 }
これにより、64ビットのDarwinまたはDragonFly BSDのいずれかの環境で実行されている場合、
salign
は4に設定され、ソケット制御メッセージのデータが32ビット境界にアライメントされるようになります。
この修正により、Goのsyscall
パッケージは、DragonFly BSDの64ビット環境においても、ソケット制御メッセージの送受信時に正しいメモリアライメントを保証できるようになり、関連するシステムコールが安定して動作するようになります。これは、Goのクロスプラットフォーム互換性を高める上で重要な改善です。
コアとなるコードの変更箇所
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index 2cdc28ee35..045a012c05 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -13,9 +13,9 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index de5ff95cf1..b28891568d 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -19,8 +19,9 @@ var (
)
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)\n
コアとなるコードの解説
src/pkg/syscall/syscall_unix.go
の変更
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
この部分では、Goのビルド時に特定のOSとアーキテクチャの組み合わせを識別するための定数が定義されています。
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
: 変更前は、Darwin(macOS)上で64ビット環境(ポインタサイズが8バイト)であるかを判定する定数でした。+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
: 新たに追加された行です。これは、GoがDragonFly BSD上で動作しており、かつ64ビット環境(ポインタサイズが8バイト)である場合にtrue
となる定数dragonfly64Bit
を定義しています。これにより、DragonFly BSDの64ビット環境をGoのコード内で識別できるようになります。netbsd32Bit
はNetBSDの32ビット環境を識別するための既存の定数で、このコミットでは変更されていません。
src/pkg/syscall/sockcmsg_unix.go
の変更
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
このcmsgAlignOf
関数は、ソケット制御メッセージのデータ部分の長さを、特定のOSが要求するアライメント境界に合わせて切り上げる役割を担っています。
salign := sizeofPtr
: デフォルトのアライメント境界をポインタサイズ(64ビットシステムでは8バイト)に設定します。- if darwin64Bit { salign = 4 }
: 変更前は、64ビットのDarwin環境でのみ、アライメント境界を32ビット(4バイト)に強制していました。これは、Darwinカーネルがネットワークサブシステムに対して32ビットアライメントを要求するためです。+ if darwin64Bit || dragonfly64Bit { salign = 4 }
: 変更後では、条件式に|| dragonfly64Bit
が追加されました。これにより、64ビットのDarwin環境または64ビットのDragonFly BSD環境のいずれかで実行されている場合、salign
が4に設定されます。これは、DragonFly BSDの64ビットカーネルも同様にネットワークサブシステムに対して32ビットアライメントを要求するという発見に基づいています。return (salen + salign - 1) & ^(salign - 1)
: この行は、salen
(元の長さ)をsalign
の倍数に切り上げるためのビット演算です。例えば、salign
が4の場合、salen
が10であれば、(10 + 4 - 1) & ^(4 - 1)
=13 & ^3
=13 & ~3
=13 & 0xFFFFFFFC
=12
となり、4の倍数に切り上げられます。
これらの変更により、Goのsyscall
パッケージは、DragonFly BSDの64ビット環境においても、ソケット制御メッセージのデータがカーネルの期待する32ビットアライメントで正しく配置されることを保証し、アライメント違反による潜在的な問題を回避します。
関連リンク
- Go CL (Code Review) 91860043: https://golang.org/cl/91860043
参考にした情報源リンク
- Go言語の
syscall
パッケージに関する公式ドキュメントやソースコード - BSD系OS(特にDragonFly BSD)のメモリアライメントに関する情報
- ソケットプログラミングにおける制御メッセージ(
cmsg
)に関する一般的な情報 runtime.GOOS
に関するGoのドキュメントsizeofPtr
に関するGoのドキュメント- https://golang.org/cl/91860043 (Goのコードレビューシステム)# [インデックス 19242] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおいて、DragonFly BSDオペレーティングシステム上でのソケット制御メッセージ(cmsg
)のハンドリングに関するバグを修正するものです。具体的には、64ビットのDragonFly BSDカーネルがネットワークサブシステムに対して32ビットのアライメントを要求するという特殊な要件に対応するため、cmsgAlignOf
関数におけるアライメント計算ロジックを更新しています。これにより、DragonFly BSD環境でのソケット通信の安定性と正確性が向上します。
コミット
commit d844d6982ebd3ea2a1a146d753581018f977c6ec
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Sun Apr 27 22:28:41 2014 +0900
syscall: fix handling socket control messages on dragonfly
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/91860043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d844d6982ebd3ea2a1a146d753581018f977c6ec
元コミット内容
syscall: fix handling socket control messages on dragonfly
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/91860043
変更の背景
この変更の背景には、特定のオペレーティングシステム(OS)におけるメモリアライメントの特殊な要件があります。Go言語のsyscall
パッケージは、OSのシステムコールを直接呼び出すためのインターフェースを提供しており、ネットワーク通信など低レベルな操作を行う際に利用されます。ソケットを介したデータ送受信では、補助データ(control messages、cmsg
)をやり取りすることがあります。この補助データは、ファイルディスクリプタの受け渡しや、IPヘッダ情報の取得など、通常のデータとは異なるメタ情報を伝達するために使用されます。
問題は、64ビットシステムにおいて、一部のOSカーネルがネットワーク関連のデータ構造(特にsockaddr
構造体やcmsg
データ)に対して、期待される64ビットアライメントではなく、32ビットアライメントを要求する場合があることです。以前のGoのsyscall
パッケージでは、64ビットのDarwin(macOS)カーネルが同様の要件を持つことが知られており、これに対応するための修正が既に導入されていました。
しかし、DragonFly BSDという別のBSD系OSの64ビットカーネルも、同様にネットワークサブシステムに対して32ビットアライメントを要求するという特殊な振る舞いをすることが判明しました。Goのランタイムがこの要件を考慮せずにcmsg
データを処理しようとすると、メモリアライメントの不一致が発生し、データ破損やクラッシュといった予期せぬ動作を引き起こす可能性がありました。このコミットは、DragonFly BSD環境でのソケット制御メッセージの正しいハンドリングを保証するために、既存のDarwin向けのアライメント修正をDragonFly BSDにも拡張することを目的としています。
前提知識の解説
1. ソケット制御メッセージ (Control Messages, cmsg
)
ソケット制御メッセージは、通常のデータストリームとは別に、ソケットを介して補助的な情報を送受信するためのメカニズムです。sendmsg
やrecvmsg
といったシステムコールで使用され、msghdr
構造体内のmsg_control
およびmsg_controllen
フィールドを通じてアクセスされます。
一般的な用途としては以下のようなものがあります。
- ファイルディスクリプタの受け渡し (SCM_RIGHTS): プロセス間でファイルディスクリプタを渡すことができます。
- IPヘッダ情報の取得 (IP_PKTINFO): 受信したIPパケットの送信元アドレスやインターフェースインデックスなどの情報を取得します。
- ユーザー認証情報 (SCM_CREDENTIALS): 送信元のユーザーID、グループID、プロセスIDなどの情報を取得します。
cmsg
データは、cmsghdr
構造体に続いて実際のデータが格納される形式を取ります。この構造体は、メッセージのタイプ、レベル、そしてデータの長さを定義します。
2. sockaddr
構造体とメモリアライメント
sockaddr
は、ソケットアドレスを表現するための汎用的な構造体です。具体的なアドレス形式(例: IPv4, IPv6, Unixドメイン)に応じて、sockaddr_in
, sockaddr_in6
, sockaddr_un
などの派生構造体が使用されます。これらの構造体は、ネットワークアドレスやポート番号などの情報を含みます。
メモリアライメントとは、データがメモリ上で特定のバイト境界に配置されることを指します。CPUは、特定のデータ型(例: 32ビット整数、64ビットポインタ)を効率的に読み書きするために、そのデータ型のサイズと同じか、それ以上の境界にデータが配置されていることを期待します。例えば、4バイトの整数は4バイト境界(アドレスが4の倍数)に、8バイトのポインタは8バイト境界に配置されるのが一般的です。
アライメントが正しくない場合(アライメントされていないアクセス)、CPUはデータを読み書きするために複数のメモリアクセスを行う必要があり、パフォーマンスが低下したり、最悪の場合、アライメント違反例外(segmentation faultなど)が発生してプログラムがクラッシュしたりすることがあります。
3. cmsgAlignOf
関数の役割
cmsgAlignOf
関数は、ソケット制御メッセージのデータ部分(sockaddr
などの構造体)がメモリ上で適切にアライメントされるように、その長さを調整(パディング)するために使用されます。OSカーネルが特定のデータ構造に対して特殊なアライメント要件を持つ場合、この関数はその要件を満たすように長さを「切り上げ」ます。
例えば、64ビットシステムでポインタサイズが8バイトであっても、カーネルが32ビットアライメント(4バイト境界)を要求する場合、cmsgAlignOf
はデータの長さを4バイトの倍数に調整します。
4. sizeofPtr
sizeofPtr
は、Goのランタイムが認識するポインタのサイズ(バイト単位)を表す定数です。32ビットシステムでは通常4、64ビットシステムでは通常8になります。これは、Goプログラムが実行されているアーキテクチャのポインタサイズを反映します。
5. DragonFly BSD
DragonFly BSDは、FreeBSD 4.8からフォークして開発されたオープンソースのUnix系オペレーティングシステムです。高性能とスケーラビリティを重視しており、特にSMP(Symmetric Multiprocessing)システムでの効率的な動作を目指しています。独自のファイルシステムであるHAMMERや、軽量カーネルスレッド(LWKT)などの特徴的な技術を持っています。
一部のBSD系OS(特に古いカーネルや特定のサブシステム)では、64ビット環境であっても、互換性や設計上の理由から、ネットワーク関連のデータ構造に対して32ビットアライメントを要求する場合があります。これは、カーネル内部のデータ構造が32ビットワードで設計されているため、64ビットのポインタやデータが32ビット境界に配置されることを前提としているためです。
6. Goのsyscall
パッケージ
Go言語のsyscall
パッケージは、低レベルなOSプリミティブへのアクセスを提供します。これには、ファイル操作、プロセス管理、ネットワーク通信など、OSが提供するシステムコールを直接呼び出す機能が含まれます。Goの標準ライブラリの多くの部分(例: os
, net
パッケージ)は、内部的にこのsyscall
パッケージを利用してOSと対話しています。異なるOS間で移植性を保ちつつ、OS固有の機能にアクセスするために重要なパッケージです。
技術的詳細
このコミットの技術的な核心は、Goのsyscall
パッケージがソケット制御メッセージを処理する際に、DragonFly BSDの64ビットカーネルが持つ特殊なメモリアライメント要件を認識し、それに対応することです。
既存のコードでは、cmsgAlignOf
関数がsockaddr
構造体の長さを適切にアライメントするために使用されていました。この関数は、デフォルトではポインタサイズ(sizeofPtr
)に基づいてアライメントを行いますが、64ビットのDarwinカーネルがネットワークサブシステムに対して32ビットアライメント(4バイト境界)を要求するという既知の問題に対応するため、darwin64Bit
というフラグが導入されていました。darwin64Bit
が真の場合、salign
(アライメント境界)はsizeofPtr
(8)ではなく4
に設定され、32ビットアライメントが強制されます。
このコミットでは、同様の要件がDragonFly BSDの64ビットカーネルにも存在することが確認されたため、cmsgAlignOf
関数内の条件式にdragonfly64Bit
という新しいフラグを追加しています。
具体的には、以下の変更が行われました。
-
dragonfly64Bit
定数の追加:src/pkg/syscall/syscall_unix.go
ファイルに、dragonfly64Bit
という新しいブール定数が追加されました。この定数は、GoがDragonFly BSD上で動作しており、かつポインタサイズが8バイト(すなわち64ビットシステム)である場合にtrue
となります。dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
ここで、
runtime.GOOS
はGoプログラムが実行されているOSの名前(例: "darwin", "linux", "dragonfly")を返すGoの組み込み定数です。 -
cmsgAlignOf
関数の条件式の更新:src/pkg/syscall/sockcmsg_unix.go
ファイル内のcmsgAlignOf
関数において、アライメント境界を決定する条件式が更新されました。 変更前:if darwin64Bit { salign = 4 }
変更後:
if darwin64Bit || dragonfly64Bit { salign = 4 }
これにより、64ビットのDarwinまたはDragonFly BSDのいずれかの環境で実行されている場合、
salign
は4に設定され、ソケット制御メッセージのデータが32ビット境界にアライメントされるようになります。
この修正により、Goのsyscall
パッケージは、DragonFly BSDの64ビット環境においても、ソケット制御メッセージの送受信時に正しいメモリアライメントを保証できるようになり、関連するシステムコールが安定して動作するようになります。これは、Goのクロスプラットフォーム互換性を高める上で重要な改善です。
コアとなるコードの変更箇所
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
index 2cdc28ee35..045a012c05 100644
--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -13,9 +13,9 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index de5ff95cf1..b28891568d 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -19,8 +19,9 @@ var (
)
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)\n
コアとなるコードの解説
src/pkg/syscall/syscall_unix.go
の変更
const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
+ netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
)
この部分では、Goのビルド時に特定のOSとアーキテクチャの組み合わせを識別するための定数が定義されています。
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
: 変更前は、Darwin(macOS)上で64ビット環境(ポインタサイズが8バイト)であるかを判定する定数でした。+ dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
: 新たに追加された行です。これは、GoがDragonFly BSD上で動作しており、かつ64ビット環境(ポインタサイズが8バイト)である場合にtrue
となる定数dragonfly64Bit
を定義しています。これにより、DragonFly BSDの64ビット環境をGoのコード内で識別できるようになります。netbsd32Bit
はNetBSDの32ビット環境を識別するための既存の定数で、このコミットでは変更されていません。
src/pkg/syscall/sockcmsg_unix.go
の変更
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
- // aligned access to BSD subsystem.
- if darwin64Bit {
+ // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
+ // still require 32-bit aligned access to network subsystem.
+ if darwin64Bit || dragonfly64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
このcmsgAlignOf
関数は、ソケット制御メッセージのデータ部分の長さを、特定のOSが要求するアライメント境界に合わせて切り上げる役割を担っています。
salign := sizeofPtr
: デフォルトのアライメント境界をポインタサイズ(64ビットシステムでは8バイト)に設定します。- if darwin64Bit { salign = 4 }
: 変更前は、64ビットのDarwin環境でのみ、アライメント境界を32ビット(4バイト)に強制していました。これは、Darwinカーネルがネットワークサブシステムに対して32ビットアライメントを要求するためです。+ if darwin64Bit || dragonfly64Bit { salign = 4 }
: 変更後では、条件式に|| dragonfly64Bit
が追加されました。これにより、64ビットのDarwin環境または64ビットのDragonFly BSD環境のいずれかで実行されている場合、salign
が4に設定されます。これは、DragonFly BSDの64ビットカーネルも同様にネットワークサブシステムに対して32ビットアライメントを要求するという発見に基づいています。return (salen + salign - 1) & ^(salign - 1)
: この行は、salen
(元の長さ)をsalign
の倍数に切り上げるためのビット演算です。例えば、salign
が4の場合、salen
が10であれば、(10 + 4 - 1) & ^(4 - 1)
=13 & ^3
=13 & ~3
=13 & 0xFFFFFFFC
=12
となり、4の倍数に切り上げられます。
これらの変更により、Goのsyscall
パッケージは、DragonFly BSDの64ビット環境においても、ソケット制御メッセージのデータがカーネルの期待する32ビットアライメントで正しく配置されることを保証し、アライメント違反による潜在的な問題を回避します。
関連リンク
- Go CL (Code Review) 91860043: https://golang.org/cl/91860043
参考にした情報源リンク
- Go言語の
syscall
パッケージに関する公式ドキュメントやソースコード - BSD系OS(特にDragonFly BSD)のメモリアライメントに関する情報
- ソケットプログラミングにおける制御メッセージ(
cmsg
)に関する一般的な情報 runtime.GOOS
に関するGoのドキュメントsizeofPtr
に関するGoのドキュメント- https://golang.org/cl/91860043 (Goのコードレビューシステム)