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

[インデックス 13520] ファイルの概要

このコミットは、Go言語のsyscallパッケージにおけるsyscall_bsd.goファイルに対する変更です。具体的には、Acceptシステムコールが特定の条件下で予期せぬ動作をするmacOS(Darwin)カーネルのバグに対応するための修正が含まれています。

コミット

commit 7aa60d998a5f81f58a09e6b1e5703becaf486043
Author: Russ Cox <rsc@golang.org>
Date:   Sun Jul 29 19:50:23 2012 -0400

    syscall: apply comment from Mikioh
    
    This comment was suggested in CL 6456045
    but never got applied.
    
    R=mikioh, mikioh.mikioh
    CC=golang-dev
    https://golang.org/cl/6447056

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/7aa60d998a5f81f58a09e6b1e5703becaf486043

元コミット内容

このコミットは、以前に提案されたものの適用されていなかったMikioh氏からのコメント(コード変更)をsyscallパッケージに適用するものです。この変更は、GoのコードレビューシステムであるGerritの変更リスト(CL)6456045で提案され、その後6447056として追跡されていました。

変更の背景

この変更の背景には、macOS(Darwin)のXNUカーネルにおける特定のバグが存在します。通常、ソケットのAcceptシステムコールは、接続が中断された場合(例えば、クライアントが接続確立前に切断した場合)にECONNABORTEDエラーを返すことが期待されます。しかし、XNUカーネルでは、この状況でECONNABORTEDエラーを返す代わりに、Acceptが成功したかのように見え、しかしながらソケットアドレスの長さ(len)が0になるという予期せぬ振る舞いをすることがありました。

この振る舞いは、Goプログラムがソケット接続を処理する際に問題を引き起こす可能性がありました。len == 0という条件は、通常は有効なソケットアドレスがないことを意味し、プログラムがこれを正常な状態として処理してしまうと、後続の操作でエラーが発生したり、不正な状態に陥ったりする可能性がありました。

このコミットは、このXNUカーネルのバグに対するGoのsyscallパッケージの堅牢性を高めることを目的としています。具体的には、len == 0という条件がmacOS上で発生した場合に、それがカーネルのバグによるものである可能性を考慮し、適切な処理を行うように修正されています。

前提知識の解説

1. syscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)の低レベルなシステムコールにアクセスするための機能を提供します。これにより、ファイル操作、ネットワーク通信、プロセス管理など、OSカーネルが提供する基本的なサービスをGoプログラムから直接利用できます。OSに依存する処理が多く含まれるため、OSごとに異なる実装(例: syscall_bsd.goはBSD系のOS向け)が存在します。

2. Acceptシステムコール

Acceptは、ネットワークプログラミングにおいて、サーバーソケットがクライアントからの接続要求を受け入れるために使用されるシステムコールです。この関数は、新しいソケットディスクリプタと、接続してきたクライアントのアドレス情報を返します。通常、エラーが発生した場合は、その種類を示すエラーコード(例: ECONNABORTED)が返されます。

3. Sockaddr

Sockaddrは、ソケットアドレスを表すデータ構造です。ネットワーク通信において、接続元や接続先のIPアドレスやポート番号などの情報がこの構造体に格納されます。Acceptシステムコールは、接続してきたクライアントのSockaddr情報を返します。

4. runtime.GOOS

runtimeパッケージは、Goランタイムに関する情報や低レベルな操作を提供します。runtime.GOOSは、Goプログラムが実行されているオペレーティングシステムの名前(例: "linux", "darwin", "windows"など)を文字列で返します。これにより、OSに依存するコードを条件分岐で記述することが可能になります。

5. XNUカーネル

XNUは、macOSおよびiOSの基盤となっているハイブリッドカーネルです。MachカーネルとFreeBSDカーネルの要素を組み合わせています。このコミットで言及されている「xnu kernels」は、macOSのカーネルを指しており、特定の条件下でのAcceptシステムコールの振る舞いにバグがあったとされています。

6. ECONNABORTED

ECONNABORTEDは、ソケット接続が中断されたことを示すエラーコードです。これは、通常、接続確立中にクライアントが切断した場合などに発生します。

技術的詳細

このコミットの技術的な核心は、macOS(Darwin)のXNUカーネルにおけるAcceptシステムコールの特殊な振る舞いに対処することです。

