[インデックス 16843] ファイルの概要
このコミットは、Go言語のリンカである cmd/ld
において、Plan 9オペレーティングシステム上で発生していたコンパイラ警告を修正するものです。具体的には、未使用変数の警告と、printf
スタイルのフォーマット文字列と引数の型不一致に関する警告が対象となっています。
コミット
commit b015af41171f00c5f6b263aafd73df6c4e58443a
Author: David du Colombier <0intro@gmail.com>
Date: Mon Jul 22 17:33:41 2013 -0400
cmd/ld: fix warnings on Plan 9
src/cmd/ld/lib.c:1379 set and not used: p
src/cmd/ld/lib.c:1426 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1437 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1456 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1477 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1459 set and not used: started
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/11615044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b015af41171f00c5f6b263aafd73df6c4e58443a
元コミット内容
このコミットは、src/cmd/ld/lib.c
ファイルに対する変更であり、以下の警告を修正することを目的としています。
src/cmd/ld/lib.c:1379 set and not used: p
src/cmd/ld/lib.c:1426 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1437 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1456 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1477 format mismatch 6llux INT, arg 3
src/cmd/ld/lib.c:1459 set and not used: started
これらの警告は、GoのリンカがPlan 9環境でコンパイルされる際に発生していました。
変更の背景
Go言語は、その初期からPlan 9オペレーティングシステムの影響を強く受けており、一部のツールチェインはPlan 9のCコンパイラやライブラリを使用して構築されていました。cmd/ld
はGoのリンカであり、Goプログラムのコンパイル済みオブジェクトファイルを結合して実行可能ファイルを生成する役割を担っています。
このコミットが作成された2013年当時、Goのツールチェインは様々なプラットフォームをサポートしていましたが、特定のプラットフォーム(この場合はPlan 9)でのコンパイル時に、標準Cとは異なるコンパイラの挙動や型定義の違いにより警告が発生することがありました。これらの警告は、直接的なバグを引き起こすものではないかもしれませんが、コードの品質を低下させ、将来的な問題の兆候となる可能性があるため、修正が望ましいとされていました。
特に、set and not used
警告は、変数が宣言され値が代入されたものの、その後のコードで一度も参照されていないことを示します。これは冗長なコードや、意図しないロジックの誤りを示唆する可能性があります。また、format mismatch
警告は、printf
のような可変引数関数において、フォーマット指定子と実際に渡される引数の型が一致しない場合に発生します。これは未定義動作を引き起こす可能性があり、特に異なるアーキテクチャやコンパイラでコンパイルされた場合に、予期せぬ出力やクラッシュにつながる可能性があります。
このコミットは、これらの警告を解消し、Plan 9上での cmd/ld
のビルドをクリーンに保つことを目的としています。
前提知識の解説
Plan 9 from Bell Labs
Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの設計思想をさらに推し進め、「すべてをファイルとして扱う」という原則を徹底しています。ネットワーク上のリソース(ファイル、デバイス、サービスなど)もすべてファイルシステムとして表現され、標準的なファイル操作インターフェースを通じてアクセスできます。Go言語の設計には、Plan 9の思想(特に並行性モデルやモジュール性)が色濃く反映されています。Plan 9のCコンパイラは、標準Cとは異なる独自の拡張や型定義を持つことがあり、それが移植性の問題を引き起こすことがあります。
Goリンカ (cmd/ld
)
Go言語のビルドプロセスにおいて、リンカ (cmd/ld
) は非常に重要な役割を担います。Goのソースコードはまずコンパイラ (cmd/compile
) によってオブジェクトファイルに変換され、その後、リンカがこれらのオブジェクトファイルと必要なランタイムライブラリを結合して、最終的な実行可能ファイルを生成します。リンカは、シンボルの解決、アドレスの再配置、実行可能ファイルのフォーマット(ELF, Mach-O, PEなど)への変換などを行います。cmd/ld
はGo言語で書かれていますが、その内部ではC言語で書かれた低レベルのルーチンや、OS固有のシステムコールを呼び出す部分も存在します。
C言語におけるコンパイラ警告
C言語のコンパイラは、プログラムの潜在的な問題や非効率なコードに対して警告を発することがよくあります。
set and not used
(設定されたが使用されていない): 変数が宣言され、値が代入されたにもかかわらず、その後のコードでその変数の値が一度も読み取られない場合に発生します。これは、プログラマの意図しない冗長なコード、あるいはロジックの誤りを示唆する可能性があります。format mismatch
(フォーマット不一致):printf
,sprintf
,fprintf
などのフォーマット文字列を使用する関数において、フォーマット指定子(例:%d
,%s
,%llx
)と、それに対応する引数の実際の型が一致しない場合に発生します。これはC言語の可変引数関数の性質上、コンパイル時に厳密な型チェックが行われにくいため、実行時に未定義動作(例: メモリ破壊、クラッシュ、誤った出力)を引き起こす可能性があります。
vlong
型と 6llux
フォーマット指定子
vlong
: Plan 9のCコンパイラにおける非標準の型で、通常は標準Cのlong long
型に相当します。これは64ビット整数を表すために使用されます。%llux
:printf
ファミリー関数で使用されるフォーマット指定子です。ll
:long long
型の引数であることを示します。u
:unsigned
(符号なし)であることを示します。x
: 16進数形式で出力することを示します。 したがって、%llux
は「符号なし64ビット整数を16進数で出力する」ことを意味します。
警告 format mismatch 6llux INT
は、%llux
が期待する unsigned long long
型の引数に対して、実際には int
型(通常32ビット)の引数が渡されていることを示しています。これは、特に32ビットシステムと64ビットシステムが混在する環境で問題となりやすいです。
技術的詳細
このコミットは、src/cmd/ld/lib.c
内の2種類の警告を修正しています。
-
未使用変数
p
の修正 (addvarint
関数内):addvarint
関数は、可変長整数(varint)をシンボルに書き込むためのものです。元のコードでは、p
というポインタが*p++ = v;
という行でインクリメントされていましたが、このインクリメント後のp
の値は関数内でそれ以上使用されていませんでした。C言語では、*p++ = v;
は「p
が指すアドレスにv
を代入し、その後p
をインクリメントする」という意味です。警告は、このインクリメント操作自体が不要であり、p
の最終的な値が使われていないことを指摘していました。 -
フォーマット不一致警告の修正 (
funcpctab
関数内):funcpctab
関数は、Goの関数におけるPC-値テーブル(プログラムカウンタと値のマッピング)を生成する際に、デバッグ情報を出力するためにBprint
関数(Plan 9のfmt
ライブラリに似たI/O関数)を使用しています。 警告format mismatch 6llux INT, arg 3
は、Bprint
の呼び出しにおいて、第3引数(p->pc
またはfunc->value+func->size
)がint
型であるにもかかわらず、フォーマット文字列%6llux
がunsigned long long
型を期待しているために発生していました。p->pc
はプログラムカウンタを表す値であり、通常はポインタサイズと同じか、それ以上の大きさを持つ整数型で表現されます。しかし、Plan 9の特定のコンパイル環境では、これが32ビットのint
として扱われていた可能性があります。 修正は、これらの引数を明示的に(vlong)
にキャストすることで行われています。vlong
はPlan 9における64ビット整数型であり、これによりBprint
が期待するunsigned long long
型と引数の型が一致し、警告が解消されます。 -
未使用変数
started
の修正 (funcpctab
関数内):funcpctab
関数内のstarted
変数は、PC-値テーブルの処理が開始されたかどうかを追跡するために使用されていました。元のコードではif(!started) started = 1; else { ... }
というロジックがあり、started
が0
の場合に1
に設定されていました。しかし、このstarted = 1;
という代入自体が、その後のstarted
の値の直接的な使用に繋がっていませんでした。つまり、started
のブール値としての状態は参照されていましたが、代入された1
という値そのものが使われていなかったため、コンパイラが警告を発していました。 修正は、if(!started) started = 1; else { ... }
をif(started) { ... }
に変更することで行われています。これにより、started
が1
に設定されるロジックが削除され、started
の状態チェックのみが行われるようになり、警告が解消されました。この変更は、ロジックの意図を変えることなく、コードをより簡潔にしています。
これらの修正は、コードのセマンティクスを変更することなく、コンパイラの警告を解消し、コードベースの健全性を向上させるものです。
コアとなるコードの変更箇所
src/cmd/ld/lib.c
ファイルにおいて、以下の変更が行われました。
addvarint
関数 (行 1379):--- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1376,7 +1376,7 @@ addvarint(Sym *s, uint32 val)\n \tp = s->p + s->np - n;\n \tfor(v = val; v >= 0x80; v >>= 7)\n \t\t*p++ = v | 0x80;\n-\t*p++ = v;\n+\t*p = v;\n }\n ```
funcpctab
関数内のBprint
呼び出し (行 1426, 1437, 1456, 1477):--- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1423,7 +1423,7 @@ funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*,\n \t\tif(val == oldval && started) {\n \t\t\tval = valfunc(func, val, p, 1, arg);\n \t\t\tif(debug['O'])\n-\t\t\t\tBprint(&bso, "%6llux %6s %P\\n", p->pc, "", p);\n+\t\t\t\tBprint(&bso, "%6llux %6s %P\\n", (vlong)p->pc, "", p);\n \t\t\tcontinue;\n \t\t}\n ``` (他の箇所も同様に `p->pc` や `func->value+func->size` に `(vlong)` キャストが追加されています)
funcpctab
関数内のstarted
変数のロジック (行 1459):--- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1453,11 +1453,9 @@ funcpctab(Sym *dst, Sym *func, char *desc, int32 (*valfunc)(Sym*, int32, Prog*,\n \t\t// where the 0x80 bit indicates that the integer continues.\n \n \t\tif(debug['O'])\n-\t\t\tBprint(&bso, "%6llux %6d %P\\n", p->pc, val, p);\n+\t\t\tBprint(&bso, "%6llux %6d %P\\n", (vlong)p->pc, val, p);\n \n-\t\tif(!started)\n-\t\t\tstarted = 1;\n-\t\telse {\n+\t\tif(started) {\n \t\t\taddvarint(dst, (p->pc - pc) / MINLC);\n \t\t\tpc = p->pc;\n \t\t}\n ```
コアとなるコードの解説
-
addvarint
関数におけるp
の修正: 元のコード*p++ = v;
は、v
をp
が指すメモリ位置に書き込んだ後、p
をインクリメントしていました。しかし、この関数内でp
のインクリメント後の値は使用されていませんでした。これは、p
が指す次のメモリ位置に何かを書き込む意図がないにもかかわらず、ポインタを動かしてしまっていたことを意味します。 修正後の*p = v;
は、v
をp
が指すメモリ位置に書き込むだけで、p
をインクリメントしません。これにより、p
が「設定されたが使用されていない」という警告が解消されます。この変更は、addvarint
の機能(可変長整数の最後のバイトを書き込む)に影響を与えません。 -
funcpctab
関数におけるBprint
の引数キャスト:Bprint
関数は、%6llux
というフォーマット指定子を使用しており、これはunsigned long long
型(64ビット符号なし整数)の引数を期待します。しかし、p->pc
やfunc->value+func->size
といった値は、Plan 9の特定のコンパイル環境ではint
型(32ビット整数)として扱われることがありました。 この型不一致は、特に64ビットの値を32ビットのレジスタにロードしようとしたり、その逆を行ったりする際に、データの切り捨てや誤った解釈を引き起こす可能性があります。 修正では、これらの引数を明示的に(vlong)
にキャストしています。vlong
はPlan 9における64ビット整数型であり、これによりBprint
に渡される引数が期待される型と一致し、コンパイラ警告が解消されます。これは、異なるアーキテクチャやコンパイラ間での移植性を高める上でも重要な修正です。 -
funcpctab
関数におけるstarted
変数のロジック修正: 元のコードif(!started) started = 1; else { ... }
は、started
がfalse
の場合にtrue
に設定し、それ以降はelse
ブロックを実行するというロジックでした。しかし、started = 1;
という代入自体が、その後のコードでstarted
の値そのものとして利用されることはなく、単にstarted
のブール値としての状態がチェックされるだけでした。 修正後のif(started) { ... }
は、started
が既にtrue
である場合にのみブロック内の処理を実行します。これにより、started
を1
に設定する冗長な代入が削除され、コードが簡潔になります。この変更は、started
変数の意図された動作(最初のイテレーションをスキップし、2回目以降のイテレーションで特定の処理を行う)を維持しつつ、未使用変数の警告を解消しています。
これらの変更は、Goのリンカの堅牢性と移植性を向上させ、クリーンなビルドを保証するために行われました。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Go言語のリンカ (
cmd/ld
) のソースコード: https://github.com/golang/go/tree/master/src/cmd/ld - Plan 9 from Bell Labs: https://9p.io/plan9/
参考にした情報源リンク
- Go Change-list 11615044: https://golang.org/cl/11615044
- C言語の
printf
フォーマット指定子に関するドキュメント (例: cppreference.com): https://en.cppreference.com/w/c/io/fprintf - C言語のコンパイラ警告に関する一般的な情報 (例: GCCのドキュメント): https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
- Plan 9のC言語に関する情報 (例: Plan 9 from Bell Labsのドキュメント): https://9p.io/plan9/doc/compiler.html (一般的な情報源として)