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

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

このコミットは、Goコンパイラ(cmd/gc)において、定数によるゼロ除算をコンパイル時にエラーとして検出するように変更を加えるものです。具体的には、整数型の定数ゼロによる除算(ODIV)または剰余演算(OMOD)が検出された場合に、コンパイルエラーを発生させるようになります。これにより、実行時パニックを未然に防ぎ、より堅牢なコードの作成を支援します。

コミット

commit ba05a436084376d0b17acb0fdde0a7bc78ab2fc1
Author: Daniel Morsing <daniel.morsing@gmail.com>
Date:   Wed Jan 30 20:21:08 2013 +0100

    cmd/gc: Error out on division by constant zero.
    
    Fixes #4264.
    
    R=cldorian, rsc
    CC=golang-dev
    https://golang.org/cl/6845113

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

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

元コミット内容

cmd/gc: Error out on division by constant zero.cmd/gc: 定数ゼロによる除算でエラーを出すようにする。)

Fixes #4264. (Issue #4264 を修正。)

変更の背景

Go言語において、実行時にゼロ除算が発生するとパニック(panic: runtime error: integer divide by zero)が発生し、プログラムが異常終了します。特に、除算のオペランドがコンパイル時に値が確定している定数である場合、このゼロ除算はコンパイル時に検出可能であるべきです。

このコミットが修正するIssue #4264は、まさにこの問題点を指摘しています。Goコンパイラが、定数ゼロによる除算をコンパイル時に捕捉せず、実行時エラーとして扱っていたため、開発者は意図しないパニックに遭遇する可能性がありました。コンパイラが早期にこのようなエラーを検出することで、開発者はより安全で信頼性の高いコードを記述できるようになります。これは、Go言語の設計哲学である「シンプルさ」と「安全性」に合致する改善です。

前提知識の解説

  • Goコンパイラ (cmd/gc): Go言語の公式コンパイラの一つで、Goソースコードを機械語に変換する役割を担います。コンパイルの過程で、構文解析、型チェック、最適化など様々な処理が行われます。
  • 型チェック (Type Checking): プログラムの各部分が期待されるデータ型と一致しているかを確認するプロセスです。これにより、型に関するエラー(例: 整数と文字列の加算)をコンパイル時に検出できます。
  • 定数 (Constants): プログラムの実行中に値が変わらない固定された値です。Goでは、constキーワードで宣言されます。定数の値はコンパイル時に決定されます。
  • ゼロ除算 (Division by Zero): 数学的に未定義の操作であり、プログラミングにおいては通常、エラーや例外、パニックの原因となります。
  • 抽象構文木 (Abstract Syntax Tree - AST): ソースコードの抽象的な構文構造を木構造で表現したものです。コンパイラはソースコードをASTに変換し、このASTを操作して様々な解析や変換を行います。typecheck.cは、このAST上での型チェックを担当する部分です。
  • ODIV, OMOD: Goコンパイラの内部表現における演算子の種類です。ODIVは除算(/)を、OMODは剰余演算子(%)を表します。
  • isconst(r, CTINT): Goコンパイラの内部関数で、与えられたノード r が整数型の定数であるかどうかを判定します。
  • mpcmpfixc(r->val.u.xval, 0): Goコンパイラの内部関数で、多倍長整数(mpはmulti-precisionの略)の比較を行います。r->val.u.xvalは定数ノード r の値(多倍長整数形式)を指し、これをゼロと比較します。結果が0であれば、r の値がゼロであることを意味します。
  • yyerror("division by zero"): Goコンパイラの内部関数で、コンパイルエラーメッセージを出力します。yyerrorは通常、yaccbisonのようなパーサジェネレータによって生成されたコードで使用されるエラー報告関数です。

技術的詳細

この変更は、Goコンパイラの型チェックフェーズで行われます。具体的には、src/cmd/gc/typecheck.c ファイル内のtypecheck関数(またはその関連ロジック)に、除算または剰余演算の右オペランドが定数ゼロであるかをチェックするロジックが追加されています。

変更の核心は以下の条件分岐です。

if((op == ODIV || op == OMOD) && isconst(r, CTINT))
if(mpcmpfixc(r->val.u.xval, 0) == 0) {
    yyerror("division by zero");
    goto error;
}
  1. op == ODIV || op == OMOD: 現在処理している演算が除算(/)または剰余演算(%)であるかを確認します。
  2. isconst(r, CTINT): 演算の右オペランド r が整数型の定数であるかを確認します。
  3. mpcmpfixc(r->val.u.xval, 0) == 0: 右オペランド r の値がゼロであるかを確認します。mpcmpfixcは多倍長整数を比較する関数で、結果が0であれば両者が等しいことを意味します。