通常のAcceptの動作では、クライアントからの接続要求を受け入れる際に、新しいソケットディスクリプタとクライアントのソケットアドレスが返されます。もし接続が途中で中断された場合、AcceptECONNABORTEDのようなエラーを返すことが期待されます。

しかし、XNUカーネルの特定のバージョンでは、接続が中断されたにもかかわらず、Acceptがエラーを返さずに成功したかのように振る舞い、かつ返されるソケットアドレスの長さ(len)が0になるというバグがありました。これは、Goのsyscallパッケージがこのlen == 0の状態を適切に処理しないと、後続のネットワーク操作で問題が発生する可能性を意味します。

このコミットでは、このXNUカーネルのバグを回避するために、Accept関数内でlen == 0のチェックにruntime.GOOS == "darwin"という条件を追加しています。これにより、len == 0という異常な状態がmacOS上で発生した場合にのみ、特別な処理(この場合は、コメントで示唆されているように、その状態を認識し、おそらくはエラーとして扱うか、再試行するなどのロジック)が適用されるようになります。

この修正により、GoのネットワークアプリケーションがmacOS上でより堅牢に動作し、XNUカーネルの既知のバグによる予期せぬ動作を回避できるようになります。

コアとなるコードの変更箇所

変更はsrc/pkg/syscall/syscall_bsd.goファイル内のAccept関数にあります。

--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -13,6 +13,7 @@
 package syscall
 
 import (
+\t"runtime"
 \t"unsafe"
 )
 
@@ -303,7 +304,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
 \tif err != nil {\n \t\treturn\n \t}\n-\tif len == 0 {\n+\tif runtime.GOOS == "darwin" && len == 0 {\n \t\t// Accepted socket has no address.\n \t\t// This is likely due to a bug in xnu kernels,\n \t\t// where instead of ECONNABORTED error socket\n```

具体的には以下の2点が変更されています。

1.  `import`文に`"runtime"`パッケージが追加されました。
2.  `Accept`関数内の条件分岐が`if len == 0 {`から`if runtime.GOOS == "darwin" && len == 0 {`に変更されました。

## コアとなるコードの解説

### 1. `import "runtime"`

`runtime`パッケージは、Goプログラムが実行されているOSに関する情報(例: `runtime.GOOS`)を提供するために必要です。この変更により、Goのコードが実行されているOSがmacOS(Darwin)であるかどうかを判別できるようになります。

### 2. `if runtime.GOOS == "darwin" && len == 0 {`

この行がこのコミットの主要な変更点です。

*   **`len == 0`**: これは、`Accept`システムコールが返したソケットアドレスの長さが0であることをチェックしています。通常、有効なソケットアドレスであれば長さは0ではありません。
*   **`runtime.GOOS == "darwin"`**: この条件は、現在のOSがmacOS(Darwin)である場合にのみ、続くブロックのコードが実行されるように制限します。

この複合条件により、`len == 0`という異常な状態が**macOS上でのみ**発生した場合に、その後のコメントで説明されているXNUカーネルのバグに対する特別な処理が適用されるようになります。

コメントの内容は以下の通りです。
```go
		// Accepted socket has no address.
		// This is likely due to a bug in xnu kernels,
		// where instead of ECONNABORTED error socket

このコメントは、len == 0という状態が「ソケットアドレスがない」ことを意味し、それがXNUカーネルのバグ(ECONNABORTEDエラーを返す代わりにこの状態になる)に起因する可能性が高いことを示唆しています。この修正により、Goのsyscallパッケージは、この特定のカーネルバグによって引き起こされる予期せぬ動作を適切に処理できるようになり、Goアプリケーションの堅牢性が向上します。

関連リンク

  • Go言語の変更リスト (CL) 6447056: https://golang.org/cl/6447056
  • Go言語の変更リスト (CL) 6456045 (言及されている元の提案): このCLは直接アクセスできませんが、コミットメッセージで参照されています。

参考にした情報源リンク

  • Go言語の公式ドキュメント: syscallパッケージ, runtimeパッケージ
  • XNUカーネルに関する一般的な情報(Apple Developer Documentationなど)
  • ソケットプログラミングに関する一般的な情報(Acceptシステムコール、Sockaddrなど)
  • Go言語のGerritコードレビューシステムに関する情報 (CLの概念など)
  • ECONNABORTEDエラーコードに関する情報
  • Go言語のGitHubリポジトリ: https://github.com/golang/go
  • このコミットのGitHubページ: https://github.com/golang/go/commit/7aa60d998a5f81f58a09e6b1e5703becaf486043