[インデックス 19049] ファイルの概要
このコミットは、Go言語のランタイムライブラリであるlibbio
とlibmach
における、Plan 9ツールチェインが生成する警告を解消するための変更です。これらの警告は表面的な不整合に起因するもので、Plan 9環境以外では問題とならないと判断されていますが、コードの整合性を高めるために修正されました。
コミット
commit 24192bbd001385ca15ed1f769ddb467e41f4bf9c
Author: Lucio De Re <lucio.dere@gmail.com>
Date: Mon Apr 7 08:40:13 2014 -0700
libbio, libmach: warnings from the Plan 9 tool chain
Superficial inconsistencies that trigger warnings in
Plan 9. Small enough to be considered trivial and
seemingly benign outside of the Plan 9 environment.
LGTM=iant
R=golang-codereviews, 0intro, iant
CC=golang-codereviews
https://golang.org/cl/73460043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/24192bbd001385ca15ed1f769ddb467e41f4bf9c
元コミット内容
このコミットは、Go言語のlibbio
およびlibmach
ライブラリにおいて、Plan 9ツールチェインが検出する警告を修正することを目的としています。これらの警告はコードの表面的な不整合に起因するものであり、Plan 9以外の環境では特に問題を引き起こすものではないとされています。しかし、コードの品質と互換性を向上させるために、これらの些細な不整合が修正されました。
変更の背景
変更の背景には、Go言語の開発が初期段階においてPlan 9オペレーティングシステムの影響を強く受けていたという歴史があります。Go言語のコンパイラやツールチェインの一部は、Plan 9のツールチェインの設計思想や実装を参考にしています。そのため、GoのコードベースにはPlan 9環境でコンパイルする際に警告が発生するような記述が残っていることがありました。
このコミットは、そのような「表面的な不整合」を修正し、Plan 9ツールチェインでのコンパイル時に発生する警告を解消することを目的としています。警告自体は機能的な問題を引き起こすものではないとされていますが、警告がないクリーンなビルドは、開発者が潜在的な問題を早期に発見し、コードの品質を維持するために重要です。特に、クロスコンパイル環境や異なるツールチェインでの互換性を確保する上で、このような細かな修正が積み重ねられていきます。
前提知識の解説
Plan 9
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、Unixの「すべてをファイルとして扱う」という哲学をさらに推し進め、ネットワーク上のリソースもファイルシステムとして透過的に扱えるようにしました。Go言語の設計者の一部(Rob Pike, Ken Thompsonなど)はPlan 9の開発にも深く関わっており、Go言語の設計思想や一部のライブラリにはPlan 9の影響が見られます。
Plan 9ツールチェイン
Plan 9ツールチェインは、Plan 9オペレーティングシステム上で動作するコンパイラ、アセンブラ、リンカなどの開発ツールのセットです。Go言語の初期のコンパイラは、Plan 9のツールチェインの設計を参考にしているため、GoのコードベースにはPlan 9のコーディングスタイルや慣習が残っていることがあります。このコミットで言及されている「警告」は、Plan 9ツールチェインの特定のバージョンや設定において、Goのコードがそのツールチェインの厳格なチェックに引っかかったことを意味します。
libbio
libbio
は、Go言語のランタイムライブラリの一部で、バッファリングされたI/O操作(Buffered Input/Output)を提供します。C言語のstdio
ライブラリに似た機能を提供し、効率的なファイル読み書きを可能にします。このコミットでは、include/bio.h
とsrc/libbio/bputrune.c
が変更されています。
Biobuf
構造体:libbio
におけるバッファリングされたI/Oのコンテキストを保持する構造体です。BGETC
マクロ:Biobuf
から1バイトを読み出すためのマクロです。このコミットでは、型キャストに関する警告が修正されています。BPUTC
マクロ:Biobuf
に1バイトを書き込むためのマクロです。Rune
: Go言語におけるUnicodeコードポイントを表す型です。通常はint32
のエイリアスです。Runeself
: Unicodeの特定の範囲を示す定数で、通常はASCII文字の範囲(0-127)を表します。runetochar
:Rune
をUTF-8バイト列に変換する関数です。USED
マクロ: Plan 9のツールチェインでよく使われるマクロで、変数が使用されていることをコンパイラに明示し、未使用変数に関する警告を抑制するために使用されます。このコミットでは、bputrune.c
でBPUTC
の戻り値が使用されていないという警告を抑制するために追加されています。
libmach
libmach
は、Go言語のランタイムライブラリの一部で、デバッグやプロファイリングに関連する機械語レベルの操作を提供します。特に、スタックトレースの解析やレジスタ情報の取得など、低レベルなシステム情報へのアクセスを扱います。このコミットでは、src/libmach/8db.c
が変更されています。
8db.c
: このファイルは、Intel 80386アーキテクチャ(Goでは386
と表記されることが多い)向けのデバッグ機能に関連するコードを含んでいます。morestack
: Goランタイムにおけるスタック拡張メカニズムの一部です。Goのgoroutineは、必要に応じてスタックサイズを動的に拡張します。morestack
は、現在のスタックが不足した場合に呼び出されるランタイム関数で、新しい、より大きなスタックフレームを割り当て、古いスタックの内容をコピーし、実行を継続する役割を担います。i386trace
:libmach
内の関数で、i386アーキテクチャのスタックトレースを解析する機能を提供します。この関数内でmorestack
に関連するデバッグコードがコメントアウトされていましたが、このコミットでその扱いが変更されています。
技術的詳細
このコミットは、主に3つのファイルに対する変更を含んでいます。それぞれの変更は、Plan 9ツールチェインが生成する特定の警告に対処するためのものです。
include/bio.h
の変更
--- a/include/bio.h
+++ b/include/bio.h
@@ -73,7 +73,7 @@ struct Biobuf
* next few bytes in little-endian order.
*/
#define BGETC(bp)\
-\t((bp)->icount?(bp)->ebuf[(bp)->icount++]:Bgetc((bp)))\n+\t((bp)->icount?(int)((bp)->ebuf[(bp)->icount++]):Bgetc((bp)))\n #define BGETLE2(bp)\
\t((bp)->icount<=-2?((bp)->icount+=2,((bp)->ebuf[(bp)->icount-2])|((bp)->ebuf[(bp)->icount-1]<<8)):Bgetle2((bp)))\
#define BGETLE4(bp)\
この変更は、BGETC
マクロにおける型キャストの追加です。元のコードでは、ebuf[(bp)->icount++]
の結果が直接返されていましたが、これが特定のコンテキストで警告を引き起こす可能性がありました。明示的に(int)
にキャストすることで、コンパイラが期待する型との不一致による警告を抑制しています。これは、C言語における暗黙の型変換に関する警告を回避するための一般的な手法です。ebuf
は通常char
型またはuchar
型であり、それを直接返す際に、int
を期待する文脈で警告が出る可能性があります。明示的なキャストにより、この警告が解消されます。
src/libbio/bputrune.c
の変更
--- a/src/libbio/bputrune.c
+++ b/src/libbio/bputrune.c
@@ -36,7 +36,8 @@ Bputrune(Biobuf *bp, long c)\
\n \trune = (Rune)c;\
\tif(rune < Runeself) {\
-\t\tBPUTC(bp, (int)rune);\n+\t\tn = BPUTC(bp, (int)rune);\n+\t\tUSED(n);\n \t\treturn 1;\
\t}\
\tn = runetochar(str, &rune);\
この変更は、BPUTC
マクロの戻り値をn
という変数に代入し、そのn
に対してUSED(n)
マクロを適用している点です。BPUTC
マクロは通常、書き込んだバイト数を返すか、エラーを示す値を返します。元のコードでは、この戻り値が使用されていませんでした。Plan 9ツールチェインは、未使用の変数や戻り値に対して警告を出すことがあります。USED(n)
マクロは、このn
が意図的に使用されていないことをコンパイラに伝え、警告を抑制します。これにより、コードの意図が明確になり、不必要な警告が解消されます。
src/libmach/8db.c
の変更
--- a/src/libmach/8db.c
+++ b/src/libmach/8db.c
@@ -195,33 +195,36 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)\
\t\t\tbreak;\
\n \t\tif(s.value == morestack) {\
-\t\t\t// This code is old and won\'t work anymore.\n-\t\t\t// But no one uses it anyway.\n-\t\t\t// Leave it obviously broken until someone needs it.\n-\t\t\twerrstr(\"morestack not implemented correctly\");\n-\t\t\treturn -1;\n-\t\t\t// In the middle of morestack.\n-\t\t\t// Caller is m->morepc.\n-\t\t\t// Caller\'s caller is in m->morearg.\n-\t\t\t// TODO(rsc): 386\n-\t\t\tgeta(map, offsetof(struct UregAmd64, r14), &m);\n-\n-\t\t\tpc = 0;\n-\t\t\tsp = 0;\n-\t\t\tpc1 = 0;\n-\t\t\ts1 = s;\n-\t\t\tmemset(&s, 0, sizeof s);\n-\t\t\tgeta(map, m+1*mach->szaddr, &pc1);\t// m->morepc\n-\t\t\tgeta(map, m+2*mach->szaddr, &sp);\t// m->morebuf.sp\n-\t\t\tgeta(map, m+3*mach->szaddr, &pc);\t// m->morebuf.pc\n-\t\t\tfindsym(pc1, CTEXT, &s);\n-\t\t\t(*trace)(map, pc1, sp-mach->szaddr, &s1);\t// morestack symbol; caller\'s PC/SP\n-\n-\t\t\t// caller\'s caller\n-\t\t\ts1 = s;\n-\t\t\tfindsym(pc, CTEXT, &s);\n-\t\t\t(*trace)(map, pc, sp, &s1);\t\t// morestack\'s caller; caller\'s caller\'s PC/SP\n-\t\t\tcontinue;\n+\t\t\tif (0) {\n+\t\t\t\t// This code is old and won\'t work anymore.\n+\t\t\t\t// But no one uses it anyway.\n+\t\t\t\t// Leave it obviously broken until someone needs it.\n+\t\t\t\t// In the middle of morestack.\n+\t\t\t\t// Caller is m->morepc.\n+\t\t\t\t// Caller\'s caller is in m->morearg.\n+\t\t\t\t// TODO(rsc): 386\n+\t\t\t\tgeta(map, offsetof(struct UregAmd64, r14), &m);\n+\t\n+\t\t\t\tpc = 0;\n+\t\t\t\tsp = 0;\n+\t\t\t\tpc1 = 0;\n+\t\t\t\ts1 = s;\n+\t\t\t\tmemset(&s, 0, sizeof s);\n+\t\t\t\tgeta(map, m+1*mach->szaddr, &pc1);\t// m->morepc\n+\t\t\t\tgeta(map, m+2*mach->szaddr, &sp);\t// m->morebuf.sp\n+\t\t\t\tgeta(map, m+3*mach->szaddr, &pc);\t// m->morebuf.pc\n+\t\t\t\tfindsym(pc1, CTEXT, &s);\n+\t\t\t\t(*trace)(map, pc1, sp-mach->szaddr, &s1);\t// morestack symbol; caller\'s PC/SP\n+\t\n+\t\t\t\t// caller\'s caller\n+\t\t\t\ts1 = s;\n+\t\t\t\tfindsym(pc, CTEXT, &s);\n+\t\t\t\t(*trace)(map, pc, sp, &s1);\t\t// morestack\'s caller; caller\'s caller\'s PC/SP\n+\t\t\t\tcontinue;\n+\t\t\t} else {\n+\t\t\t\twerrstr(\"morestack not implemented correctly\");\n+\t\t\t\treturn -1;\n+\t\t\t}\n \t\t}\
この変更は、i386trace
関数内のmorestack
に関連するデバッグコードの扱いを変更しています。元のコードでは、morestack
の処理がコメントアウトされており、その直後にwerrstr("morestack not implemented correctly"); return -1;
というエラー処理が記述されていました。
今回の変更では、コメントアウトされていたmorestack
のデバッグコード全体がif (0) { ... }
というブロックで囲まれました。これは、このコードブロックが決して実行されないことを明示的に示すための一般的なC言語のイディオムです。これにより、コンパイラは到達不能なコードとして認識し、関連する警告(例えば、未使用の変数や到達不能なコードパスに関する警告)を抑制することができます。
この変更の意図は、morestack
のデバッグコードが「古く、もはや動作しない」というコメントの通り、現状では使用されないことを明確にしつつ、将来的に必要になった場合に備えてコードを削除せずに残しておくことです。同時に、このコードブロックがコンパイル時に警告を生成しないようにすることで、ビルドプロセスのクリーンさを保っています。else
ブロックには、以前と同様のエラーメッセージと戻り値が記述されており、morestack
の処理が正しく実装されていない場合の挙動は維持されています。
コアとなるコードの変更箇所
include/bio.h
#define BGETC(bp)\
- ((bp)->icount?(bp)->ebuf[(bp)->icount++]:Bgetc((bp)))\
+ ((bp)->icount?(int)((bp)->ebuf[(bp)->icount++]):Bgetc((bp)))
src/libbio/bputrune.c
if(rune < Runeself) {
- BPUTC(bp, (int)rune);
+ n = BPUTC(bp, (int)rune);
+ USED(n);
return 1;
}
src/libmach/8db.c
if(s.value == morestack) {
- // This code is old and won't work anymore.
- // But no one uses it anyway.
- // Leave it obviously broken until someone needs it.
- werrstr("morestack not implemented correctly");
- return -1;
- // In the middle of morestack.
- // Caller is m->morepc.
- // Caller's caller is in m->morearg.
- // TODO(rsc): 386
- geta(map, offsetof(struct UregAmd64, r14), &m);
-
- pc = 0;
- sp = 0;
- pc1 = 0;
- s1 = s;
- memset(&s, 0, sizeof s);
- geta(map, m+1*mach->szaddr, &pc1); // m->morepc
- geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
- geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
- findsym(pc1, CTEXT, &s);
- (*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
-
- // caller's caller
- s1 = s;
- findsym(pc, CTEXT, &s);
- (*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
- continue;
+ if (0) {
+ // This code is old and won't work anymore.
+ // But no one uses it anyway.
+ // Leave it obviously broken until someone needs it.
+ // In the middle of morestack.
+ // Caller is m->morepc.
+ // Caller's caller is in m->morearg.
+ // TODO(rsc): 386
+ geta(map, offsetof(struct UregAmd64, r14), &m);
+
+ pc = 0;
+ sp = 0;
+ pc1 = 0;
+ s1 = s;
+ memset(&s, 0, sizeof s);
+ geta(map, m+1*mach->szaddr, &pc1); // m->morepc
+ geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
+ geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
+ findsym(pc1, CTEXT, &s);
+ (*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
+
+ // caller's caller
+ s1 = s;
+ findsym(pc, CTEXT, &s);
+ (*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
+ continue;
+ } else {
+ werrstr("morestack not implemented correctly");
+ return -1;
+ }
}
コアとなるコードの解説
include/bio.h
の変更
BGETC
マクロの変更は、ebuf[(bp)->icount++]
の戻り値がchar
型またはunsigned char
型である場合に、それがint
型を期待するコンテキストで使用される際に発生する可能性のある型変換に関する警告を抑制するためのものです。明示的に(int)
にキャストすることで、コンパイラに対してこの変換が意図的であることを伝え、警告を回避します。これは、C言語の型システムにおける厳密なチェックと、それによって発生する警告への対処法の一例です。
src/libbio/bputrune.c
の変更
bputrune.c
における変更は、BPUTC
マクロの戻り値が未使用であることに関する警告を抑制するためのものです。BPUTC
は通常、書き込んだバイト数などの情報を返しますが、このコンテキストではその戻り値が後続の処理で利用されていませんでした。Plan 9ツールチェインのような厳格なコンパイラは、このような未使用の戻り値に対して警告を発することがあります。n = BPUTC(...)
で戻り値を変数n
に代入し、さらにUSED(n)
マクロを適用することで、n
が意図的に使用されていないことをコンパイラに明示し、警告を抑制します。USED
マクロは、特にデバッグ目的や将来の拡張のために変数を残しつつ、現在のコンパイルで警告を出さないようにする際に有用です。
src/libmach/8db.c
の変更
8db.c
におけるmorestack
関連のコードの変更は、到達不能なコードに関する警告を抑制するためのものです。以前のコードでは、morestack
のデバッグロジックがコメントアウトされており、その直後にエラー処理が記述されていました。この状態では、コンパイラがコメントアウトされたコードブロックを認識せず、その後のエラー処理が常に実行されると判断し、到達不能なコードに関する警告を出す可能性がありました。
if (0) { ... } else { ... }
という構造にすることで、if (0)
の条件が常に偽であるため、{ ... }
内のコードブロックが実行されることはありません。これにより、コンパイラはこのブロック内のコードが意図的に無効化されていることを認識し、関連する警告(例えば、ブロック内の未使用変数や到達不能なコードパスに関する警告)を抑制します。この手法は、コードを削除せずに無効化し、将来の参照のために残しておく場合に非常に有効です。同時に、ビルド時の警告を減らし、クリーンなコンパイルを維持するのに役立ちます。
関連リンク
- https://golang.org/cl/73460043 (Go Gerrit Code Review)
参考にした情報源リンク
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Go言語のスタック管理 (morestack): https://go.dev/src/runtime/stack.go (Goソースコード内の
stack.go
はmorestack
の概念を理解する上で参考になりますが、直接的な変更箇所ではありません。) - C言語の
USED
マクロに関する一般的な情報 (Plan 9のドキュメントや関連するC言語の慣習): https://man.cat-v.org/plan_9/1/used (Plan 9のused
コマンドに関するマニュアルページですが、USED
マクロの意図を理解するのに役立ちます。) - C言語の型キャストと警告に関する一般的な情報 (C言語の標準やコンパイラのドキュメント)
- Go言語の初期の歴史とPlan 9の影響に関する情報 (Go言語の公式ブログや歴史に関する記事)
- https://go.dev/doc/faq#go_and_plan9 (Go FAQ: Is Go a Plan 9 system?)
- https://go.dev/talks/2012/go-and-plan9.slide (Go and Plan 9 by Rob Pike) I have generated the detailed explanation of the commit as requested.