これら3つの条件がすべて真である場合、つまり「整数型の定数ゼロによる除算または剰余演算」が検出された場合に、yyerror("division by zero")を呼び出してコンパイルエラーメッセージを出力し、goto error;によってエラー処理ルーチンへジャンプします。これにより、コンパイルが中断され、ユーザーに問題が通知されます。

この変更は、コンパイラのフロントエンドに近い部分で行われるため、実行時ではなくコンパイル時にエラーを捕捉できる点が重要です。これにより、デバッグが容易になり、プログラムの信頼性が向上します。

また、テストケースも追加・修正されています。

  • test/64bit.go: 64ビット整数に関する定数テストで、ゼロ除算を避けるための条件分岐が追加されています。これは、テストコード自体がゼロ除算エラーを発生させないようにするための調整です。
  • test/fixedbugs/bug410.go: 既存のバグ修正テストファイルで、誤ってゼロ除算を引き起こしていた箇所が修正されています。これは、このコミットの直接的な修正とは異なりますが、関連するゼロ除算のテストケースとして修正された可能性があります。
  • test/fixedbugs/issue4264.go: 新たに作成されたテストファイルで、このコミットが修正するIssue #4264の具体的なシナリオをテストします。このファイルは、println(x/0)のようなコードがコンパイルエラーになることを期待しています。// errorcheckコメントは、コンパイラが特定のエラーメッセージを出力することを期待するテストであることを示します。

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

src/cmd/gc/typecheck.c ファイルの reswitch: ラベルの直後、またはその近くに以下のコードが追加されています。

--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -640,6 +640,13 @@ reswitch:
 			n->op = OCMPIFACE;
 		}
 	}
+
+	if((op == ODIV || op == OMOD) && isconst(r, CTINT))
+	if(mpcmpfixc(r->val.u.xval, 0) == 0) {
+		yyerror("division by zero");
+		goto error;
+	}
+
 	n->type = t;
 	goto ret;

コアとなるコードの解説

追加されたコードブロックは、Goコンパイラの型チェックフェーズにおいて、特定の条件が満たされた場合にコンパイルエラーを発生させるためのものです。

  1. if((op == ODIV || op == OMOD) && isconst(r, CTINT)):

    • op == ODIV || op == OMOD: 現在処理中の抽象構文木(AST)ノードが、除算(/)または剰余演算子(%)を表しているかどうかをチェックします。
    • isconst(r, CTINT): 演算の右オペランド(除数または剰余の基数)が、整数型の定数であるかどうかをチェックします。r は右オペランドを表すASTノードです。
    • この行は、まず「整数型の定数による除算または剰余演算」の可能性を絞り込みます。
  2. if(mpcmpfixc(r->val.u.xval, 0) == 0) { ... }:

    • この内側のif文は、外側の条件が真であった場合にのみ評価されます。
    • mpcmpfixc(r->val.u.xval, 0) == 0: 右オペランド r の具体的な値がゼロであるかどうかをチェックします。r->val.u.xvalは、定数ノードrが保持する多倍長整数値へのポインタです。mpcmpfixc関数は2つの多倍長整数を比較し、等しい場合に0を返します。
    • この行が真である場合、それは「整数型の定数ゼロによる除算または剰余演算」が実際に発生していることを意味します。
  3. yyerror("division by zero");:

    • 上記の条件がすべて満たされた場合、この関数が呼び出され、コンパイラの標準エラー出力に「division by zero」というエラーメッセージを出力します。これは、ユーザーにコンパイルエラーとして報告されます。
  4. goto error;:

    • エラーメッセージの出力後、このgoto文によって、現在の型チェック処理を中断し、エラー処理ルーチンへと制御を移します。これにより、コンパイルプロセスが停止し、エラーが報告されます。

