Go の気になったコミット (2022 年 4 月)

[golang/go](https://github.com/golang/go) の master ブランチに行われたコミットから個人的に気になったものをリストにしたものです。

前回作成したリストはこちら。

https://qiita.com/sg0hsmt/items/d74d96095b83f15746de

軽く説明を追加していますが勘違いや誤りがあるかもしれません。

## Topic

## Commits

### 2022-04-01

https://github.com/golang/go/commit/37065847d87df92b5eb246c88ba2085efcf0b331

楕円曲線暗号で使用する P-256 の処理で panic を起こす問題が修正されています。 [^1] [^2]
この修正はバックポートされており Go 1.17.9 および Go 1.18.1 がリリース済みです。

[^1]: https://github.com/golang/go/issues/52075
[^2]: https://github.com/advisories/GHSA-v5qw-m6mv-3q79

https://github.com/golang/go/commit/9743fdd097171cada6231503974209edc5400ee8

Go では OS やアーキテクチャに固有の処理がある場合はファイル名を使用して GOOS や GOARCH を指定することが一般的です。
ソースディレクトリで使用されているタグは [`build.Package`](https://pkg.go.dev/go/build#Package) の `AllTags` で調べられますが GOOS と GOARCH が両方指定されており実行環境と GOARCH が一致する場合に GOOS が含まれない問題が修正されています。 [^3]

[^3]: https://github.com/golang/go/issues/52053

https://github.com/golang/go/commit/12acf9b0f009305eefc71d4cee8808cc244e86aa

連続したメモリをゼロクリアするためのランタイム関数 `memclrNoHeapPointers()` が AVX2 が利用できる場合 (GOAMD64 が 3 以上の場合) に最適化されています。

https://github.com/golang/go/commit/3334afd7609185574ad179cb030064f0825c2101

Go 1.18 で新しい GC Pacer が導入されたため古いコードが削除されています。

https://github.com/golang/go/commit/31ee4bb28dff98f29654e7f1b43488641b3157db

ユニコードの `U+007F` を [`strconv.Quote()`](https://pkg.go.dev/strconv#Quote) に渡した際に制御文字 (DELETE) としてエスケープされていなかった問題が修正されています。 [^4]

[^4]: https://github.com/golang/go/issues/52062

https://github.com/golang/go/commit/a84ef500213ef6c2a0e4bfd82253e9fcd28f1f62

Go 1.18 で導入された go work use にディレクトリではなくファイル名を渡すと panic になる問題が修正されています。 [^5]

[^5]: https://github.com/golang/go/issues/51749

https://github.com/golang/go/commit/a41763539c7ad09a22720a517a28e6018ca4db0f

HTTP レスポンスがステータス 301 かつ Location ヘッダーがない場合にレスポンスの内容を取得できない問題が修正されています。 [^6]
一般的にステータス 301 は Location ヘッダーとセットのことが多い (RFC 7231 では SHOULD) ですが Location ヘッダーを設定しないサーバー (Amazon S3) が存在するため対応したようです。

[^6]: https://github.com/golang/go/issues/49281

https://github.com/golang/go/commit/26ab2159694b19ef5feb56f4fe7a9cd18360dcdd

https://github.com/golang/go/commit/62d4c32b7e5c1f5954c97c264d1105fc3743220e

arm64 向けに命令のサポートが追加されています。
gVisor に必要だからというのがその理由みたいです。

### 2022-04-02

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

https://github.com/golang/go/commit/89dff118ada91061350aa149b54a2ab4fdbd6810

https://github.com/golang/go/commit/690ac4071fa3e07113bf371c9e74394ab54d6749

Go doc のフォーマット変更に向けた作業の一部です。 [^7]
Go 1.19 では gofmt がドキュメントコメントもサポートするほか、構文を解析するパッケージが追加されます。

[^7]: https://github.com/golang/go/issues/51082

https://github.com/golang/go/commit/8a816d5efcc842ae92f0193aa9c1d433bd66ef31

Go 1.13 未満の環境で型指定されていないシフト演算を警告する不具合が修正されています。 [^8]
Go 1.18 でビルドされた gopls を使用して Go 1.11 のコードを修正するようなケースで遭遇する問題です。

[^8]: https://github.com/golang/go/issues/52031

### 2022-04-04

https://github.com/golang/go/commit/85b5f86584686677c554b2538a7edee96d684aea

net でキャンセルまたはタイムアウトが発生した際のエラーを `errors.Is(err, context.Canceled)` または `errors.Is(err, context.DeadlineExceeded)` で判定できるようになりました。従来からある [`net.Error`](https://pkg.go.dev/net#Error) との互換性も問題ありません。 [^9]

[^9]: https://github.com/golang/go/issues/51428

https://github.com/golang/go/commit/345184496ce358e663b0150f679d5e5cf1337b41

Windows でも [`os.Interrupt`](https://pkg.go.dev/os#Signal) をハンドリングするための修正が行われています。
残念ながらこの修正は後日 revert されてしまいました。 [^10]

[^10]: https://github.com/golang/go/commit/f86f9a3038eb6db513a0ea36bc2af7a13b005e99

https://github.com/golang/go/commit/492c85ab84dc1d4d19be0466d2d73f4a6174f07e

Go 1.18 で導入された go work use -r に存在しないディレクトリ名を渡すと panic になる問題が修正されています。 [^11]

[^11]: https://github.com/golang/go/issues/51841

https://github.com/golang/go/commit/1af60b2f4990bffdd1b050ffd11e978578d1e38f

ネストされた正規表現が深さ制限 (1000) を超えた際のエラーとして `ErrInvalidDepth` が新しく定義されました。 [^12]
深さ制限チェックの追加は Go 1.18 リリース前に行われており Go 1.16, Go 1.17 にもバックポートされています。 [^13]
ただし、この時点では既存のエラーを使う形になっていました。

なお `ErrInvalidDepth` は別のコミットによって `ErrNestingDepth` にリネームされています。 [^14] [^15]
元の提案では `ErrNestingDepth` だったのが何故か `ErrInvalidDepth` で反映されていたらしいです。

[^12]: https://github.com/golang/go/issues/51684
[^13]: https://github.com/golang/go/issues/51112
[^14]: https://github.com/golang/go/commit/575fd8817ae9817303a69065def80c574718169e
[^15]: https://github.com/golang/go/commit/0bf545e51f5303ddedb0ea60f02ff221ac088fc7

### 2022-04-05

https://github.com/golang/go/commit/35998c010947d3a5a26409fffcb4ed16c3595850

Go 1.18 から SHA-1 形式で署名された証明書の検証が無効化されました。 [^16]
しかし、 OCSP 応答または CRL についても無効化され WebPKI との互換性に問題が出たため証明書のみを対象とするように修正されました。 [^17]
この修正は Go 1.18.1 にもバックポートされています。

[^16]: https://tip.golang.org/doc/go1.18#sha1
[^17]: https://github.com/golang/go/issues/41682#issuecomment-1072695832

https://github.com/golang/go/commit/ac313524fe4997b80a4221647f0da79d0e07b88e

`reflect.Type.NumMethod()` および `reflect.Value.NumMethod()` のコメントが修正されています。
interface に対して使った場合にドキュメントと実際の動作が異なる問題がありましたが、ドキュメントを修正する対応がとられています。
本来は不具合として Go 1.16 で修正予定でしたが互換性問題があったため取りやめとなった経緯があるようです。

https://github.com/golang/go/commit/c58f1bb65f2187d79a5842bb19f4db4cafd22794

[`text/template`](https://pkg.go.dev/text/template) で comparable ではない値 (マップやスライス) と nil の比較が可能になりました。 [^18]

[^18]: https://github.com/golang/go/issues/51642

https://github.com/golang/go/commit/1a955bcdb701d788b048a39d7273621729e257bc

同じサイズの配列 (スライスではない) を比較する際のコード生成に対してアンロールによる最適化が行われています。

### 2022-04-06

https://github.com/golang/go/commit/65153e478e302eaf3556372ff257ebfc893943c1

証明書の検証処理が修正されています。 [^19] [^20]

[^19]: https://github.com/golang/go/issues/48869
[^20]: https://github.com/golang/go/issues/45856

https://github.com/golang/go/commit/9e16cc1541d42cb081d359339e3f45b4b9b2a372

[`hash/maphash`](https://pkg.go.dev/hash/maphash) のオーバーヘッドが大きいため文字列やバイト列から直接ハッシュ値を取得する関数が追加されています。 [^21]

[^21]: https://github.com/golang/go/issues/42710

### 2022-04-07

https://github.com/golang/go/commit/81ae993e54547415ba674082801b05961e3f2aa3

NetBSD 環境でのテストで特定のエラーを無視する修正が行われています。 [^22]
Go 本体のテストなので実装への影響はありません。

[^22]: https://github.com/golang/go/issues/52168

https://github.com/golang/go/commit/d3362fc1242f20c40f6d3986ddf4398019c8ea26

riscv64 でレジスタベースの関数呼び出し規約が有効化されました。
amd64, arm64, ppc64 に続くアーキテクチャになります。
(デフォルト有効化はこのコミットではなく別コミットで行われていました)

https://github.com/golang/go/commit/063f4032f5ea8820d265ee1196ef9b8eba02c63f

[`sort`](https://pkg.go.dev/sort) パッケージにバイナリサーチ用の関数として `Find()` が追加されました。 [^23]
すでに [`sort.Search()`](https://pkg.go.dev/sort#Search) が存在するのですが比較関数の型が変更されたほか、一致する項目があったかどうかも返すようになっています。

[^23]: https://github.com/golang/go/issues/50340

### 2022-04-12

https://github.com/golang/go/commit/494b79f39ab8e7b6f096b6c6088bd84bb8592dc4

`doc/comment` パッケージが追加されています。 [^24]
記載は省略していますが多数の変更が行われています。

[^24]: https://github.com/golang/go/issues/51082

https://github.com/golang/go/commit/ca7c6ef33d9eca2dbc7eb46601a051dc7dc4e411

クローズされたチャンネルに対する受信処理の性能が改善されています。 [^25]

[^25]: https://github.com/golang/go/issues/52067

### 2022-04-13

https://github.com/golang/go/commit/45c3387d777caf28f4b992ad9a6216e3085bb8fe

エラーを含む大きな PEM ファイルを与えられた場合に発生するスタックオーバーフローが修正されています。 [^26] [^27]
この修正はバックポートされており Go 1.17.9 および Go 1.18.1 がリリース済みです。

[^26]: https://github.com/golang/go/issues/51853
[^27]: https://github.com/advisories/GHSA-q42m-q8hq-53rj

https://github.com/golang/go/commit/5bf6c97e76c721242a9b064950cd901c33f6f0b9

Go 1.16 で追加された [`embed`](https://pkg.go.dev/embed) で埋め込もうとしているディレクトリがルートにあると動かない不具合が修正されています。 [^28]
Dockerfile でビルドしようとした場合に遭遇しやすいようです。

[^28]: https://github.com/golang/go/issues/49570

https://github.com/golang/go/commit/4569fe64101c2209e3429bd1c953b5f4021fc43d

Go 1.18 で追加された `buildvcs` オプションに auto が追加され、デフォルトも auto に変更されました。
従来のデフォルト有効 (true) でしたが VCS のディレクトリが存在するもののツールが利用できない場合にビルド失敗する問題が起きていたようです。 [^29]

[^29]: https://github.com/golang/go/issues/51748

### 2022-04-14

https://github.com/golang/go/commit/72e77a7f41bbf45d466119444307fd3ae996e257

[`sort`](https://pkg.go.dev/sort) パッケージのソート処理が quicksort から pdqsort (Pattern-defeating quicksort) ベースの実装に変更されています。 [^30]
多くのケース (特にソート済みスライス) で従来より高速化されるようです。

[^30]: https://github.com/golang/go/issues/50154

### 2022-04-15

https://github.com/golang/go/commit/1ba96d8c0909eca59e28c048150c3834982f79fb

https://github.com/golang/go/commit/3d8cb26504f9e3f5b45b4ea97b55714a25e016c1

https://github.com/golang/go/commit/c4b2288755d07b9505ef498819bb540b7b0fa215

https://github.com/golang/go/commit/78bea702cd38ac5004a97f110e7f659336a04d57

switch をバイナリサーチではなくジャンプテーブルで実装するための修正です。
常にジャンプテーブルが使われるわけではなく、利用可能なアーキテクチャにも制限があるようです。

https://github.com/golang/go/commit/01b9ae22ed3c0f9c9ea29adbcd23bd97de6d18dd

定数などコンパイル時に決まる switch case の処理が改善されています。 [^31]
`runtime.GOOS` などが多いようです。

[^31]: https://github.com/golang/go/issues/50253

https://github.com/golang/go/commit/35a92f92bd0ce15c658dd6794238ca90b71e4422

byte スライスに Varint エンコードされた値を append する関数が追加されています。 [^32]
Varint エンコードは protobuf で使われている形式で protobuf にも同様の (しかし少し最適化された) 関数が実装されているようです。 [^33]

[^32]: https://github.com/golang/go/issues/51644
[^33]: https://pkg.go.dev/google.golang.org/protobuf/encoding/protowire

### 2022-04-16

https://github.com/golang/go/commit/2c73f5f32fceb31b5da7f9a820c0c637f57a9ab5

[`http.Request.WithContext()`](https://pkg.go.dev/net/http#Request.WithContext) で行われていた不要なデータコピーが削除されています。 [^34]

[^34]: https://github.com/golang/go/issues/52239

https://github.com/golang/go/commit/ac01de5446ec92544768dabee3b0d1faf5f596d9

[`http.StatusText()`](https://pkg.go.dev/net/http#StatusText) の実装が map から switch case に変更されています。
これによりコンパイル時の最適化が期待できるそうです。

https://github.com/golang/go/commit/e3982660a73b04a87c08215cb5aaa16d816ea573

macOS 環境でまれにデッドロックする問題が修正されています。 [^35]
goroutine のプリエンプションとシグナル処理の組み合わせに問題があったらしく Go 1.17 および Go 1.18 にもバックポートされています。

[^35]: https://github.com/golang/go/issues/52226

### 2022-04-17

https://github.com/golang/go/commit/e948c3394ee137bae45e85cfa7c8ec0bb0e16dc8

[`reflect.Value.Type()`](https://pkg.go.dev/reflect#Value.Type) がインライン化できるようになりました。
常にインライン化の恩恵を受けられるわけではないようですが地味に効果がありそうです。

### 2022-04-20

https://github.com/golang/go/commit/d68a8d0f27bb3599b49cacd119d7ac3202248050

https://github.com/golang/go/commit/3ae414c31e59c9ee210fa3606f36cf0ea36b9906

[`crypto/rand`](https://pkg.go.dev/crypto/rand) で行っている乱数生成器からの読み込み処理がプラットフォームごとにバラバラだったのを統一したうえでバッファリングしないように修正されています。
従来は [`bufio`](https://pkg.go.dev/bufio) で 4096 BYTE バッファしていたのがその都度取得するようになり、より新鮮な値を取得できるようになっただけでなく複数コアで取得する場合の性能向上が期待できるようです。

### 2022-04-21

https://github.com/golang/go/commit/ebe1435fbb50bb82bfca53063e8daba4f870ec8d

runtime にランダムな uint64 を取得する `fastrand64()` が追加されています。
通常のプログラムからは利用できませんが標準ライブラリの一部から利用しているようです。 [^36] [^37] [^38]

[^36]: https://github.com/golang/go/commit/c2d436dcfad64d5cc301cf05d446f7a93c19133e
[^37]: https://github.com/golang/go/commit/01b8f5e8821eac0e3456d6200b351629fd3752f4
[^38]: https://github.com/golang/go/commit/a4bbcd4b1fc9dd40e0f86416d37bdd9e6d430f3f

### 2022-04-22

https://github.com/golang/go/commit/b34838913da606087b0f3141891f7d0fb2254eef

POSIX プラットフォームにて [`exec.Cmd`](https://pkg.go.dev/os/exec#Cmd) の Dir が空ではなく Env が nil の場合、子プロセスに Dir が環境変数 `PWD` として渡されるようになりました。 [^39]
また、 `exec.Cmd.Environ()` が追加されておりコマンドに渡される環境変数を取得できるようになりました。

[^39]: https://github.com/golang/go/issues/50599

https://github.com/golang/go/commit/21e1ffe7bc7793a8f1c1fca4dfa32f1f3f70681c

[`bufio.Writer.WriteString()`](https://pkg.go.dev/bufio#Writer.WriteString) でバッファサイズを超えた文字列を書き込む場合に writer が `WriteString()` をサポートしていればバッファを介さず書き込むことで不要なコピーを削減しています。
`[]byte` を書き込む `Write()` は以前からそのようになっていたようです。

https://github.com/golang/go/commit/3c29aca43630da1604c3378d2351050f23655268

構造体および配列の比較コードを生成する処理がリファクタリングされています。 [^40]

[^40]: https://github.com/golang/go/issues/38674

https://github.com/golang/go/commit/67d6be139c77b63395d8c1fa29cdae8d34635f3e

[`reflect.Value`](https://pkg.go.dev/reflect#Value) にあるいくつかのメソッドがインライン化できるようになりました。
map や配列の長さ取得では若干の速度低下があるようですがそれ以外のケースでは高速化されており encoding/json にも影響が出ているようです。

### 2022-04-26

https://github.com/golang/go/commit/a5d61be040ed20b5774bff1b6b578c6d393ab332

[`http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader) が返すエラーとして `http.MaxBytesError` が定義されました。 [^41]
これによりエラーの理由をチェックできるようになります。

[^41]: https://github.com/golang/go/issues/30715

### 2022-04-27

https://github.com/golang/go/commit/e1b5f347e78c733bb0743df04c990e20f74bf188

https://github.com/golang/go/commit/d8cf2243e0ed1c498ed405432c10f9596815a582

定期的に (現在は 2 分に 1 回) に起動される GC で使われている idle mark worker の数が最大 1 個 (GC worker が既にある場合は 0 個) に制限されました。 [^42] [^43]
これによって GC がほとんど起動していない Go プログラムの CPU 使用率が急激に上昇するといった問題が回避できるようです。

[^42]: https://github.com/golang/go/issues/44163
[^43]: https://github.com/golang/go/issues/37116

https://github.com/golang/go/commit/13b18ec947c9589b47f058d7e7b95e60fcdb3fc9

GC の goroutine をどのスレッドで動かすかの判定処理 (スケジューリング) が改善されています。 [^44] [^45]
以前は停止したスレッドに割り当ててしまうことによる問題があったようです。

[^44]: https://github.com/golang/go/issues/39004
[^45]: https://github.com/golang/go/issues/44313

### 2022-04-29

https://github.com/golang/go/commit/4bb45f7549548add8222aa4f3040d0e2120691a9

https://github.com/golang/go/commit/29bbca5c2c1ad41b2a9747890d183b6dd3a4ace4

https://github.com/golang/go/commit/4289bd365c38a44db091396873050cab3cfa8098

Go ランタイムで発生する例外についてユーザーコードが原因と思われるものとそれ以外を分けたようです。 [^46]
これによって問題の切り分けがしやすくなることを期待しているようです。

[^46]: https://github.com/golang/go/issues/51485

### 2022-04-30

https://github.com/golang/go/commit/11a650bb4aabfd7998b61df3ac33f61831d7abff

Go 1.18 にて map の key に string をベースとした Defined type を使用している場合、 [`reflect.Value.SetMapIndex()`](https://pkg.go.dev/reflect#Value.SetMapIndex) および [`reflect.Value.MapIndex()`](https://pkg.go.dev/reflect#Value.MapIndex) が通常の string でも成功する問題が修正されています。 [^47]
この問題は Go 1.18 からの不具合でバックポートが用意されています。

[^47]: https://github.com/golang/go/issues/52379

## 雑感

Go 1.18 リリースが遅れたせいか 4 月はコミットが多かったです。
4 月時点では完了していないので記載していませんが Go 1.19 には次の変更も入りそうです。

- 新しいアーキテクチャ linux/loong64 が利用可能になりそうです。 [^48]
- BoringCrypto を使うための `dev.boringcrypto` ブランチを master にマージしようとしているようです。 [^49]

[^48]: https://github.com/golang/go/issues/46229
[^49]: https://github.com/golang/go/issues/51940

また、 Go 開発者の方が Go 1.19 で追加される機能についてツイートしていましたのでご紹介します。
コミットを追いかけていたつもりですが見落としているものも多数ありました。

https://threadreaderapp.com/thread/1522271576904937477.html