[インデックス 11469] ファイルの概要
このコミットは、Goコンパイラの一部である8g
(x86アーキテクチャ向けのGoコンパイラ)において、ローカルプログラムカウンタ(PC)の型をulong
からuintptr
に変更するものです。これにより、特定のバグ(Issue #2478)が修正され、より堅牢でポータブルなコードベースへの改善が図られています。
コミット
commit f3492a7d404f41d45f9174b27086861fe2d2b3a5
Author: Russ Cox <rsc@golang.org>
Date: Mon Jan 30 13:20:10 2012 -0500
8g: use uintptr for local pc
Fixes #2478.
R=ken2
CC=golang-dev
https://golang.org/cl/5593051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f3492a7d404f41d45f9174b27086861fe2d2b3a5
元コミット内容
8g: use uintptr for local pc
Fixes #2478.
R=ken2
CC=golang-dev
https://golang.org/cl/5593051
変更の背景
このコミットは、Go言語のコンパイラ(特に8g
、x86アーキテクチャ向けのコンパイラ)におけるバグ、Issue #2478を修正するために行われました。具体的なバグの内容はコミットメッセージからは直接読み取れませんが、プログラムカウンタ(PC)を扱う際にulong
型を使用していたことが問題の原因であったと推測されます。
ulong
はC言語における符号なし長整数型であり、そのサイズはシステムによって異なる可能性があります(例:32ビットシステムでは32ビット、64ビットシステムでは64ビット)。一方、uintptr
はGo言語においてポインタを保持するのに十分な大きさを持つ符号なし整数型として定義されています。プログラムカウンタはメモリ上の命令のアドレスを指すため、これは本質的にポインタの一種です。
異なるアーキテクチャやコンパイラ設定において、ulong
のサイズがポインタのサイズと一致しない場合、あるいは将来的なアーキテクチャ変更に対応できない場合に、予期せぬ動作やバグ(例えば、アドレスの切り捨てやオーバーフロー)が発生する可能性があります。この変更は、PCの表現にuintptr
を使用することで、よりポータブルで安全な方法でアドレスを扱うことを目的としています。
前提知識の解説
8gコンパイラ
8g
は、Go言語の初期のコンパイラツールチェーンの一部で、x86(32ビット)アーキテクチャ向けのGoコードをコンパイルするために使用されていました。Go言語のコンパイラは、ターゲットアーキテクチャごとに異なる名前を持っており、例えば6g
はamd64、5g
はARMを指していました。現在では、これらのコンパイラは統合され、go build
コマンドを通じて透過的に利用されますが、当時のGo開発においては、特定のアーキテクチャ向けのコンパイラを指す用語として使われていました。
プログラムカウンタ (PC)
プログラムカウンタ(Program Counter, PC)は、CPUのレジスタの一つで、次に実行される命令のメモリ上のアドレスを保持しています。CPUはPCが指すアドレスから命令をフェッチし、実行します。命令の実行が完了すると、PCは通常、次の命令のアドレスに進みます。関数呼び出しやジャンプ命令などによって、PCの値は変更され、プログラムの実行フローが制御されます。デバッグやプロファイリングにおいては、特定の時点でのPCの値を知ることが、プログラムの実行状態を理解する上で非常に重要です。
uintptr型 (Go言語)
uintptr
はGo言語の組み込み型の一つで、ポインタを保持するのに十分な大きさを持つ符号なし整数型です。これは、ポインタと整数型の間で安全に変換を行う必要がある場合(例えば、C言語との相互運用や、ガベージコレクタが管理しないメモリ領域を扱う場合)に主に使用されます。uintptr
は、ポインタが指すアドレスの数値表現であり、ポインタ演算を行うことができますが、ガベージコレクタの対象外であるため、誤った使用はメモリリークやクラッシュの原因となる可能性があります。
ulong型 (C言語)
ulong
はC言語におけるunsigned long
型のことで、符号なし長整数型を意味します。その具体的なサイズは、コンパイラやターゲットシステム(アーキテクチャ)によって異なります。例えば、多くの32ビットシステムでは32ビット(4バイト)ですが、64ビットシステムでは64ビット(8バイト)になることが一般的です。この可変性が、異なるシステム間でのコードのポータビリティに影響を与えることがあります。
getcallerpc()
関数
getcallerpc()
は、Go言語のランタイムやコンパイラ内部で使用される関数(またはコンパイラ組み込み関数)で、現在の関数の呼び出し元のプログラムカウンタ(PC)を取得するために使用されます。これは、スタックトレースの生成、プロファイリング、デバッグなどの低レベルな操作で利用されます。この関数はGoのユーザーコードから直接呼び出すことは通常なく、コンパイラやランタイムの内部実装の詳細です。
技術的詳細
このコミットの技術的な核心は、プログラムカウンタの表現にulong
からuintptr
への型変更を行った点にあります。
-
型の安全性とポータビリティ:
- C言語の
ulong
は、そのサイズがプラットフォーム依存であるため、32ビットシステムと64ビットシステムで異なる挙動を示す可能性があります。プログラムカウンタはメモリのアドレスを指すため、そのサイズはポインタのサイズと一致している必要があります。もしulong
がポインタよりも小さいサイズで定義されているシステムでコンパイルされた場合、アドレスが切り捨てられ、不正なメモリ参照やクラッシュを引き起こす可能性があります。 - Go言語の
uintptr
は、Goの仕様によって「ポインタを保持するのに十分な大きさを持つ符号なし整数型」と明確に定義されています。これにより、Goがサポートするすべてのアーキテクチャにおいて、ポインタのサイズに合わせた適切な整数型が保証されます。この変更により、コンパイラがPCを扱う際の型の安全性が向上し、異なるアーキテクチャへの移植性が高まります。
- C言語の
-
ガベージコレクションとの関連:
- Go言語はガベージコレクション(GC)を持つ言語です。GCはメモリ上のポインタを追跡し、到達可能なオブジェクトを特定して、到達不能なオブジェクトを解放します。
uintptr
はポインタの数値表現であり、それ自体はGCの対象ではありません。しかし、getcallerpc()
のような関数が返す値は、実行中のコードのアドレスであり、これはGCが管理するヒープ上のオブジェクトへのポインタとは異なります。 - この変更は、GCの動作に直接的な影響を与えるものではありませんが、コンパイラが内部的にアドレスを扱う際の正確性を保証する上で重要です。特に、スタックフレームやレジスタに一時的に保持されるPCの値が、常に正確なアドレスを表現できるようにすることで、デバッグ情報やプロファイリングの正確性が保たれます。
- Go言語はガベージコレクション(GC)を持つ言語です。GCはメモリ上のポインタを追跡し、到達可能なオブジェクトを特定して、到達不能なオブジェクトを解放します。
-
コンパイラの内部構造:
src/cmd/8g/gsubr.c
は、Goコンパイラの8g
(x86向け)のサブルーチンやユーティリティ関数が含まれるファイルであると推測されます。regpc
という変数は、レジスタに関連するプログラムカウンタの値を保持するための配列である可能性が高いです。コンパイラは、コード生成や最適化の過程で、レジスタの状態やPCの値を頻繁に追跡する必要があります。regpc[D_NONE]
やregpc[i]
といった記述から、これはレジスタの種類(D_NONE
は「なし」を意味する定数、i
はレジスタのインデックス)に対応するPCの値を格納する配列であることが示唆されます。getcallerpc(&n)
の戻り値をregpc[i]
に代入していることから、特定のレジスタが使用された時点での呼び出し元のPCを記録していると考えられます。
この変更は、Goコンパイラの低レベルな部分における型の厳密性を高め、将来的なバグの発生を防ぐための重要な改善と言えます。
コアとなるコードの変更箇所
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -783,7 +783,7 @@ ginit(void)
reg[resvd[i]]++;
}
-ulong regpc[D_NONE];
+uintptr regpc[D_NONE];
void
gclean(void)
@@ -871,7 +871,7 @@ out:
if (i == D_SP)
print("alloc SP\\n");
if(reg[i] == 0) {
-\t\tregpc[i] = (ulong)getcallerpc(&n);\
+\t\tregpc[i] = (uintptr)getcallerpc(&n);\
\t\tif(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {\
\t\t\tdump("regalloc-o", o);\
\t\t\tfatal("regalloc %R", i);\
コアとなるコードの解説
このコミットでは、src/cmd/8g/gsubr.c
ファイル内の2箇所が変更されています。
-
regpc
配列の型定義の変更:-ulong regpc[D_NONE]; +uintptr regpc[D_NONE];
regpc
は、おそらくレジスタに関連するプログラムカウンタの値を格納するための配列です。元のコードではC言語のulong
型で宣言されていましたが、これをGo言語のuintptr
型に変更しています。これにより、regpc
配列が保持する値が、ポインタのサイズに依存しない、より正確でポータブルなアドレス表現となることが保証されます。D_NONE
は、この配列のサイズを決定するための定数であり、おそらく定義されているレジスタの総数を示しています。 -
getcallerpc()
の戻り値のキャストの変更:-\t\tregpc[i] = (ulong)getcallerpc(&n);\ +\t\tregpc[i] = (uintptr)getcallerpc(&n);\
この行は、
getcallerpc(&n)
関数が返す値をregpc[i]
に代入する際に、明示的な型キャストを行っています。元のコードではulong
にキャストしていましたが、これもuintptr
にキャストするように変更されています。getcallerpc(&n)
は、現在の関数の呼び出し元のプログラムカウンタ(アドレス)を返します。この戻り値は本質的にポインタであるため、それをuintptr
として扱うことは、Goの型システムにおけるポインタと整数の間の適切な変換方法です。これにより、getcallerpc()
が返すアドレス情報が、regpc
配列に正確かつ安全に格納されるようになります。
これらの変更は、Goコンパイラが内部的にプログラムカウンタを扱う際の型の整合性とポータビリティを向上させ、Issue #2478で報告されたバグを修正するものです。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/f3492a7d404f41d45f9174b27086861fe2d2b3a5
- Go Code Review (CL): https://golang.org/cl/5593051
参考にした情報源リンク
- Go Code Review 5593051: 8G: USE UINTPTR FOR LOCAL PC (https://golang.org/cl/5593051)
- GoLand Issue GO-2478: Red code on make function (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQErZFoFP44Z6Lduwo4KzuU_YjTPjIzt9zCi-X_BvmCNV8Q0aDXr2vjFP5G-n61weNRZ5MngOkDyo-ZIFnOAYI7DtLbsLGMYdl8YX9634EuY7iT02cSLDoY7FGkAwYjXqC_ZdEcAce9Z)
- GitHub Issue #2478 (minio/minio): server: golang runtime error on sending a curl request on localhost:9000 (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHNQCCcw22rVS4N4TNRr0nkR_MA_ZN1i2riuSbPVp09_YlHDGMx-yuZt7AFLnZHeuzYp6bIzSxZKZwmG8jlZKG1RDCCwKQ2TmrFpmYS4lQAOilvpedX7HbbRT9Bi8j9KXVaEAQCNA==)
- Go source code (src/runtime/proc.go): (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFMeamFuAubdkp2RruffF1W8mSB5_eNGIweDrfOEw9Piuxs0oiqucpWmLAaO8oUZDgs1G3-vwNdHtpux-ds6v9aLe_h8R854imuuS8i7YgbSSRRBXJlwEArgMnxznc=)
- Go source code (src/net/http/transport.go): (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFXPNA4smYXSnfVnf3Rd08WjLM7NRuf1bu4XzvD8dfx5moCQaYe1xqjDpN9SJ8rUyz5djJegqHSp2JwxyHX0MDM1quol3XdodO-NXUJMuHuFPIWU9haGoLPzwrGryYC7rG-A2p-X9AgVID3uCDXEicZJ4oopzeBC4Cj)