このコードは、コンパイル時に静的に検出できるゼロ除算のケースを特定し、実行時パニックを未然に防ぐための重要な安全策をGoコンパイラに組み込んでいます。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/cmd/gc/typecheck.c および関連するテストファイル)
  • Go言語のIssueトラッカー (Issue #4264)
  • Go言語のCode Reviewサイト (CL 6845113)
  • Go言語のコンパイラに関する一般的な知識 (型チェック、ASTなど)
  • 多倍長整数演算に関する一般的な知識 (mpcmpfixcなど)

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

このコミットは、Goコンパイラ(cmd/gc)において、定数によるゼロ除算をコンパイル時にエラーとして検出するように変更を加えるものです。具体的には、整数型の定数ゼロによる除算(ODIV)または剰余演算(OMOD)が検出された場合に、コンパイルエラーを発生させるようになります。これにより、実行時パニックを未然に防ぎ、より堅牢なコードの作成を支援します。

コミット

commit ba05a436084376d0b17acb0fdde0a7bc78ab2fc1
Author: Daniel Morsing <daniel.morsing@gmail.com>
Date:   Wed Jan 30 20:21:08 2013 +0100

    cmd/gc: Error out on division by constant zero.
    
    Fixes #4264.
    
    R=cldorian, rsc
    CC=golang-dev
    https://golang.org/cl/6845113

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

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

元コミット内容

cmd/gc: Error out on division by constant zero.cmd/gc: 定数ゼロによる除算でエラーを出すようにする。)

Fixes #4264. (Issue #4264 を修正。)

変更の背景

Go言語において、実行時にゼロ除算が発生するとパニック(panic: runtime error: integer divide by zero)が発生し、プログラムが異常終了します。特に、除算のオペランドがコンパイル時に値が確定している定数である場合、このゼロ除算はコンパイル時に検出可能であるべきです。

このコミットが修正するIssue #4264は、まさにこの問題点を指摘しています。Goコンパイラが、定数ゼロによる除算をコンパイル時に捕捉せず、実行時エラーとして扱っていたため、開発者は意図しないパニックに遭遇する可能性がありました。コンパイラが早期にこのようなエラーを検出することで、開発者はより安全で信頼性の高いコードを記述できるようになります。これは、Go言語の設計哲学である「シンプルさ」と「安全性」に合致する改善です。

