[インデックス 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=