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

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

このコミットは、Go言語のコンパイラツールチェーンの一部であるcmd/5gディレクトリ内のgsubr.cファイルに対する修正です。具体的には、C言語のキーワードにおけるタイプミスを修正しています。

コミット

commit b1cb5f5dcb93893efe5cdca45828f5d9e9f2512d
Author: Russ Cox <rsc@golang.org>
Date:   Sat Jun 2 23:57:38 2012 -0400

    cmd/5g: fix typo
    
    TBR=lvd
    CC=golang-dev
    https://golang.org/cl/6275048

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

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

元コミット内容

cmd/5g: fix typo

変更の背景

このコミットは、Go言語のコンパイラの一部であるcmd/5g内のソースコードで発見された単純なタイプミスを修正することを目的としています。具体的には、src/cmd/5g/gsubr.cファイル内で、C言語の予約語であるvoidが誤ってbsdvoidと記述されていた箇所を修正しています。このようなタイプミスは、コンパイルエラーを引き起こすか、あるいはコンパイラが意図しない動作をする可能性があり、Goコンパイラの安定性と正確性を保つ上で重要な修正となります。

前提知識の解説

Goコンパイラとcmd/5g

Go言語は、そのコンパイラやツールチェーン自体もGo言語で書かれていることが多いですが、初期のGoコンパイラや、特に低レベルな部分(アセンブラやリンカなど)はC言語で実装されているものも存在します。 cmd/5gは、Go言語のコンパイラツールチェーンの一部であり、具体的にはARMアーキテクチャ(特にARMv5/v6)向けのGoコンパイラを指します。Go言語のコンパイラは、ターゲットアーキテクチャごとに異なる名前が付けられており、例えば6gはamd64向け、8gは386向け、5gはarm向けといった具合です。これらのコンパイラは、Goのソースコードを各アーキテクチャの機械語に変換する役割を担っています。

C言語のvoidキーワード

C言語におけるvoidキーワードは、非常に多岐にわたる用途を持つ重要な型指定子です。

  1. 関数の戻り値の型: 関数が何も値を返さないことを示します。
    void print_message() {
        // 何も返さない
    }
    
  2. 関数の引数: 関数が引数を取らないことを明示的に示します。C++では空の括弧()が引数なしを意味しますが、C言語では()は「引数の型が指定されていない(可変引数かもしれない)」という意味になるため、引数を取らないことを明確にするにはvoidを使用します。
    int main(void) {
        // 引数を取らない
        return 0;
    }
    
  3. 汎用ポインタ (void*): 任意の型のデータを指すことができる汎用ポインタです。void*は、特定のデータ型にキャストされるまで直接デリファレンス(間接参照)することはできません。mallocmemcpyのようなメモリ操作関数でよく使用されます。
    void *ptr; // 任意の型を指すことができるポインタ
    int *int_ptr;
    int_ptr = (int *)ptr; // int型にキャスト
    

このコミットで修正されたbsdvoidという記述は、C言語の標準には存在しないキーワードです。おそらく、voidとタイプミスされたものと考えられます。

技術的詳細

このコミットの技術的詳細は、C言語の構文とGoコンパイラの内部構造に深く関連しています。

src/cmd/5g/gsubr.cファイルは、GoコンパイラのARMバックエンドにおける汎用サブルーチン(general subroutines)を実装しているC言語のソースファイルです。このファイルには、コード生成や最適化に関連する低レベルな処理が含まれています。

問題の箇所は、checkrefという関数の定義部分です。この関数は、Go言語のnilポインタデリファレンス(nil pointer dereference)時にセグメンテーション違反(segmentation fault, segv)を強制的に発生させるための命令を生成する役割を担っています。これは、Goランタイムがnilポインタアクセスを検出し、プログラムをクラッシュさせることで、プログラマにバグを知らせるための重要なメカニズムの一部です。

元のコードでは、checkref関数の戻り値の型がbsdvoidと誤って記述されていました。C言語のコンパイラは、bsdvoidという型を認識しないため、このコードはコンパイルエラーとなるか、あるいは特定のコンパイラ設定や環境下では警告を出しつつも、未定義の動作を引き起こす可能性がありました。Goコンパイラのような基盤となるツールチェーンにおいて、このような構文エラーは致命的であり、コンパイラ自体のビルド失敗や、生成されるバイナリの不正な動作に直結します。

修正は、この誤ったbsdvoidを正しいC言語のキーワードであるvoidに置き換えるという非常にシンプルなものです。これにより、checkref関数が値を返さない関数として正しく定義され、Cコンパイラによって正常にコンパイルされるようになります。この修正は、Goコンパイラのビルドプロセスを安定させ、生成されるGoプログラムのnilポインタデリファレンス時の挙動が意図通りになることを保証します。

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

--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1143,7 +1143,7 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
 
 // Generate an instruction referencing *n
 // to force segv on nil pointer dereference.
-bsdvoid
+void
 checkref(Node *n)
 {
 	Node m1, m2;

コアとなるコードの解説

変更箇所は、src/cmd/5g/gsubr.cファイルの1144行目です。

  • - bsdvoid: 変更前の行で、checkref関数の戻り値の型がbsdvoidと誤って記述されていました。これはC言語の有効なキーワードではありません。
  • + void: 変更後の行で、bsdvoidが正しいC言語のキーワードであるvoidに修正されています。

このcheckref関数は、コメントにもあるように「nilポインタデリファレンス時にsegvを強制するための命令を生成する」役割を持っています。Go言語では、nilポインタへのアクセスはランタイムエラー(パニック)を引き起こしますが、その低レベルな実装の一部として、C言語で書かれたコンパイラが特定の命令を挿入し、OSレベルでのセグメンテーション違反をトリガーすることがあります。この関数は、そのためのコード生成ロジックの一部です。

void checkref(Node *n)という関数シグネチャは、checkref関数がNode型のポインタnを引数として受け取り、何も値を返さない(void)ことを示しています。この修正により、Cコンパイラはcheckref関数の定義を正しく解釈し、Goコンパイラのビルドが正常に完了するようになります。

関連リンク

参考にした情報源リンク