前提知識の解説

  • Goコンパイラ (cmd/gc): Go言語の公式コンパイラの一つで、Goソースコードを機械語に変換する役割を担います。コンパイルの過程で、構文解析、型チェック、最適化など様々な処理が行われます。
  • 型チェック (Type Checking): プログラムの各部分が期待されるデータ型と一致しているかを確認するプロセスです。これにより、型に関するエラー(例: 整数と文字列の加算)をコンパイル時に検出できます。
  • 定数 (Constants): プログラムの実行中に値が変わらない固定された値です。Goでは、constキーワードで宣言されます。定数の値はコンパイル時に決定されます。
  • ゼロ除算 (Division by Zero): 数学的に未定義の操作であり、プログラミングにおいては通常、エラーや例外、パニックの原因となります。
  • 抽象構文木 (Abstract Syntax Tree - AST): ソースコードの抽象的な構文構造を木構造で表現したものです。コンパイラはソースコードをASTに変換し、このASTを操作して様々な解析や変換を行います。typecheck.cは、このAST上での型チェックを担当する部分です。
  • ODIV, OMOD: Goコンパイラの内部表現における演算子の種類です。ODIVは除算(/)を、OMODは剰余演算子(%)を表します。
  • isconst(r, CTINT): Goコンパイラの内部関数で、与えられたノード r が整数型の定数であるかどうかを判定します。
  • mpcmpfixc(r->val.u.xval, 0): Goコンパイラの内部関数で、多倍長整数(mpはmulti-precisionの略)の比較を行います。r->val.u.xvalは定数ノード r の値(多倍長整数形式)を指し、これをゼロと比較します。結果が0であれば、r の値がゼロであることを意味します。
  • **yyerror("division by zero")**: Goコンパイラの内部関数で、コンパイルエラーメッセージを出力します。yyerrorは通常、yaccbison`のようなパーサジェネレータによって生成されたコードで使用されるエラー報告関数です。

技術的詳細

この変更は、Goコンパイラの型チェックフェーズで行われます。具体的には、src/cmd/gc/typecheck.c ファイル内のtypecheck関数(またはその関連ロジック)に、除算または剰余演算の右オペランドが定数ゼロであるかをチェックするロジックが追加されています。

変更の核心は以下の条件分岐です。

if((op == ODIV || op == OMOD) && isconst(r, CTINT))
if(mpcmpfixc(r->val.u.xval, 0) == 0) {
    yyerror("division by zero");
    goto error;
}
  1. op == ODIV || op == OMOD: 現在処理している演算が除算(/)または剰余演算(%)であるかを確認します。
  2. isconst(r, CTINT): 演算の右オペランド r が整数型の定数であるかを確認します。
  3. mpcmpfixc(r->val.u.xval, 0) == 0: 右オペランド r の値がゼロであるかを確認します。mpcmpfixcは多倍長整数を比較する関数で、結果が0であれば両者が等しいことを意味します。

これら3つの条件がすべて真である場合、つまり「整数型の定数ゼロによる除算または剰余演算」が検出された場合に、yyerror("division by zero")を呼び出してコンパイルエラーメッセージを出力し、goto error;によってエラー処理ルーチンへジャンプします。これにより、コンパイルが中断され、ユーザーに問題が通知されます。

この変更は、コンパイラのフロントエンドに近い部分で行われるため、実行時ではなくコンパイル時にエラーを捕捉できる点が重要です。これにより、デバッグが容易になり、プログラムの信頼性が向上します。

また、テストケースも追加・修正されています。

  • test/64bit.go: 64ビット整数に関する定数テストで、ゼロ除算を避けるための条件分岐が追加されています。これは、テストコード自体がゼロ除算エラーを発生させないようにするための調整です。
  • test/fixedbugs/bug410.go: 既存のバグ修正テストファイルで、誤ってゼロ除算を引き起こしていた箇所が修正されています。これは、このコミットの直接的な修正とは異なりますが、関連するゼロ除算のテストケースとして修正された可能性があります。
  • test/fixedbugs/issue4264.go: 新たに作成されたテストファイルで、このコミットが修正するIssue #4264の具体的なシナリオをテストします。このファイルは、println(x/0)のようなコードがコンパイルエラーになることを期待しています。// errorcheckコメントは、コンパイラが特定のエラーメッセージを出力することを期待するテストであることを示します。

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

src/cmd/gc/typecheck.c ファイルの reswitch: ラベルの直後、またはその近くに以下のコードが追加されています。

--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -640,6 +640,13 @@ reswitch:
 			n->op = OCMPIFACE;
 		}
 	}
+
+	if((op == ODIV || op == OMOD) && isconst(r, CTINT))
+	if(mpcmpfixc(r->val.u.xval, 0) == 0) {
+		yyerror("division by zero");
+		goto error;
+	}
+
 	n->type = t;
 	goto ret;

コアとなるコードの解説

追加されたコードブロックは、Goコンパイラの型チェックフェーズにおいて、特定の条件が満たされた場合にコンパイルエラーを発生させるためのものです。

  1. if((op == ODIV || op == OMOD) && isconst(r, CTINT)):

    • op == ODIV || op == OMOD: 現在処理中の抽象構文木(AST)ノードが、除算(/)または剰余演算子(%)を表しているかどうかをチェックします。
    • isconst(r, CTINT): 演算の右オペランド(除数または剰余の基数)が、整数型の定数であるかどうかをチェックします。r は右オペランドを表すASTノードです。
    • この行は、まず「整数型の定数による除算または剰余演算」の可能性を絞り込みます。
  2. if(mpcmpfixc(r->val.u.xval, 0) == 0) { ... }:

    • この内側のif文は、外側の条件が真であった場合にのみ評価されます。
    • mpcmpfixc(r->val.u.xval, 0) == 0: 右オペランド r の具体的な値がゼロであるかどうかをチェックします。r->val.u.xvalは、定数ノードrが保持する多倍長整数値へのポインタです。mpcmpfixc関数は2つの多倍長整数を比較し、等しい場合に0を返します。
    • この行が真である場合、それは「整数型の定数ゼロによる除算または剰余演算」が実際に発生していることを意味します。
  3. yyerror("division by zero");:

    • 上記の条件がすべて満たされた場合、この関数が呼び出され、コンパイラの標準エラー出力に「division by zero」というエラーメッセージを出力します。これは、ユーザーにコンパイルエラーとして報告されます。
  4. goto error;:

    • エラーメッセージの出力後、このgoto文によって、現在の型チェック処理を中断し、エラー処理ルーチンへと制御を移します。これにより、コンパイルプロセスが停止し、エラーが報告されます。

このコードは、コンパイル時に静的に検出できるゼロ除算のケースを特定し、実行時パニックを未然に防ぐための重要な安全策をGoコンパイラに組み込んでいます。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/cmd/gc/typecheck.c および関連するテストファイル)
  • Go言語のIssueトラッカー (Issue #4264)
  • Go言語のCode Reviewサイト (CL 6845113)
  • Go言語のコンパイラに関する一般的な知識 (型チェック、ASTなど)
  • 多倍長整数演算に関する一般的な知識 (mpcmpfixcなど)