[インデックス 1653] ファイルの概要
このコミットは、Go言語の初期のDarwin(macOS)向けシステムコール実装における、Getdirentries
関数の修正に関するものです。具体的には、src/lib/syscall/file_darwin.go
ファイルが変更されています。
コミット
commit 2f147992b4f3f8a89d1d51d48845f5d310719388
Author: Rob Pike <r@golang.org>
Date: Mon Feb 9 20:04:36 2009 -0800
fix Getdirentries: base comes back in r2.
R=rsc
DELTA=3 (3 added, 0 deleted, 0 changed)
OCL=24727
CL=24727
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2f147992b4f3f8a89d1d51d48845f5d310719388
元コミット内容
fix Getdirentries: base comes back in r2.
変更の背景
このコミットは、Darwin(macOS)システムにおけるGetdirentries
システムコールの挙動に対応するための修正です。Getdirentries
はディレクトリのエントリを読み込むためのシステムコールですが、特定の環境(この場合はDarwin)では、そのオフセット情報(base
)がシステムコールの戻り値のセカンダリレジスタ(r2
)に格納されて返されるという特性がありました。
Go言語の初期のシステムコールラッパーは、プライマリの戻り値(r1
)とエラーコード(err
)を主に扱っていましたが、Getdirentries
のようにセカンダリの戻り値も重要な意味を持つ場合、その値を適切に取得して利用する必要がありました。この修正は、Getdirentries
が返すbase
値を正しくbasep
ポインタに書き戻すことで、ディレクトリ読み込みの継続性を保証するために導入されました。
前提知識の解説
システムコール (Syscall)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイルI/O、メモリ管理、プロセス制御など、OSの基本的な機能にアクセスするために使用されます。Go言語では、syscall
パッケージを通じてこれらのシステムコールを呼び出すことができます。
Getdirentries
/ SYS_GETDIRENTRIES64
Getdirentries
は、Unix系システムでディレクトリの内容を読み取るためのシステムコールです。ディレクトリ内のファイルやサブディレクトリのエントリをバッファに書き込みます。
SYS_GETDIRENTRIES64
は、特に64ビットのオフセットを扱うためのGetdirentries
のバリアントで、Darwinを含む一部のシステムで利用されます。これにより、大きなディレクトリやファイルシステムを効率的に処理できます。
Go言語の初期のシステムコール実装とr1
, r2
Go言語の初期のsyscall
パッケージでは、Syscall
やSyscall6
といった関数が、OSのシステムコールを直接呼び出すための低レベルなラッパーとして提供されていました。これらの関数は、システムコールの戻り値をr1
, r2
, err
という形式で返します。
r1
: システムコールの主要な戻り値。通常、成功した場合は非負の値(例えば、読み込まれたバイト数など)、エラーの場合は-1
が返されます。r2
: システムコールのセカンダリな戻り値。一部のシステムコールでは、r1
だけでは表現しきれない追加の情報(例えば、Getdirentries
における次の読み込み開始位置のオフセットなど)をr2
に格納して返します。err
: システムコールがエラーを返した場合の、OS固有のエラーコード。
特に、32ビットシステムで64ビットの値を返すシステムコールや、複数の戻り値を持つシステムコールの場合、r1
とr2
の両方が使用されることがあります。このコミットのケースでは、Getdirentries
がbase
オフセットをr2
に返していました。
unsafe.Pointer
とuintptr
Go言語におけるunsafe.Pointer
は、任意の型のポインタを保持できる特殊なポインタ型です。型安全性を無視してメモリを直接操作することを可能にします。uintptr
は、ポインタの値を整数として表現する型です。これらは、C言語のポインタ操作に似た低レベルなメモリ操作や、システムコールへの引数としてポインタを渡す際に使用されます。
技術的詳細
このコミットが修正している問題は、Getdirentries
システムコールが、次の読み込みを開始すべきオフセット(base
)を、GoのSyscall6
関数が返すr2
レジスタに格納して返すというDarwin特有の挙動にあります。
元のコードでは、Syscall6
の戻り値のうち、r1
(主要な戻り値)とerr
(エラーコード)のみが利用され、r2
の値は無視されていました。しかし、Getdirentries
システムコールは、読み込みが成功した場合に、次に読み込むべきディレクトリ内のオフセットをr2
に設定します。このオフセットは、basep
というポインタを通じて呼び出し元に返されるべき値です。
修正前は、Getdirentries
が成功しても、basep
が更新されないため、連続してディレクトリを読み込む際に常に最初から読み込みが開始されてしまうか、不正なオフセットで処理が続行される可能性がありました。これは、ディレクトリの全エントリを列挙するような処理において、無限ループや不完全な結果につながるバグとなります。
このコミットは、Syscall6
の呼び出し結果として得られたr2
の値を、システムコールが成功した場合(r1 != -1
)に、basep
が指すメモリ位置に明示的に書き込むことで、この問題を解決しています。これにより、Getdirentries
の呼び出し元は、正しく次の読み込みオフセットを取得し、ディレクトリの継続的な走査が可能になります。
コアとなるコードの変更箇所
--- a/src/lib/syscall/file_darwin.go
+++ b/src/lib/syscall/file_darwin.go
@@ -96,5 +96,8 @@ func Dup2(fd1, fd2 int64) (ret int64, errno int64) {
func Getdirentries(fd int64, buf *byte, nbytes int64, basep *int64) (ret int64, errno int64) {
r1, r2, err := Syscall6(SYS_GETDIRENTRIES64, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes, int64(uintptr(unsafe.Pointer(basep))), 0, 0);
+ if r1 != -1 {
+ *basep = r2
+ }
return r1, err;
}
コアとなるコードの解説
変更はsrc/lib/syscall/file_darwin.go
ファイルのGetdirentries
関数内にあります。
func Getdirentries(fd int64, buf *byte, nbytes int64, basep *int64) (ret int64, errno int64) {
r1, r2, err := Syscall6(SYS_GETDIRENTRIES64, fd, int64(uintptr(unsafe.Pointer(buf))), nbytes, int64(uintptr(unsafe.Pointer(basep))), 0, 0);
if r1 != -1 {
*basep = r2
}
return r1, err;
}
-
r1, r2, err := Syscall6(...)
:Syscall6
関数は、SYS_GETDIRENTRIES64
システムコールを呼び出します。引数として、ファイルディスクリプタfd
、バッファbuf
、読み込むバイト数nbytes
、そしてbasep
(次の読み込みオフセットを格納するためのポインタ)が渡されます。Syscall6
は、システムコールの戻り値をr1
、r2
、そしてエラーerr
として返します。 -
if r1 != -1 { ... }
: この条件分岐は、システムコールが成功したかどうかをチェックしています。Unix系システムコールでは、通常、成功した場合は非負の値(例えば、読み込まれたバイト数)を返し、エラーの場合は-1
を返します。したがって、r1 != -1
はシステムコールがエラーなく完了したことを意味します。 -
*basep = r2
: システムコールが成功した場合、r2
に格納されている値(Getdirentries
システムコールが返す次の読み込みオフセット)を、basep
が指すメモリ位置に書き込みます。*basep
はポインタbasep
が指す先の値を意味します。これにより、呼び出し元が提供したbasep
ポインタを通じて、正しいオフセット情報が更新されます。
この修正により、Getdirentries
関数は、Darwin環境において、ディレクトリの読み込みオフセットを正しく管理できるようになり、ディレクトリの継続的な走査が正確に行われるようになりました。
関連リンク
- Go言語の
syscall
パッケージに関するドキュメント: https://pkg.go.dev/syscall - Darwinの
getdirentries
システムコールに関する情報(manページなど)
参考にした情報源リンク
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHQ_2hDeWpLMZJSvYMX3fXX6ptKdnJ3QAtozQNTwuGVE0FDKtwgP6SDFqUAa5h6SgRpREw9gPgAyPW1Mgodf9o-NKTRYnN6iZdRviaj2EBZe2hTqgMjAxo-HB17ZYvMe8Jyo2Ti
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGvBOVNxYNdBR6aIS-o_xdGU5dijcRuNIIbssy_ghOvP5gkm4Zt9Htq8rgY-O_iRKWY2IFcWL2rX5V8y-AgR5qIwBxgbts14VdxLFYCdg4h1BqyL57JzWwlKg53GrPfKG3OHh2C
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEJ4-jSu-AUsLVIUXX7VKw6dcZH8bR09wnfeXR1P5t36kIbEfQfu11vVqRfkddkQWIyDqksjwVKd49RbvgmivSt_R3E4Pa8gzJQjfAcQ9wdBwTmKzImzrkC2XzkAZgl8iMB0hDOw3G0rQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHKo22xClPosb1iheulFCCPbNoY_CVxf4O7BcbOJXzfQyG4y1rgtI00P6YZ-t7yTr550QMlAsU2Cd6y1SS3lYtNx4PP6djFaKxJRVaaK6971C-Tk4VOf4Jwv4gn0YOHmCyYJhJfQqRS
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFxEwM1ypZQ6t7SHihBg73nG05ld5vjr89phvIY2I90Kpxoq4Le3zZTlSa1PTyCbSy2QtMTgY23u44fcbpeHLQ2i6MRhp2GyEqrZy0NE8J2lp8WtWiJjI8YhDZ9kukiuchaPA_jn1OYJsNiu2gHKoQDKT-z94rXwSQd5Zdf3TK2HpkoIPu8nT1tQ39jobCjMKxhQ7WH6i35Egmxs_KT
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHEQN5SkAUEemJqE1Ppai7KiQIX06B0wueYqRGCgDqJCwXMelS7zVBvbloMRCtz8QLWsIXkY-3uYTP11eIWoUZBihY2swRYsB8UYbQET78MwSOdOzxi443pvWslZglQvdM0POc=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHrJpuWj-IEcQqWjsSYj7NTgCJDkqCtTmP0y2nkdDOqM-4YORzLPBkx5wS8K_YV_JxutflGF7IUAgmUFNMYCfO_-JWBR3RbxGwXEN4G1-1URvjU-IIssyIhKuz0nhATS0b03YUbmWs5-eZjvM-AP1lA4mYEElsA==