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

[インデックス 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ファイルのパースロジックの改善にあります。

  1. ファイルパスの引数化: parseProcNetIGMPparseProcNetIGMP6関数は、これまでハードコードされたファイルパス(/proc/net/igmp/proc/net/igmp6)を直接開いていました。この変更により、これらの関数はpath引数を受け取るようになり、テスト時に実際の/procファイルではなく、テストデータファイルを使用できるようになりました。これは、パースロジックの単体テストを容易にし、再現性を高める上で非常に重要です。

  2. 堅牢な行パース:

    • getFieldsからsplitAtBytesへの変更: 以前はgetFieldsという内部関数が使用されていましたが、これは単純な空白区切りを前提としており、行のフォーマットが少しでも崩れると正しく動作しない可能性がありました。新しいsplitAtBytes関数は、より柔軟に区切り文字(スペース、コロン、タブ、改行など)を指定できるため、さまざまなフォーマットの行に対応できます。
    • フィールド数のチェック: parseProcNetIGMPでは、パースされたフィールドの数が期待される数(IPv4マルチキャストアドレス行の場合は4、インターフェース名行の場合は5)と異なる場合にpanicする可能性がありました。変更後、len(f) < 4len(f) < 6といったチェックが追加され、フィールド数が不足している場合はその行の処理をスキップするようになりました。これにより、不正なフォーマットの行があってもクラッシュせず、次の行の処理を続行できます。
    • 行の種類の識別: parseProcNetIGMPでは、行の先頭文字がスペースやタブでない場合に新しいインターフェースの行であると判断するロジックが追加されました (l[0] != ' ' && l[0] != '\t')。これにより、インターフェース名とマルチキャストアドレスの行が混在する/proc/net/igmpのフォーマットをより正確に識別できるようになりました。
  3. テストカバレッジの向上: src/pkg/net/interface_linux_test.goという新しいテストファイルが追加されました。このファイルには、TestParseProcNetというテスト関数が含まれており、実際の/proc/net/igmpおよび/proc/net/igmp6ファイルの内容を模倣したtestdata/igmpおよびtestdata/igmp6ファイルを使用して、パースロジックが正しく動作するかどうかを検証します。これにより、将来的なカーネルの変更や予期せぬファイルフォーマットの変更があった場合でも、パースロジックの回帰を防ぐことができます。

  4. バッファサイズの調整: src/pkg/net/parse.goopen関数において、ファイル読み込み用のバッファサイズが1024バイトからos.Getpagesize()(システムのページサイズ、通常4KB)に変更されました。これにより、ファイル読み込みの効率が向上する可能性があります。

これらの変更は、Go言語のnetパッケージがLinuxシステム上でより堅牢に動作し、さまざまな環境や予期せぬ入力に対しても安定したパフォーマンスを提供するように設計されています。

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

このコミットにおける主要なコード変更は以下のファイルに集中しています。

  • src/pkg/net/interface_linux.go: /proc/net/igmpおよび/proc/net/igmp6ファイルのパースロジックが変更されました。
    • parseProcNetIGMPparseProcNetIGMP6関数がpath引数を受け取るように変更。
    • 行のパースにgetFieldsの代わりにsplitAtBytesを使用。
    • パースされたフィールドの数と行のフォーマットに対する堅牢なチェックを追加。
  • src/pkg/net/interface_linux_test.go (新規追加): parseProcNetIGMPparseProcNetIGMP6関数の単体テストが追加されました。
  • 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関数内で、parseProcNetIGMPparseProcNetIGMP6を呼び出す際に、それぞれの/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)
	}
}

このテスト関数は、parseProcNetIGMPparseProcNetIGMP6が、それぞれtestdata/igmptestdata/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()によって取得されるシステムのページサイズに変更されました。これにより、システムのメモリ管理に合わせた効率的なバッファサイズが使用され、パフォーマンスが向上する可能性があります。

関連リンク

参考にした情報源リンク