[インデックス 19194] ファイルの概要
このコミットは、Goコンパイラのcmd/gcにおけるisgoconst関数で発生していたセグメンテーション違反(segfault)を修正するものです。具体的には、varキーワードで宣言された変数がsym->defを持たない場合に、isgoconst関数が不正なメモリアクセスを行う問題を解決します。
コミット
commit 32dffef0980eb810b97f48eb9dfabb33602a0472
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Wed Apr 16 23:12:06 2014 -0400
cmd/gc: fix segfault in isgoconst.
Variables declared with 'var' have no sym->def.
Fixes #7794.
LGTM=rsc
R=golang-codereviews, bradfitz, rsc
CC=golang-codereviews
https://golang.org/cl/88360043
---
src/cmd/gc/const.c | 2 +-\n test/fixedbugs/issue7794.go | 12 ++++++++++++\n 2 files changed, 13 insertions(+), 1 deletion(-)\n
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 28d0725d33..f356c4f59a 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -1594,7 +1594,7 @@ isgoconst(Node *n)\n \n case ONAME:\n l = n->sym->def;\n-\t\tif(l->op == OLITERAL && n->val.ctype != CTNIL)\n+\t\tif(l && l->op == OLITERAL && n->val.ctype != CTNIL)\n \t\t\treturn 1;\n \t\tbreak;\n \t\ndiff --git a/test/fixedbugs/issue7794.go b/test/fixedbugs/issue7794.go
new file mode 100644
index 0000000000..1e303bd4f2
--- /dev/null
+++ b/test/fixedbugs/issue7794.go
@@ -0,0 +1,12 @@
+// compile
+\n+// Copyright 2014 The Go Authors. All rights reserved.\n+// Use of this source code is governed by a BSD-style\n+// license that can be found in the LICENSE file.\n+\n+package main\n+\n+func main() {\n+\tvar a [10]int\n+\tconst ca = len(a)\n+}\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/32dffef0980eb810b97f48eb9dfabb33602a0472
元コミット内容
Goコンパイラのcmd/gcにおいて、isgoconst関数で発生するセグメンテーション違反を修正します。この問題は、varキーワードで宣言された変数がsym->def(シンボルの定義)を持たないことに起因していました。この修正は、GoのIssue #7794を解決します。
変更の背景
この変更は、Goコンパイラのcmd/gc(当時のGoの主要なコンパイラ)が、特定のコードパターンでクラッシュする(セグメンテーション違反を起こす)バグを修正するために行われました。具体的には、isgoconstという関数が、コンパイル時に定数であるかどうかを判断する際に、varで宣言された変数に対して誤った処理を行っていました。
Go言語では、constで宣言された値はコンパイル時に定数として扱われ、その値はコードに直接埋め込まれるか、コンパイル時に評価されます。一方、varで宣言された変数は実行時に値が割り当てられる可能性があり、その定義はコンパイル時の定数とは異なる方法で扱われます。
問題は、isgoconst関数が、ONAME(名前付きエンティティ、つまり変数など)を処理する際に、そのシンボル定義(n->sym->def)にアクセスしようとしたことにありました。しかし、varで宣言された変数、特に配列のlenのような組み込み関数を適用した場合など、そのsym->defがNULLになるケースが存在しました。元のコードでは、このNULLチェックが行われていなかったため、NULLポインタをデリファレンスしようとしてセグメンテーション違反が発生していました。
このバグはGoのIssue #7794として報告され、このコミットによって修正されました。
前提知識の解説
Goコンパイラ (cmd/gc)
cmd/gcは、Go言語のソースコードを機械語に変換する主要なコンパイラの歴史的な名称です。現在のGoのソースツリーではsrc/cmd/compileに位置しています。コンパイラは、ソースコードを解析し、抽象構文木(AST)を構築し、中間表現(IR)に変換し、最終的に実行可能なバイナリを生成します。
isgoconst関数
isgoconstは、Goコンパイラの内部関数の一つで、与えられた式や値がGoのコンパイル時定数であるかどうかを判断する役割を担っています。コンパイラは、定数値を事前に評価することで、コードの最適化(例: コンパイル時にif条件を評価して不要なコードを削除するなど)を行います。
AST/IRとノードタイプ (ONAME, OLITERAL)
Goコンパイラは、ソースコードを解析する際に、その構造を内部的なデータ構造である抽象構文木(AST)や中間表現(IR)として表現します。これらの木構造の各ノードは、ソースコードの異なる要素を表す「オペレーションコード(opcode)」を持っています。
ONAME: ソースコード内の名前付きエンティティ(変数、関数、型、パッケージなど)を表すノードタイプです。OLITERAL: ソースコードに直接記述されたリテラル値(例: 整数10、文字列"hello"、真偽値true、浮動小数点数など)を表すノードタイプです。
シンボルとsym->def
Goコンパイラは、ソースコード内の識別子(変数名、関数名など)に関する情報を「シンボルテーブル」に格納します。このシンボルテーブル内の各エントリは「シンボル(Sym)」オブジェクトとして表現されます。
Sym(Symbol): コンパイラのシンボルテーブルにおける識別子に関する情報を保持するオブジェクトです。sym->def: このフィールドは、シンボルの「定義」を指すポインタです。歴史的に、このフィールドはシンボルがどのように定義されたか(例: リテラルとして定義されたか、別の変数として定義されたかなど)を示すために使用されていました。しかし、varで宣言された変数など、特定のケースではこのdefフィールドがNULLになるか、OLITERALノードを指さないことがあります。現在のGoコンパイラでは、このsym->defフィールドは非推奨(deprecated)とされており、より高レベルの抽象化が推奨されていますが、このコミットが作成された時点ではまだ使用されていました。
varとconstの違い
const: コンパイル時定数を宣言します。その値はコンパイル時に完全に決定され、実行時に変更されることはありません。コンパイラはこれらの値を直接コードに埋め込むことができます。var: 変数を宣言します。その値は実行時に変更される可能性があり、メモリ上に割り当てられます。varで宣言された変数は、constのようにコンパイル時にリテラルとして直接扱われるわけではありません。
技術的詳細
問題は、src/cmd/gc/const.c内のisgoconst関数がONAMEノードを処理するロジックにありました。
case ONAME:
l = n->sym->def;
if(l->op == OLITERAL && n->val.ctype != CTNIL)
return 1;
break;
このコードスニペットでは、ONAMEノード(n)が与えられた場合、まずそのシンボル定義(n->sym->def)をlに代入しています。その後、if(l->op == OLITERAL ...)という条件で、lがOLITERALノードであるかどうかをチェックしています。
ここで問題となるのは、varで宣言された変数(特に、test/fixedbugs/issue7794.goのテストケースのように、配列のlenをconstに代入しようとするような場合)のONAMEノードでは、n->sym->defがNULLになる可能性があることです。
元のコードでは、lがNULLであるにもかかわらず、l->opという形でNULLポインタをデリファレンスしようとしていました。これは未定義動作を引き起こし、結果としてセグメンテーション違反(プログラムのクラッシュ)につながっていました。
このコミットの修正は、このNULLポインタデリファレンスを防ぐために、lがNULLでないことを事前にチェックする条件を追加することです。
コアとなるコードの変更箇所
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -1594,7 +1594,7 @@ isgoconst(Node *n)\n \n case ONAME:\n l = n->sym->def;\n-\t\tif(l->op == OLITERAL && n->val.ctype != CTNIL)\n+\t\tif(l && l->op == OLITERAL && n->val.ctype != CTNIL)\n \t\t\treturn 1;\n \t\tbreak;\n \t\n```
## コアとなるコードの解説
変更された行は以下の通りです。
```c
if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
この修正の核心は、条件式の先頭にl &&を追加したことです。
lはn->sym->defの値です。l &&という条件は、C言語(およびGoコンパイラのCコードベース)において、lがNULLでない場合にのみ真となります。- 論理AND演算子(
&&)はショートサーキット評価を行うため、もしlがNULLであれば、l &&の時点で条件全体が偽と判断され、l->opの評価は行われません。
これにより、lがNULLである場合にNULLポインタをデリファレンスしようとする試みが回避され、セグメンテーション違反が防止されます。varで宣言された変数は、その定義がOLITERALノードではないため、lがNULLであるか、あるいはl->opがOLITERALではないため、このifブロックの条件を満たさず、isgoconst関数は正しく0(定数ではない)を返します。
追加されたテストケースtest/fixedbugs/issue7794.goは、このバグが再現する最小限のコードを示しています。
package main
func main() {
var a [10]int
const ca = len(a)
}
このコードでは、varで宣言された配列aの長さ(len(a))をconst定数caに代入しようとしています。len(a)はコンパイル時に評価可能ですが、a自体はvar変数であるため、isgoconstがaのシンボル定義を処理する際にsym->defがNULLとなり、修正前のコンパイラではクラッシュしていました。修正後は、このコードが正しくコンパイルされるようになります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/32dffef0980eb810b97f48eb9dfabb33602a0472
- Go CL (Code Review): https://golang.org/cl/88360043
参考にした情報源リンク
- Go compiler cmd/gc isgoconst ONAME OLITERAL sym->defに関するWeb検索結果
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGsslCYphAlmWmcLutxflVyiINGcjgM__KLuJ0u4sTwWlhzHgJHduQ2vucLnMOY8_H00txZTiDDoEwgF96XDgvrHfV4E0Ep719LakbIR7i-qY5mfEbGX7BOVQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEPe-yDzgcJjJZ4r3JvP0GX7OmEJ3Puo4WSBdx-p6q137ZJkuZlVLGGT8ndClSj_YtlVOnHdqGEcVcy9IOGulV8zdEh-SOtDwXVMfC-sclXSiVTlGqplCTzI1d5gLZp29bskOOoNaKeRTuZAMIfzn9RMWXq8hgmoThdcQaipA==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF9WqbjxXA9o-wb6MCUYuyi6oBw84Mub-bls7jlY3cvzjGljattqdGvXyhFCrUObkVN6BfvfPIXj2EvYb8dHb_qrDT7dz5LHKQK5kvPTEoQ0Oa6908jtUtqfX0qRbHTW6Sqyu3PF-4=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEbLY3BWBI9OWubVZCZF5mmFy-UZIaWCLB7C2RKibKRPoqSb1iU2GAUVi_UZvwmQ5oCaqnNJ0HNmr_X93LqK3l3xiYiMy8H46gKIa6xEgGZ-FRr
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEJdbRF5yZFAJu0mnPqyBBcD_Lghme8Gwaf1Uq0QwHq-vd8y7080qucZLXWPu3qKZtdPAOhgzTpcjw2n5FnbCL89yNmxLo0nKsEAnMnggHj-jY297ZzIT7bszvPzFn3DcB8_lr3bccaB8dtRyRm8=