Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18228] ファイルの概要

このコミットは、Goランタイムのsrc/pkg/runtime/symtab.cファイルに対する変更です。symtab.cは、Goプログラムの実行時に使用されるシンボルテーブル(特にPC-Lineテーブル、pclntab)の初期化と管理に関連するコードを含んでいます。シンボルテーブルは、プログラムカウンタ(PC)アドレスとソースコードの行番号、関数名などをマッピングするために使用され、デバッグ情報やスタックトレースの生成に不可欠です。

コミット

commit a2edc469a0d4f744c26d3245a6600a02b4ebf426
Author: Russ Cox <rsc@golang.org>
Date:   Mon Jan 13 11:39:04 2014 -0500

    runtime: remove redundant 0x prefix in error print
    
    %x already adds the prefix unconditionally
    
    R=golang-codereviews, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/51550043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/a2edc469a0d4f744c26d3245a6600a02b4ebf426

元コミット内容

このコミットは、Goランタイム内のエラーメッセージ出力において、冗長な0xプレフィックスを削除するものです。具体的には、runtime·printf関数で16進数を出力する際に、フォーマット指定子%xが既に0xプレフィックスを無条件に追加するため、コード内で明示的に0xを記述する必要がないという修正です。

変更の背景

Goランタイムの内部で使用されるruntime·printf関数は、標準Cライブラリのprintfに似た機能を提供します。通常、C言語のprintfにおいて16進数(%xまたは%X)を出力する際、0xまたは0Xのプレフィックスを付けるには、#フラグ(例: %#x)を使用する必要があります。しかし、Goランタイムの特定のprintf実装では、%xフォーマット指定子自体が既に0xプレフィックスを自動的に付加するようになっています。

このコミットが行われる前は、src/pkg/runtime/symtab.c内のエラー出力で、runtime·printf("... 0x%x ...", ...)のように、フォーマット指定子の前に手動で0xを記述していました。これは、%xが既に0xを付加するGoランタイムのprintfの挙動と重複し、結果として0x0x...のような冗長な出力になる可能性がありました(あるいは、単にコード上の冗長性として認識されていました)。このコミットは、この冗長性を排除し、コードをよりクリーンにするために行われました。

前提知識の解説

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理するソフトウェアコンポーネントの集合体です。これには、ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ割り当て、スタック管理、プリミティブな同期メカニズム、そして低レベルのI/O操作などが含まれます。Goプログラムは、オペレーティングシステム上で直接実行されるのではなく、このランタイム上で動作します。src/pkg/runtimeディレクトリには、これらのランタイム機能のソースコードが含まれています。

printfフォーマット指定子と%x

printfは、C言語とその派生言語(Goランタイムの内部関数も含む)で広く使われる、書式付き出力を行う関数です。フォーマット文字列内の%で始まるシーケンスは、引数の値をどのように表示するかを指示する「フォーマット指定子」です。

  • %d: 10進整数
  • %s: 文字列
  • %p: ポインタのアドレス(通常は16進数)
  • %xまたは%X: 符号なし整数を16進数で表示します。%xは小文字のa-fを使用し、%Xは大文字のA-Fを使用します。

標準Cのprintfでは、%xはデフォルトで0xプレフィックスを付けません。プレフィックスを付けるには、%#xのように#フラグを使用します。しかし、このコミットの背景にあるように、Goランタイムのruntime·printfの内部実装では、%xが既に0xプレフィックスを無条件に付加するようになっている点が重要です。

シンボルテーブルとpclntab

Goプログラムがコンパイルされると、実行可能ファイルにはデバッグ情報やプロファイリング情報の一部として「シンボルテーブル」が含まれます。シンボルテーブルは、プログラム内の関数名、変数名、ソースコードの行番号と、それらがメモリ上のどのアドレスに対応するかをマッピングするデータ構造です。

pclntab(PC-Line Table)は、Goランタイムにおけるシンボルテーブルの重要な部分です。これは、プログラムカウンタ(PC、現在実行中の命令のアドレス)から、対応する関数名やソースファイルの行番号を効率的にルックアップするために最適化されたデータ構造です。スタックトレースの生成や、デバッガが現在実行中のコードの場所を特定する際に利用されます。src/pkg/runtime/symtab.cは、このpclntabの初期化と検証を行うコードを含んでいます。

技術的詳細

このコミットの技術的詳細は、Goランタイムの内部的なprintf実装の挙動に集約されます。 src/pkg/runtime/symtab.c内のruntime·symtabinit関数は、pclntabのヘッダが期待される形式であるかを検証します。もしヘッダが不正な場合、エラーメッセージを出力してプログラムを終了させます。

変更前のコードでは、このエラーメッセージの出力にruntime·printf("... 0x%x 0x%x\\n", ...)という形式が使われていました。ここで、0xという文字列リテラルが明示的に記述され、その後に%xフォーマット指定子が続いていました。

コミットメッセージが示すように、Goランタイムのruntime·printfにおける%xの内部実装は、標準Cのprintfとは異なり、#フラグがなくても自動的に0xプレフィックスを付加するようになっています。したがって、0x%xと書くと、runtime·printf0xというリテラル文字列を出力し、その後に%xによって生成された値(これも0xプレフィックスが付いている)を出力することになり、結果として0x0x...のような冗長な出力、または少なくとも意図しない二重のプレフィックスが発生する可能性がありました。

このコミットは、この冗長な0xリテラルを削除し、runtime·printf("... %x %x\\n", ...)とすることで、%xフォーマット指定子に任せて適切な0xプレフィックス付きの16進数を出力させるように修正しました。これにより、出力はより正確で意図通りになり、コードも簡潔になりました。この変更は機能的な影響はほとんどなく、主にコードのクリーンアップと正確性の向上を目的としています。

コアとなるコードの変更箇所

--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -38,7 +38,7 @@ runtime·symtabinit(void)
 	// two zero bytes, a byte giving the PC quantum,
 	// and a byte giving the pointer width in bytes.
 	if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) {
-\t\truntime·printf("runtime: function symbol table header: 0x%x 0x%x\\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
+\t\truntime·printf("runtime: function symbol table header: %x %x\\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));
 \t\truntime·throw("invalid function symbol table\\n");
 \t}

コアとなるコードの解説

変更はsrc/pkg/runtime/symtab.cファイルのruntime·symtabinit関数内の一行です。

元のコード:

runtime·printf("runtime: function symbol table header: 0x%x 0x%x\\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));

この行では、pclntabのヘッダが不正な場合にエラーメッセージを出力しています。0x%xというフォーマット文字列が2回使われており、これはリテラルの0xと、その後に続く16進数フォーマット指定子%xを組み合わせたものです。

変更後のコード:

runtime·printf("runtime: function symbol table header: %x %x\\n", *(uint32*)pclntab, *(uint32*)(pclntab+4));

変更点としては、フォーマット文字列から明示的に記述されていた0xリテラルが削除されました。これにより、%xフォーマット指定子のみが残ります。Goランタイムのruntime·printf%xが既に0xプレフィックスを自動的に付加する性質を持つため、この変更によって出力されるメッセージは、依然として0xプレフィックス付きの16進数を含みますが、冗長な0xが二重に出力される可能性がなくなります。これは、コードの意図をより明確にし、出力の正確性を保証するためのクリーンアップです。

関連リンク

参考にした情報源リンク