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

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

このコミットは、Go言語のランタイムライブラリであるlibbiolibmachにおける、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.hsrc/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.cBPUTCの戻り値が使用されていないという警告を抑制するために追加されています。

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)の条件が常に偽であるため、{ ... }内のコードブロックが実行されることはありません。これにより、コンパイラはこのブロック内のコードが意図的に無効化されていることを認識し、関連する警告(例えば、ブロック内の未使用変数や到達不能なコードパスに関する警告)を抑制します。この手法は、コードを削除せずに無効化し、将来の参照のために残しておく場合に非常に有効です。同時に、ビルド時の警告を減らし、クリーンなコンパイルを維持するのに役立ちます。

関連リンク

参考にした情報源リンク

  • Plan 9 from Bell Labs: https://9p.io/plan9/
  • Go言語のスタック管理 (morestack): https://go.dev/src/runtime/stack.go (Goソースコード内のstack.gomorestackの概念を理解する上で参考になりますが、直接的な変更箇所ではありません。)
  • C言語のUSEDマクロに関する一般的な情報 (Plan 9のドキュメントや関連するC言語の慣習): https://man.cat-v.org/plan_9/1/used (Plan 9のusedコマンドに関するマニュアルページですが、USEDマクロの意図を理解するのに役立ちます。)
  • C言語の型キャストと警告に関する一般的な情報 (C言語の標準やコンパイラのドキュメント)
  • Go言語の初期の歴史とPlan 9の影響に関する情報 (Go言語の公式ブログや歴史に関する記事)