[インデックス 12148] ファイルの概要
このコミットは、Go言語の標準ライブラリnet
パッケージにおいて、Linuxシステム上の/proc/net/igmp
および/proc/net/igmp6
ファイルからIGMP (Internet Group Management Protocol) および IGMPv6 (Internet Group Management Protocol version 6) のマルチキャストグループ情報をパースする処理の堅牢性を向上させるものです。特に、これらのファイルの内容が予期せぬ形式であった場合でも、パース処理がクラッシュしないように修正が加えられています。
コミット
commit 9765325d4980b15c46b57663bdfd501a75b1f4e6
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Thu Feb 23 06:26:31 2012 +0900
net: make parseProcNetIGMP more robust
Suggested by Paul Borman.
Fixes #2826.
R=rsc, borman
CC=golang-dev
https://golang.org/cl/5689048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9765325d4980b15c46b57663bdfd501a75b1f4e6
元コミット内容
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 21038c629b..15c2f3781b 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -166,13 +166,13 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
return nil, err
}
}\n-\tifmat4 := parseProcNetIGMP(ifi)\n-\tifmat6 := parseProcNetIGMP6(ifi)\n+\tifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)\n+\tifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)\n \treturn append(ifmat4, ifmat6...), nil
}\n \n-func parseProcNetIGMP(ifi *Interface) []Addr {\n-\tfd, err := open("/proc/net/igmp")\n+func parseProcNetIGMP(path string, ifi *Interface) []Addr {\n+\tfd, err := open(path)\n \tif err != nil {\n \t\treturn nil
\t}\n@@ -185,23 +185,26 @@ func parseProcNetIGMP(ifi *Interface) []Addr {\n \tfd.readLine() // skip first line
\tb := make([]byte, IPv4len)
\tfor l, ok := fd.readLine(); ok; l, ok = fd.readLine() {\n-\t\tf := getFields(l)\n-\t\tswitch len(f) {\n-\t\tcase 4:\n+\t\tf := splitAtBytes(l, " :\\r\\t\\n")
+\t\tif len(f) < 4 {\n+\t\t\tcontinue
+\t\t}\n+\t\tswitch {\n+\t\tcase l[0] != ' ' && l[0] != '\t': // new interface line
+\t\t\tname = f[1]
+\t\tcase len(f[0]) == 8:\n \t\t\tif ifi == nil || name == ifi.Name {\n \t\t\t\tfmt.Sscanf(f[0], "%08x", &b)
\t\t\t\tifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
\t\t\t\tifmat = append(ifmat, ifma.toAddr())
\t\t\t}\n-\t\tcase 5:\n-\t\t\tname = f[1]
\t\t}\n \t}\n \treturn ifmat
}\n \n-func parseProcNetIGMP6(ifi *Interface) []Addr {\n-\tfd, err := open("/proc/net/igmp6")\n+func parseProcNetIGMP6(path string, ifi *Interface) []Addr {\n+\tfd, err := open(path)\n \tif err != nil {\n \t\treturn nil
\t}\n@@ -210,7 +213,10 @@ func parseProcNetIGMP6(ifi *Interface) []Addr {\n \tvar ifmat []Addr
\tb := make([]byte, IPv6len)
\tfor l, ok := fd.readLine(); ok; l, ok = fd.readLine() {\n-\t\tf := getFields(l)\n+\t\tf := splitAtBytes(l, " \\r\\t\\n")
+\t\tif len(f) < 6 {\n+\t\t\tcontinue
+\t\t}\n \t\tif ifi == nil || f[1] == ifi.Name {\n \t\t\tfmt.Sscanf(f[2], "%32x", &b)
\t\t\tifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}\ndiff --git a/src/pkg/net/interface_linux_test.go b/src/pkg/net/interface_linux_test.go
new file mode 100644
index 0000000000..f14d1fe06e
--- /dev/null
+++ b/src/pkg/net/interface_linux_test.go
@@ -0,0 +1,54 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import "testing"
+
+const (
+ numOfTestIPv4MCAddrs = 14
+ numOfTestIPv6MCAddrs = 18
+)
+
+var (
+ igmpInterfaceTable = []Interface{
+ {Name: "lo"},
+ {Name: "eth0"}, {Name: "eth1"}, {Name: "eth2"},
+ {Name: "eth0.100"}, {Name: "eth0.101"}, {Name: "eth0.102"}, {Name: "eth0.103"},
+ {Name: "device1tap2"},
+ }
+ igmp6InterfaceTable = []Interface{
+ {Name: "lo"},
+ {Name: "eth0"}, {Name: "eth1"}, {Name: "eth2"},
+ {Name: "eth0.100"}, {Name: "eth0.101"}, {Name: "eth0.102"}, {Name: "eth0.103"},
+ {Name: "device1tap2"},
+ {Name: "pan0"},
+ }
+)
+
+func TestParseProcNet(t *testing.T) {
+ defer func() {
+ if p := recover(); p != nil {
+ t.Fatalf("panicked")
+ }
+ }()
+
+ var ifmat4 []Addr
+ for _, ifi := range igmpInterfaceTable {
+ ifmat := parseProcNetIGMP("testdata/igmp", &ifi)
+ ifmat4 = append(ifmat4, ifmat...)
+ }
+ if len(ifmat4) != numOfTestIPv4MCAddrs {
+ t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
+ }
+
+ var ifmat6 []Addr
+ for _, ifi := range igmp6InterfaceTable {
+ ifmat := parseProcNetIGMP6("testdata/igmp6", &ifi)
+ ifmat6 = append(ifmat6, ifmat...)
+ }
+ if len(ifmat6) != numOfTestIPv6MCAddrs {
+ t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
+ }
+}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
index 4ce01dc906..769414e0ee 100644
--- a/src/pkg/net/interface_test.go
+++ b/src/pkg/net/interface_test.go
@@ -31,17 +31,17 @@ func TestInterfaces(t *testing.T) {
for _, ifi := range ift {
ifxi, err := InterfaceByIndex(ifi.Index)
if err != nil {
-\t\t\tt.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+\t\t\tt.Fatalf("InterfaceByIndex(%q) failed: %v", ifi.Index, err)
}
if !sameInterface(ifxi, &ifi) {
-\t\t\tt.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+\t\t\tt.Fatalf("InterfaceByIndex(%q) = %v, want %v", ifi.Index, *ifxi, ifi)
}
ifxn, err := InterfaceByName(ifi.Name)
if err != nil {
-\t\t\tt.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+\t\t\tt.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err)
}
if !sameInterface(ifxn, &ifi) {
-\t\t\tt.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+\t\t\tt.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, *ifxn, ifi)
}
t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
t.Logf("\thardware address %q", ifi.HardwareAddr.String())
diff --git a/src/pkg/net/parse.go b/src/pkg/net/parse.go
index 4c4200a49b..7c87b42f6d 100644
--- a/src/pkg/net/parse.go
+++ b/src/pkg/net/parse.go
@@ -67,7 +67,7 @@ func open(name string) (*file, error) {
if err != nil {
return nil, err
}
-\treturn &file{fd, make([]byte, 1024)[0:0], false}, nil
+\treturn &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
}
func byteIndex(s string, c byte) int
diff --git a/src/pkg/net/testdata/igmp b/src/pkg/net/testdata/igmp
new file mode 100644
index 0000000000..5f380a2c7d
--- /dev/null
+++ b/src/pkg/net/testdata/igmp
@@ -0,0 +1,24 @@
+Idx Device : Count Querier Group Users Timer Reporter
+1 lo : 1 V3
+ 010000E0 1 0:00000000 0
+2 eth0 : 2 V2
+ FB0000E0 1 0:00000000 1
+ 010000E0 1 0:00000000 0
+3 eth1 : 1 V3
+ 010000E0 1 0:00000000 0
+4 eth2 : 1 V3
+ 010000E0 1 0:00000000 0
+5 eth0.100 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+6 eth0.101 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+7 eth0.102 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+8 eth0.103 : 2 V3
+ FB0000E0 1 0:00000000 0
+ 010000E0 1 0:00000000 0
+9 device1tap2: 1 V3
+ 010000E0 1 0:00000000 0
diff --git a/src/pkg/net/testdata/igmp6 b/src/pkg/net/testdata/igmp6
new file mode 100644
index 0000000000..6cd5a2d4d9
--- /dev/null
+++ b/src/pkg/net/testdata/igmp6
@@ -0,0 +1,18 @@
+1 lo ff020000000000000000000000000001 1 0000000C 0
+2 eth0 ff0200000000000000000001ffac891e 1 00000006 0
+2 eth0 ff020000000000000000000000000001 1 0000000C 0
+3 eth1 ff0200000000000000000001ffac8928 2 00000006 0
+3 eth1 ff020000000000000000000000000001 1 0000000C 0
+4 eth2 ff0200000000000000000001ffac8932 2 00000006 0
+4 eth2 ff020000000000000000000000000001 1 0000000C 0
+5 eth0.100 ff0200000000000000000001ffac891e 1 00000004 0
+5 eth0.100 ff020000000000000000000000000001 1 0000000C 0
+6 pan0 ff020000000000000000000000000001 1 0000000C 0
+7 eth0.101 ff0200000000000000000001ffac891e 1 00000004 0
+7 eth0.101 ff020000000000000000000000000001 1 0000000C 0
+8 eth0.102 ff0200000000000000000001ffac891e 1 00000004 0
+8 eth0.102 ff020000000000000000000000000001 1 0000000C 0
+9 eth0.103 ff0200000000000000000001ffac891e 1 00000004 0
+9 eth0.103 ff020000000000000000000000000001 1 0000000C 0
+10 device1tap2 ff0200000000000000000001ff4cc3a3 1 00000004 0
+10 device1tap2 ff020000000000000000000000000001 1 0000000C 0
変更の背景
このコミットは、Go言語のnet
パッケージがLinuxシステム上でマルチキャストグループ情報を取得する際に使用する/proc/net/igmp
および/proc/net/igmp6
ファイルのパース処理における潜在的な脆弱性に対処するために行われました。具体的には、Go issue #2826で報告された問題に対応しています。
従来のparseProcNetIGMP
およびparseProcNetIGMP6
関数は、これらの/proc
ファイルの内容が特定のフォーマットに従っていることを前提としていました。しかし、これらのファイルはカーネルのバージョンやシステムの設定によってフォーマットが微妙に異なる場合があり、また、予期せぬデータや破損したデータが含まれる可能性もゼロではありませんでした。このような場合、既存のパースロジックではpanic
(Goにおけるランタイムエラー)が発生し、アプリケーションがクラッシュする可能性がありました。
このコミットの目的は、パース処理をより堅牢にし、予期せぬ入力に対しても安全に処理を続行できるようにすることです。これにより、GoアプリケーションがLinuxシステム上でマルチキャストインターフェース情報を取得する際の安定性と信頼性が向上します。
前提知識の解説
/proc
ファイルシステム
Linuxカーネルは、実行中のプロセスやシステムの状態に関する情報を提供する仮想ファイルシステムである/proc
ファイルシステムを公開しています。このファイルシステム内のファイルは、実際のディスク上のファイルではなく、カーネルがメモリ上に動的に生成するデータへのインターフェースです。システム管理者やアプリケーションは、これらのファイルを読み書きすることで、カーネルの内部状態を監視したり、設定を変更したりすることができます。
/proc/net/igmp
と/proc/net/igmp6
/proc/net/igmp
: このファイルは、IPv4マルチキャストグループのメンバーシップに関する情報を提供します。システム上の各ネットワークインターフェースが参加しているIPv4マルチキャストグループのアドレスや、関連する統計情報などが含まれます。/proc/net/igmp6
: 同様に、このファイルはIPv6マルチキャストグループのメンバーシップに関する情報を提供します。IPv6マルチキャストアドレスは、IPv4とは異なる形式を持ちます。
これらのファイルの内容は、通常、以下のような形式で表示されます(正確なフォーマットはカーネルバージョンによって異なる場合があります)。
/proc/net/igmp
の例:
Idx Device : Count Querier Group Users Timer Reporter
1 lo : 1 V3
010000E0 1 0:00000000 0
2 eth0 : 2 V2
FB0000E0 1 0:00000000 1
010000E0 1 0:00000000 0
このフォーマットでは、インターフェース名(例: lo
, eth0
)の行と、そのインターフェースが参加しているマルチキャストグループのアドレス(例: 010000E0
)の行が混在しています。マルチキャストグループのアドレスは16進数で表現され、リトルエンディアン形式で格納されていることが多いです。
/proc/net/igmp6
の例:
1 lo ff020000000000000000000000000001 1 0000000C 0
2 eth0 ff0200000000000000000001ffac891e 1 00000006 0
こちらはよりシンプルな行ベースのフォーマットで、インターフェース名とIPv6マルチキャストアドレスが直接関連付けられています。
IGMP (Internet Group Management Protocol)
IGMPは、IPv4ネットワーク上でホストがマルチキャストグループのメンバーシップをルーターに通知するために使用される通信プロトコルです。マルチキャスト通信では、単一の送信元から複数の受信者に対してデータを効率的に送信できます。IGMPは、ルーターがどのホストがどのマルチキャストグループに関心があるかを把握し、不要なマルチキャストトラフィックをネットワーク全体に転送しないようにするために不可欠です。
Go言語のnet
パッケージ
Go言語の標準ライブラリであるnet
パッケージは、ネットワークI/Oのプリミティブを提供します。これには、TCP/IP、UDP、IP、Unixドメインソケットなどのネットワークプロトコルを扱うための機能が含まれます。このパッケージは、ネットワークインターフェースの情報を取得したり、IPアドレスを解決したり、ネットワーク接続を確立したりするためのAPIを提供します。
技術的詳細
このコミットの主要な技術的変更点は、/proc/net/igmp
および/proc/net/igmp6
ファイルのパースロジックの改善にあります。
-
ファイルパスの引数化:
parseProcNetIGMP
とparseProcNetIGMP6
関数は、これまでハードコードされたファイルパス(/proc/net/igmp
と/proc/net/igmp6
)を直接開いていました。この変更により、これらの関数はpath
引数を受け取るようになり、テスト時に実際の/proc
ファイルではなく、テストデータファイルを使用できるようになりました。これは、パースロジックの単体テストを容易にし、再現性を高める上で非常に重要です。 -
堅牢な行パース:
getFields
からsplitAtBytes
への変更: 以前はgetFields
という内部関数が使用されていましたが、これは単純な空白区切りを前提としており、行のフォーマットが少しでも崩れると正しく動作しない可能性がありました。新しいsplitAtBytes
関数は、より柔軟に区切り文字(スペース、コロン、タブ、改行など)を指定できるため、さまざまなフォーマットの行に対応できます。- フィールド数のチェック:
parseProcNetIGMP
では、パースされたフィールドの数が期待される数(IPv4マルチキャストアドレス行の場合は4、インターフェース名行の場合は5)と異なる場合にpanic
する可能性がありました。変更後、len(f) < 4
やlen(f) < 6
といったチェックが追加され、フィールド数が不足している場合はその行の処理をスキップするようになりました。これにより、不正なフォーマットの行があってもクラッシュせず、次の行の処理を続行できます。 - 行の種類の識別:
parseProcNetIGMP
では、行の先頭文字がスペースやタブでない場合に新しいインターフェースの行であると判断するロジックが追加されました (l[0] != ' ' && l[0] != '\t'
)。これにより、インターフェース名とマルチキャストアドレスの行が混在する/proc/net/igmp
のフォーマットをより正確に識別できるようになりました。
-
テストカバレッジの向上:
src/pkg/net/interface_linux_test.go
という新しいテストファイルが追加されました。このファイルには、TestParseProcNet
というテスト関数が含まれており、実際の/proc/net/igmp
および/proc/net/igmp6
ファイルの内容を模倣したtestdata/igmp
およびtestdata/igmp6
ファイルを使用して、パースロジックが正しく動作するかどうかを検証します。これにより、将来的なカーネルの変更や予期せぬファイルフォーマットの変更があった場合でも、パースロジックの回帰を防ぐことができます。 -
バッファサイズの調整:
src/pkg/net/parse.go
のopen
関数において、ファイル読み込み用のバッファサイズが1024
バイトからos.Getpagesize()
(システムのページサイズ、通常4KB)に変更されました。これにより、ファイル読み込みの効率が向上する可能性があります。
これらの変更は、Go言語のnet
パッケージがLinuxシステム上でより堅牢に動作し、さまざまな環境や予期せぬ入力に対しても安定したパフォーマンスを提供するように設計されています。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
src/pkg/net/interface_linux.go
:/proc/net/igmp
および/proc/net/igmp6
ファイルのパースロジックが変更されました。parseProcNetIGMP
とparseProcNetIGMP6
関数がpath
引数を受け取るように変更。- 行のパースに
getFields
の代わりにsplitAtBytes
を使用。 - パースされたフィールドの数と行のフォーマットに対する堅牢なチェックを追加。
src/pkg/net/interface_linux_test.go
(新規追加):parseProcNetIGMP
とparseProcNetIGMP6
関数の単体テストが追加されました。src/pkg/net/testdata/igmp
(新規追加):parseProcNetIGMP
のテストに使用されるIPv4 IGMPデータのサンプル。src/pkg/net/testdata/igmp6
(新規追加):parseProcNetIGMP6
のテストに使用されるIPv6 IGMPデータのサンプル。src/pkg/net/parse.go
:open
関数におけるファイル読み込みバッファの初期化サイズが変更されました。src/pkg/net/interface_test.go
: テストメッセージのフォーマットが%#q
から%q
に変更されました。これは機能的な変更ではなく、テスト出力の改善です。
コアとなるコードの解説
src/pkg/net/interface_linux.go
の変更
// interfaceMulticastAddrTable 関数内の変更
- ifmat4 := parseProcNetIGMP(ifi)
- ifmat6 := parseProcNetIGMP6(ifi)
+ ifmat4 := parseProcNetIGMP("/proc/net/igmp", ifi)
+ ifmat6 := parseProcNetIGMP6("/proc/net/igmp6", ifi)
interfaceMulticastAddrTable
関数内で、parseProcNetIGMP
とparseProcNetIGMP6
を呼び出す際に、それぞれの/proc
ファイルのパスを明示的に渡すようになりました。これにより、これらのパース関数がより汎用的に、かつテスト可能になりました。
// parseProcNetIGMP 関数のシグネチャ変更
-func parseProcNetIGMP(ifi *Interface) []Addr {
- fd, err := open("/proc/net/igmp")
+func parseProcNetIGMP(path string, ifi *Interface) []Addr {
+ fd, err := open(path)
parseProcNetIGMP
関数は、ifi *Interface
に加えてpath string
引数を受け取るようになりました。これにより、テスト時に/proc/net/igmp
の代わりにテスト用のファイルパスを指定できるようになります。parseProcNetIGMP6
も同様に変更されています。
// parseProcNetIGMP 関数のパースロジック変更
b := make([]byte, IPv4len)
for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
- f := getFields(l)
- switch len(f) {
- case 4:
+ f := splitAtBytes(l, " :\\r\\t\\n") // 新しい分割関数
+ if len(f) < 4 { // フィールド数のチェック
+ continue // 不足している場合はスキップ
+ }
+ switch {
+ case l[0] != ' ' && l[0] != '\t': // 新しいインターフェース行の識別
+ name = f[1]
+ case len(f[0]) == 8: // マルチキャストアドレス行の識別 (8文字の16進数)
if ifi == nil || name == ifi.Name {
fmt.Sscanf(f[0], "%08x", &b)
ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
ifmat = append(ifmat, ifma.toAddr())
}
- case 5:
- name = f[1]
}
}
この部分が最も重要な変更です。
getFields(l)
がsplitAtBytes(l, " :\\r\\t\\n")
に置き換えられました。splitAtBytes
は、指定された複数の区切り文字(スペース、コロン、キャリッジリターン、タブ、改行)で行を分割します。これにより、/proc/net/igmp
の多様なフォーマットに対応できるようになります。if len(f) < 4 { continue }
というチェックが追加され、パースされたフィールドが4つ未満の場合(つまり、期待されるデータが不足している場合)は、その行をスキップして次の行に進むようになりました。これにより、不正なフォーマットの行があってもpanic
することなく処理を続行できます。switch
文の条件がlen(f)
から行の内容に基づくものに変更されました。l[0] != ' ' && l[0] != '\t'
は、行の先頭がスペースやタブでない場合に、それが新しいインターフェースの定義行であると判断します。/proc/net/igmp
のフォーマットでは、インターフェースの行は左端から始まり、マルチキャストアドレスの行はインデントされています。len(f[0]) == 8
は、最初のフィールドが8文字の場合に、それがIPv4マルチキャストアドレスの行であると判断します。
parseProcNetIGMP6
も同様に、splitAtBytes
の使用とif len(f) < 6 { continue }
というフィールド数チェックが追加されています。
src/pkg/net/interface_linux_test.go
(新規追加)
func TestParseProcNet(t *testing.T) {
defer func() {
if p := recover(); p != nil {
t.Fatalf("panicked")
}
}()
// IPv4 IGMP のテスト
var ifmat4 []Addr
for _, ifi := range igmpInterfaceTable {
ifmat := parseProcNetIGMP("testdata/igmp", &ifi) // テストデータファイルを使用
ifmat4 = append(ifmat4, ifmat...)
}
if len(ifmat4) != numOfTestIPv4MCAddrs {
t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
}
// IPv6 IGMP のテスト
var ifmat6 []Addr
for _, ifi := range igmp6InterfaceTable {
ifmat := parseProcNetIGMP6("testdata/igmp6", &ifi) // テストデータファイルを使用
ifmat6 = append(ifmat6, ifmat...)
}
if len(ifmat6) != numOfTestIPv6MCAddrs {
t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
}
}
このテスト関数は、parseProcNetIGMP
とparseProcNetIGMP6
が、それぞれtestdata/igmp
とtestdata/igmp6
というテストデータファイルを使って正しくマルチキャストアドレスをパースできるかを検証します。defer func() { if p := recover(); p != nil { t.Fatalf("panicked") } }()
というrecover
ブロックは、パース処理中にpanic
が発生しないことを保証するためのものです。これにより、堅牢性向上の目的が達成されているかを確認できます。
src/pkg/net/parse.go
の変更
// open 関数内の変更
- return &file{fd, make([]byte, 1024)[0:0], false}, nil
+ return &file{fd, make([]byte, os.Getpagesize())[0:0], false}, nil
ファイル読み込みに使用される内部バッファのサイズが、固定の1024
バイトからos.Getpagesize()
によって取得されるシステムのページサイズに変更されました。これにより、システムのメモリ管理に合わせた効率的なバッファサイズが使用され、パフォーマンスが向上する可能性があります。
関連リンク
- Go Issue 2826: https://code.google.com/p/go/issues/detail?id=2826 (古いGoogle Codeのリンクですが、当時のIssueトラッカーです)
- Go CL 5689048: https://golang.org/cl/5689048 (このコミットに対応するGoの変更リスト)
参考にした情報源リンク
- Linux
proc
ファイルシステムに関するドキュメント (例:man proc
) - IGMP (Internet Group Management Protocol) のRFC (例: RFC 2236, RFC 3376)
- Go言語の
net
パッケージのドキュメント: https://pkg.go.dev/net - Go言語のテストに関するドキュメント: https://go.dev/blog/testing
- Go言語の
panic
とrecover
に関するドキュメント: https://go.dev/blog/defer-panic-and-recover