[インデックス 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ページなど)