[インデックス 16743] ファイルの概要
このコミットは、Go言語のリンカである cmd/5l
(ARM), cmd/6l
(x86-64), cmd/8l
(x86) におけるエラーメッセージバッファのサイズを増やす変更です。具体的には、エラーメッセージを格納するための内部バッファ buf
のサイズが STRINGSZ
(200バイト) から 1024
バイトに拡張されています。これにより、ファイル名を含む長いエラーメッセージが切り詰められることなく表示されるようになります。
コミット
commit 6c99b5c0d31b21d0163bd1d7ee0e248e19a0cba3
Author: Russ Cox <rsc@golang.org>
Date: Thu Jul 11 22:49:15 2013 -0400
cmd/5l, cmd/6l, cmd/8l: increase error buffer size
STRINGSZ (200) is fine for lines generated by things like
instruction dumps, but an error containing a couple file
names can easily exceed that, especially on Macs with
the ridiculous default $TMPDIR.
R=ken2
CC=golang-dev
https://golang.org/cl/11199043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6c99b5c0d31b21d0163bd1d7ee0e248e19a0cba3
元コミット内容
cmd/5l, cmd/6l, cmd/8l: increase error buffer size
STRINGSZ (200) is fine for lines generated by things like
instruction dumps, but an error containing a couple file
names can easily exceed that, especially on Macs with
the ridiculous default $TMPDIR.
R=ken2
CC=golang-dev
https://golang.org/cl/11199043
変更の背景
この変更の背景には、Go言語のリンカが生成するエラーメッセージが、特定の環境下でバッファオーバーフローを起こし、メッセージが途中で切り詰められてしまう問題がありました。特に、ファイルパスが長くなる傾向にあるmacOS環境の $TMPDIR
(一時ディレクトリ) などで、複数のファイル名を含むエラーメッセージが STRINGSZ
で定義された200バイトのバッファに収まりきらないケースが発生していました。
STRINGSZ
は、命令ダンプのような比較的短い文字列を扱う場合には十分なサイズでしたが、エラーメッセージのように動的に内容が変化し、かつファイルパスなどの長い文字列を含む可能性がある場合には不十分でした。エラーメッセージが途中で切れてしまうと、ユーザーは問題の根本原因を特定しにくくなり、デバッグの効率が低下します。この問題を解決し、より分かりやすいエラーメッセージを提供するために、エラーバッファのサイズを増やす必要がありました。
前提知識の解説
Go言語のツールチェインとリンカ
Go言語のビルドプロセスは、ソースコードをコンパイルし、最終的に実行可能なバイナリを生成する一連のツールチェインによって構成されています。このツールチェインには、コンパイラ (go tool compile
)、アセンブラ (go tool asm
)、そしてリンカ (go tool link
) などが含まれます。
- コンパイラ: Goのソースコードをアセンブリコードに変換します。
- アセンブラ: アセンブリコードをオブジェクトファイルに変換します。
- リンカ: 複数のオブジェクトファイルやライブラリを結合し、最終的な実行可能バイナリを生成します。リンカは、プログラムが参照する外部関数やデータのアドレスを解決し、それらを適切に配置する役割を担います。
cmd/5l
, cmd/6l
, cmd/8l
これらは、Go言語の初期のツールチェインにおけるリンカのコマンド名です。Go言語はクロスプラットフォーム開発を強く意識しており、異なるCPUアーキテクチャ向けにバイナリを生成できます。
cmd/5l
: ARMアーキテクチャ向けのリンカです。cmd/6l
: x86-64 (AMD64) アーキテクチャ向けのリンカです。現代のほとんどのデスクトップPCやサーバーで広く使われています。cmd/8l
: x86 (IA-32) アーキテクチャ向けのリンカです。32ビットシステムで使われます。
これらのリンカは、それぞれ特定のアーキテクチャの命令セットやメモリモデルに合わせて最適化されています。
STRINGSZ
STRINGSZ
は、Go言語のツールチェイン内部で使われていた定数で、主に文字列バッファのデフォルトサイズを定義するために使用されていました。このコミットの時点では、その値は200バイトでした。これは、命令ダンプのような固定長または比較的短い文字列の表示には十分でしたが、可変長で長いパス名などを含むエラーメッセージには不十分であることが判明しました。
diag
関数
diag
関数は、Go言語のツールチェイン内で診断メッセージ(エラー、警告など)を出力するために使用される内部関数です。この関数は printf
スタイルのフォーマット文字列と可変引数を受け取り、それらを整形して標準エラー出力などに書き出します。このコミットでは、diag
関数内で使用される一時バッファ buf
のサイズが変更されています。
技術的詳細
このコミットの技術的な詳細は、Go言語のリンカ (cmd/5l
, cmd/6l
, cmd/8l
) のソースコードにおけるエラーメッセージ処理の改善にあります。
各リンカの list.c
ファイルには、診断メッセージを出力するための diag
関数が実装されています。この diag
関数内で、フォーマットされたメッセージを一時的に格納するために char buf[STRINGSZ]
という固定サイズのバッファが使用されていました。
問題は、STRINGSZ
が200バイトと定義されていたことです。エラーメッセージが、例えば以下のような形式で出力される場合を考えます。
error: could not open file /path/to/very/long/directory/name/another/long/directory/name/source_file.go and /path/to/another/very/long/directory/name/another/long/directory/name/target_file.go
このようなメッセージは、特にmacOSのように一時ディレクトリのパスが非常に長くなる環境では、容易に200バイトを超過してしまいます。バッファサイズを超過すると、diag
関数はメッセージの残りの部分を切り捨ててしまい、ユーザーには不完全なエラーメッセージしか表示されません。これはデバッグを困難にし、ユーザーエクスペリエンスを損ないます。
このコミットでは、この問題を解決するために、buf
のサイズを STRINGSZ
から 1024
バイトに増やしています。1024バイトは、ほとんどの一般的なエラーメッセージ、特にファイルパスを含む場合でも、十分な長さを確保できるサイズです。これにより、エラーメッセージが途中で切り詰められる可能性が大幅に低減され、より完全で有用な診断情報がユーザーに提供されるようになります。
この変更は、Go言語のツールチェインの堅牢性とユーザーフレンドリーさを向上させるための、小さなしかし重要な改善と言えます。
コアとなるコードの変更箇所
変更は src/cmd/5l/list.c
, src/cmd/6l/list.c
, src/cmd/8l/list.c
の3つのファイルにわたっています。それぞれのファイルで、diag
関数内のローカル変数 buf
の宣言が変更されています。
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -473,7 +473,7 @@ Oconv(Fmt *fp)
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn, *sep;
+ char buf[1024], *tn, *sep;
va_list arg;
tn = "";
同様の変更が src/cmd/6l/list.c
と src/cmd/8l/list.c
にも適用されています。
コアとなるコードの解説
上記のコードスニペットは、diag
関数の定義の一部を示しています。
void diag(char *fmt, ...)
: これはdiag
関数のシグネチャです。fmt
はフォーマット文字列(printf
と同様の形式)で、...
は可変引数リストを示します。char buf[STRINGSZ], *tn, *sep;
: 変更前の行です。ここでbuf
という名前のchar
型の配列が宣言されており、そのサイズはSTRINGSZ
で定義されていました。STRINGSZ
はこの時点では200でした。char buf[1024], *tn, *sep;
: 変更後の行です。buf
のサイズが1024
に直接ハードコードされています。これにより、diag
関数が内部でメッセージを整形する際に使用するバッファの容量が、200バイトから1024バイトに拡張されました。
この変更により、diag
関数が生成するエラーメッセージが、より長い文字列(特にファイルパスなど)を含んでいても、途中で切り詰められることなく完全にバッファに収まるようになります。これは、エラーメッセージの完全性と有用性を向上させるための直接的な修正です。
関連リンク
- Go言語の公式ウェブサイト: https://golang.org/
- Go言語のソースコードリポジトリ (GitHub): https://github.com/golang/go
- このコミットのGo Gerritレビューページ: https://golang.org/cl/11199043
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Gitのコミット履歴と差分表示
- 一般的なリンカの動作に関する情報
- C言語における可変引数関数 (
stdarg.h
) に関する情報