[インデックス 1649] ファイルの概要
このコミットは、Go言語の初期段階におけるsyscall.Getdirentries関数の引数型に関するバグ修正です。具体的には、len(buf)の戻り値の型がintであるのに対し、syscall.Getdirentriesが期待するサイズ引数の型がint64であったために発生したビルドエラーを修正しています。
コミット
commit c8d59c1fb24cd5efd495ec8142aa69270ddba8d2
Author: Rob Pike <r@golang.org>
Date: Mon Feb 9 10:20:15 2009 -0800
fix int64/int error - build broken
R=gri
OCL=24678
CL=24678
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c8d59c1fb24cd5efd495ec8142aa69270ddba8d2
元コミット内容
fix int64/int error - build broken
このコミットメッセージは非常に簡潔で、「int64とintの型エラーを修正 - ビルドが壊れていた」と述べています。これは、型不一致が原因でGoのビルドプロセスが失敗していたことを示唆しています。
変更の背景
このコミットは、Go言語の非常に初期の段階(2009年2月)に行われたものです。当時のGoはまだ開発途上にあり、APIの設計や型システムが固まりきっていない時期でした。特に、システムコールをラップするsyscallパッケージは、OS固有のAPIとGoの型システムとの間のブリッジとして機能するため、このような型不一致の問題が発生しやすい箇所でした。
syscall.Getdirentriesは、ディレクトリのエントリを読み取るためのシステムコールをGoから呼び出すためのラッパー関数です。この関数は、読み取るバッファのサイズを引数として受け取りますが、OSのシステムコールが期待するサイズ引数の型と、Goのlen()関数が返す型との間に不一致があったと考えられます。
具体的には、len()関数はGoのスライスや配列の長さをint型で返しますが、syscall.Getdirentriesが内部的に呼び出すOSのシステムコール(この場合はDarwin/macOSのgetdirentries)は、サイズ引数として64ビット整数(C言語のsize_tやssize_tに相当し、Goではint64で表現されることが多い)を期待していた可能性があります。この型不一致が原因で、コンパイルエラーやランタイムエラーが発生し、Goのビルドが中断されていたと推測されます。
前提知識の解説
Go言語の型システム
Go言語は静的型付け言語であり、変数の型はコンパイル時に決定されます。Goにはint、int8、int16、int32、int64などの整数型があります。int型は、実行環境のCPUアーキテクチャに依存するサイズ(32ビットまたは64ビット)を持ちます。一方、int64は常に64ビットの整数を表します。
Goの組み込み関数であるlen()は、スライス、配列、文字列、マップ、チャネルなどの長さを返します。このlen()関数の戻り値の型は常にintです。
システムコールとsyscallパッケージ
システムコールは、ユーザー空間のプログラムがオペレーティングシステム(OS)のカーネルが提供するサービス(ファイルI/O、メモリ管理、プロセス制御など)を利用するためのインターフェースです。Go言語では、syscallパッケージがOSのシステムコールへの低レベルなアクセスを提供します。
syscallパッケージ内の関数は、OSのC言語APIに対応する形で定義されていることが多く、引数の型や戻り値の型はOSのAPIの仕様に厳密に従う必要があります。C言語のsize_tやssize_tのような型は、Goでは通常uintptrやint64などの型にマッピングされます。
getdirentriesシステムコール (Darwin/macOS)
getdirentriesは、Unix系OS(特にBSD系、macOSを含む)で利用されるシステムコールの一つで、ディレクトリの内容を読み取るために使用されます。このシステムコールは、ファイルディスクリプタ、バッファ、バッファサイズ、およびオフセットを引数として受け取ります。バッファサイズは、通常、符号なし整数型(size_t)または符号付き整数型(ssize_t)で指定されます。64ビットシステムでは、これらの型は64ビット幅を持つことが一般的です。
技術的詳細
このコミットの技術的な核心は、Goのint型とOSのシステムコールが期待する64ビット整数型との間の不一致を解決することにあります。
変更が行われたファイルはsrc/lib/os/dir_amd64_darwin.goです。これは、Goのosパッケージの一部で、amd64アーキテクチャ上のDarwin(macOS)システムにおけるディレクトリ操作(特にディレクトリ内のエントリを読み取る機能)を実装しています。
問題の箇所は、Readdirnames関数内でsyscall.Getdirentriesを呼び出している部分です。
元のコード:
ret, err2 := syscall.Getdirentries(fd.fd, &buf[0], len(buf), &base);
ここで、len(buf)はint型を返します。しかし、syscall.Getdirentriesの第3引数(バッファサイズ)は、内部的にgetdirentriesシステムコールに渡される際に、64ビット整数型を期待していました。Goのint型が32ビットシステムでは32ビット、64ビットシステムでは64ビットとなるため、特に32ビット環境でコンパイルされたGoプログラムが64ビットシステムコールを呼び出す場合や、コンパイラが型チェックを厳密に行う場合に問題が発生します。
この場合、amd64アーキテクチャ(64ビット)向けにビルドしているにもかかわらず、len(buf)が返すint型が、syscall.Getdirentriesが期待するint64型と異なるためにコンパイルエラーが発生したと考えられます。Goのコンパイラは、異なるサイズの整数型間の暗黙的な変換を許容しないため、明示的な型変換が必要となります。
コアとなるコードの変更箇所
変更はsrc/lib/os/dir_amd64_darwin.goファイルの1箇所のみです。
--- a/src/lib/os/dir_amd64_darwin.go
+++ b/src/lib/os/dir_amd64_darwin.go
@@ -26,7 +26,7 @@ func Readdirnames(fd *FD, count int) (names []string, err *os.Error) {
if count == 0 {
break
}
- ret, err2 := syscall.Getdirentries(fd.fd, &buf[0], len(buf), &base);
+ ret, err2 := syscall.Getdirentries(fd.fd, &buf[0], int64(len(buf)), &base);
if ret < 0 || err2 != 0 {
return names, os.ErrnoToError(err2)
}
コアとなるコードの解説
変更は非常にシンプルで、syscall.Getdirentries関数の第3引数であるlen(buf)に対して、明示的にint64型への型変換を行っています。
int64(len(buf))
これにより、len(buf)が返すint型の値が、syscall.Getdirentriesが期待するint64型に変換されて渡されるようになります。この修正によって、型不一致によるコンパイルエラーが解消され、Goのビルドが正常に完了するようになりました。
この修正は、Go言語が異なるOSやアーキテクチャに対応する際に、システムコールインターフェースの厳密な型要件を満たすことの重要性を示しています。特に、len()のような組み込み関数が返す汎用的なint型と、特定のシステムコールが期待する固定サイズの整数型との間のギャップを埋めるために、明示的な型変換が必要となる典型的なケースです。
関連リンク
- Go言語の
syscallパッケージに関するドキュメント(現在のバージョン): https://pkg.go.dev/syscall - Go言語の
osパッケージに関するドキュメント(現在のバージョン): https://pkg.go.dev/os - GitHub上のGoリポジトリ: https://github.com/golang/go
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/c8d59c1fb24cd5efd495ec8142aa69270ddba8d2
- Go言語の公式ドキュメント(型、組み込み関数など)
- Unix系OSの
getdirentriesシステムコールに関する一般的な情報(manページなど)