[インデックス 18828] ファイルの概要
このコミットは、Goランタイムにおけるnacl/amd64p32
アーキテクチャ向けのシグナルハンドリングの不具合を修正するものです。具体的には、以前の変更(CL 15790043)が正しくマージされなかったことによる問題を再適用し、ファイル名を変更し、適切なビルドタグを追加することで、シグナルハンドリングが正しく機能するようにしています。
コミット
commit 053127b12f4ad04417f3d26b0acbf91e9a9c1a6a
Author: Dave Cheney <dave@cheney.net>
Date: Wed Mar 12 07:21:55 2014 +1100
runtime: fix nacl/amd64p32 signal handling
The change to signal_amd64.c from CL 15790043 was not merged correctly.
This CL reapplies the change, renaming the file to signal_amd64x.c and adds the appropriate build tags.
LGTM=iant, bradfitz
R=rsc, iant, bradfitz
CC=golang-codereviews
https://golang.org/cl/72790043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/053127b12f4ad04417f3d26b0acbf91e9a9c1a6a
元コミット内容
このコミットは、以前のCL 15790043で導入されたsignal_amd64.c
への変更が正しくマージされなかったことに対する再適用です。元のCL 15790043は「runtime: fix stack re-scan during stack growth」というタイトルで、スタックの成長中に不要なスタックの再スキャンが行われる問題を修正することを目的としていました。
変更の背景
このコミットの背景には、Goランタイムのシグナルハンドリングにおける特定のアーキテクチャ(nacl/amd64p32
)での問題があります。
- CL 15790043のマージ問題: 以前のコミット(CL 15790043)で
signal_amd64.c
ファイルに対して行われた変更が、何らかの理由でGoのリポジトリに正しくマージされませんでした。これにより、その変更が意図していた修正が適用されていない状態が続いていました。 nacl/amd64p32
特有のシグナルハンドリング:nacl/amd64p32
は、Google Native Client (NaCl) 環境におけるamd64
アーキテクチャで、ポインタサイズが32ビットであるという特殊な環境です。NaClはサンドボックス化された環境であり、通常のOSとは異なるシグナル処理のメカニズムを持つため、Goランタイムはこれに合わせた特別なハンドリングを必要とします。正しくマージされなかった変更は、この特殊な環境でのシグナルハンドリングの正確性に影響を与えていたと考えられます。- 問題の再修正: このコミットは、正しくマージされなかった変更を再適用することで、
nacl/amd64p32
環境でのシグナルハンドリングの不具合を解消することを目的としています。ファイル名をsignal_amd64x.c
に変更し、適切なビルドタグを追加することで、特定の環境でのみこの修正が適用されるようにしています。
前提知識の解説
Goランタイムとシグナルハンドリング
Goプログラムは、オペレーティングシステムからのシグナル(例: SIGTERM
、SIGINT
、SIGSEGV
など)を処理するために、os/signal
パッケージとGoランタイムの内部メカニズムを利用します。
os/signal
パッケージ: Goプログラムが特定のシグナルを受信した際に通知を受け取るための高レベルなインターフェースを提供します。- Goランタイムの役割: ランタイムは、プロファイリング(
SIGPROF
)や同期シグナル(SIGBUS
、SIGFPE
、SIGSEGV
など、プログラムエラーによって引き起こされるもの)の処理のために、独自のシグナルハンドラをインストールします。シグナルが受信されると、ランタイムの内部gsignal
ゴルーチンがそれを処理し、必要に応じてos/signal.Notify()
で登録されたチャネルに委譲します。
nacl/amd64p32
アーキテクチャ
- Native Client (NaCl): Googleが開発した、ウェブブラウザ内でコンパイルされたC/C++コードを安全に実行するためのサンドボックス環境です。セキュリティモデルが厳格であり、低レベルなシステムインタラクション(シグナル配信を含む)が仮想化または制限されます。
amd64p32
: 64ビットのAMDプロセッサを対象としながらも、ポインタサイズが32ビットであるという特殊なアーキテクチャです。これは、メモリ使用量を抑えつつ64ビットのレジスタセットを利用したい場合に用いられることがあります。- NaCl環境でのシグナルハンドリングの課題: NaClのサンドボックス化された性質は、シグナルハンドリングに大きな影響を与えます。従来のOSとは異なり、プロセスがカーネルのシグナルメカニズムと直接対話することはできません。NaClランタイム自体がシグナルに似たイベントを仲介するため、Goランタイムのシグナルハンドラの実装は、このサンドボックス環境の制約に適応する必要があります。特に、メモリアクセス違反(
SIGSEGV
)などの低レベルな問題は、NaClサンドボックス内でシグナルとして現れる可能性があり、その処理は複雑になることがあります。
uintreg
とuintptr
uintptr
: Goにおけるポインタ型で、任意のポインタを保持できる整数型です。ポインタ演算には使用できませんが、ポインタの値を整数として扱う際に用いられます。そのサイズは、実行環境のポインタサイズ(32ビットまたは64ビット)に依存します。uintreg
: このコンテキストでは、レジスタの値を保持するための型を指していると考えられます。特定のアーキテクチャやコンテキストにおいて、レジスタのサイズがポインタのサイズと異なる場合があります。例えば、64ビットアーキテクチャで32ビットポインタを使用する場合、レジスタは64ビット幅を持つが、ポインタは32ビット幅となります。
技術的詳細
このコミットの技術的な変更点は以下の通りです。
-
ファイル名の変更:
src/pkg/runtime/signal_amd64.c
からsrc/pkg/runtime/signal_amd64x.c
へファイル名が変更されました。- この変更は、特定のアーキテクチャやビルド環境に特化したコードであることを明確にするため、または以前の変更との競合を避けるために行われた可能性があります。
-
ビルドタグの追加:
- 元のファイルには
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
というビルドタグがありました。 - 変更後のファイルには、これに加えて
// +build amd64 amd64p32
と// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
という2つのビルドタグが追加されました。 +build amd64 amd64p32
タグは、このファイルがamd64
およびamd64p32
アーキテクチャ向けにビルドされることを示します。+build nacl
タグの追加は、このシグナルハンドリングの修正がNative Client環境に特に関連していることを明示しています。これにより、Goのビルドシステムは、これらの特定の環境でビルドする際にのみこのファイルを含めるようになります。
- 元のファイルには
-
シグナルハンドリングロジックの修正:
runtime·sighandler
関数内で、シグナルコンテキスト(ctxt
)から取得した命令ポインタ(SIG_RIP
)とスタックポインタ(SIG_RSP
)を処理する部分に修正が加えられました。- 具体的には、
SIG_RSP(info, ctxt)
から取得したスタックポインタsp
に対して、以下の条件付きのコードが追加されました。if(sizeof(uintreg) > sizeof(uintptr)) *--sp = 0;
- このコードは、レジスタのサイズ(
uintreg
)がポインタのサイズ(uintptr
)よりも大きい場合に、スタックにゼロをプッシュするものです。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/signal_amd64.c
+++ b/src/pkg/runtime/signal_amd64x.c
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -89,6 +90,8 @@ runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
// won\'t get to see who faulted.)
if(SIG_RIP(info, ctxt) != 0) {
sp = (uintptr*)SIG_RSP(info, ctxt);
+ if(sizeof(uintreg) > sizeof(uintptr))\n+ *--sp = 0;
*--sp = SIG_RIP(info, ctxt);
SIG_RSP(info, ctxt) = (uintptr)sp;
}
コアとなるコードの解説
このコミットの最も重要なコード変更は、runtime·sighandler
関数内の以下の部分です。
sp = (uintptr*)SIG_RSP(info, ctxt);
if(sizeof(uintreg) > sizeof(uintptr))
*--sp = 0;
*--sp = SIG_RIP(info, ctxt);
SIG_RSP(info, ctxt) = (uintptr)sp;
このコードブロックは、シグナルハンドラが呼び出された際に、シグナル発生時のコンテキスト(特に命令ポインタとスタックポインタ)を適切に処理するためのものです。
-
sp = (uintptr*)SIG_RSP(info, ctxt);
- シグナル情報(
info
)とコンテキスト(ctxt
)から、シグナル発生時のスタックポインタ(SIG_RSP
)を取得し、それをuintptr
型のポインタとしてsp
に格納します。これは、スタックに値をプッシュするために使用されます。
- シグナル情報(
-
if(sizeof(uintreg) > sizeof(uintptr))
- この条件文は、レジスタのサイズ(
uintreg
)がポインタのサイズ(uintptr
)よりも大きい場合に真となります。 - これは、特に
amd64p32
のような環境で重要です。amd64
アーキテクチャではレジスタが64ビット幅ですが、amd64p32
ではポインタが32ビット幅です。このような場合、レジスタの完全な値をスタックに保存する際に、ポインタサイズとの不一致による問題が発生する可能性があります。
- この条件文は、レジスタのサイズ(
-
*--sp = 0;
- 上記の条件が真の場合、つまりレジスタサイズがポインタサイズよりも大きい場合に、スタックポインタをデクリメント(スタックを拡張)し、その新しい位置に
0
をプッシュします。 - この操作の目的は、レジスタの値をスタックに保存する際に、パディング(埋め草)を提供することであると考えられます。例えば、64ビットレジスタの値を32ビットポインタのスタックに保存する場合、上位32ビットが失われる可能性があります。この
0
のプッシュは、スタックアライメントを維持したり、あるいはレジスタの完全な値を保存するためのスペースを確保したりする役割を果たす可能性があります。これにより、シグナルからの復帰時にレジスタの状態が正しく復元されることを保証します。
- 上記の条件が真の場合、つまりレジスタサイズがポインタサイズよりも大きい場合に、スタックポインタをデクリメント(スタックを拡張)し、その新しい位置に
-
*--sp = SIG_RIP(info, ctxt);
- 次に、シグナル発生時の命令ポインタ(
SIG_RIP
)をスタックにプッシュします。これは、シグナルハンドラから復帰した際に、プログラムが中断された正確な場所から実行を再開するために不可欠です。
- 次に、シグナル発生時の命令ポインタ(
-
SIG_RSP(info, ctxt) = (uintptr)sp;
- 最後に、更新されたスタックポインタ
sp
の値をシグナルコンテキストに書き戻します。これにより、シグナルハンドラが終了した後に、OSが正しいスタックポインタを使用してプログラムの実行を再開できるようになります。
- 最後に、更新されたスタックポインタ
この修正は、特にnacl/amd64p32
のような特殊なアーキテクチャにおいて、シグナルハンドリングがレジスタとポインタのサイズの違いを適切に考慮し、スタックの状態を正確に維持することを保証するために重要です。これにより、シグナル発生時のプログラムの状態が破損することなく、安定した動作が期待されます。
関連リンク
- Go CL 72790043: https://golang.org/cl/72790043
参考にした情報源リンク
-
Goの
os/signal
パッケージとシグナルハンドリングに関する情報:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHrioic1-pgR9olMQGzLTE0uFYBGr7KM_E1FR61Qf2qpkLxPTvLBVFxsXYE1pmlp3wsVyABhbZeDtjQT108rKfMp4YrmvnHpvd6FMyCYNSAnN56zxlSQA0_0eZgjhVQUAh5DN_hf3FaJTC3VnkFKz-nqYfKQaOg5H08QpEIy3YVWyacSzHi9vU=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHmju41XrbJlOSJnRf07_eE3vGrH3tddxQwaSNdE5W7OKbyN498J_IxNTA3pnwpQY7Q6X_LjUb53tRDZS1YoD1hUy7l1sbX9oUIlgwPH9JnpQJtdFoN6QNxRBKhU611bAeaenuM8Miy9QJXyPqWu3XHnPh8a7wg-UzZeRZgAZQ=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHYUf_LsE0negDiN_RrAh6sFJkxcdTEyc5bgsRY6croNMlLp0Vt4ZqUB2y5YTi6Ko65FHgC-njfnW4BxR08OfR59y0ak7FdBccxyvQ4_UhI4C9xSnrKmQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFDVtW45r4rJmq_QtHHeqhmTfal1N4GUd6nJvMeGpEqXVcyiGu2WF72v2TucPI2aK496mrmf9U0__ZZrtbw4ssRP4aEP__uGlm-SzdBcC7UP_0BV7Qk6vPNJATBfxEWdurMe2s=
-
Go CL 15790043に関する情報:
- Web search results for "Go CL 15790043": "Go CL 15790043, titled "runtime: fix stack re-scan during stack growth", addresses an issue where the stack was being re-scanned unnecessarily during stack growth operations. This fix likely improves the efficiency and performance of the Go runtime by avoiding redundant work."
-
nacl/amd64p32
に関する情報:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQENM9kJbCrCmeYYzLvVQq9cXILh5YcgPg44z1L-hW9zw-gb4IGQuL7EJYgjPY3gntnuYMbXjwIP4PNNKeh7RmSNOd0IA6ZZ__qkenMxz9fdP6fqTmKzCZPQkars_4WqKkdz6uZZCBghBiIKmpn04g==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQETA3C8cqkWXA_18MAj2gmeHEee6hdSNWg4lxeu0O3uwe8pCZyxd7vmtKMKKF8DtiLPodayC8QeLHfvI57AqgKN8zBBSJRjJRrbUX-9RtQ3Dd9tP69fyTx8Hf_9c4QwBBC1t4BFZej4M1eqq1Xe0Q==