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

[インデックス 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)での問題があります。

  1. CL 15790043のマージ問題: 以前のコミット(CL 15790043)でsignal_amd64.cファイルに対して行われた変更が、何らかの理由でGoのリポジトリに正しくマージされませんでした。これにより、その変更が意図していた修正が適用されていない状態が続いていました。
  2. nacl/amd64p32特有のシグナルハンドリング: nacl/amd64p32は、Google Native Client (NaCl) 環境におけるamd64アーキテクチャで、ポインタサイズが32ビットであるという特殊な環境です。NaClはサンドボックス化された環境であり、通常のOSとは異なるシグナル処理のメカニズムを持つため、Goランタイムはこれに合わせた特別なハンドリングを必要とします。正しくマージされなかった変更は、この特殊な環境でのシグナルハンドリングの正確性に影響を与えていたと考えられます。
  3. 問題の再修正: このコミットは、正しくマージされなかった変更を再適用することで、nacl/amd64p32環境でのシグナルハンドリングの不具合を解消することを目的としています。ファイル名をsignal_amd64x.cに変更し、適切なビルドタグを追加することで、特定の環境でのみこの修正が適用されるようにしています。

前提知識の解説

Goランタイムとシグナルハンドリング

Goプログラムは、オペレーティングシステムからのシグナル(例: SIGTERMSIGINTSIGSEGVなど)を処理するために、os/signalパッケージとGoランタイムの内部メカニズムを利用します。

  • os/signalパッケージ: Goプログラムが特定のシグナルを受信した際に通知を受け取るための高レベルなインターフェースを提供します。
  • Goランタイムの役割: ランタイムは、プロファイリング(SIGPROF)や同期シグナル(SIGBUSSIGFPESIGSEGVなど、プログラムエラーによって引き起こされるもの)の処理のために、独自のシグナルハンドラをインストールします。シグナルが受信されると、ランタイムの内部gsignalゴルーチンがそれを処理し、必要に応じてos/signal.Notify()で登録されたチャネルに委譲します。

nacl/amd64p32アーキテクチャ

  • Native Client (NaCl): Googleが開発した、ウェブブラウザ内でコンパイルされたC/C++コードを安全に実行するためのサンドボックス環境です。セキュリティモデルが厳格であり、低レベルなシステムインタラクション(シグナル配信を含む)が仮想化または制限されます。
  • amd64p32: 64ビットのAMDプロセッサを対象としながらも、ポインタサイズが32ビットであるという特殊なアーキテクチャです。これは、メモリ使用量を抑えつつ64ビットのレジスタセットを利用したい場合に用いられることがあります。
  • NaCl環境でのシグナルハンドリングの課題: NaClのサンドボックス化された性質は、シグナルハンドリングに大きな影響を与えます。従来のOSとは異なり、プロセスがカーネルのシグナルメカニズムと直接対話することはできません。NaClランタイム自体がシグナルに似たイベントを仲介するため、Goランタイムのシグナルハンドラの実装は、このサンドボックス環境の制約に適応する必要があります。特に、メモリアクセス違反(SIGSEGV)などの低レベルな問題は、NaClサンドボックス内でシグナルとして現れる可能性があり、その処理は複雑になることがあります。

uintreguintptr

  • uintptr: Goにおけるポインタ型で、任意のポインタを保持できる整数型です。ポインタ演算には使用できませんが、ポインタの値を整数として扱う際に用いられます。そのサイズは、実行環境のポインタサイズ(32ビットまたは64ビット)に依存します。
  • uintreg: このコンテキストでは、レジスタの値を保持するための型を指していると考えられます。特定のアーキテクチャやコンテキストにおいて、レジスタのサイズがポインタのサイズと異なる場合があります。例えば、64ビットアーキテクチャで32ビットポインタを使用する場合、レジスタは64ビット幅を持つが、ポインタは32ビット幅となります。

技術的詳細

このコミットの技術的な変更点は以下の通りです。

  1. ファイル名の変更:

    • src/pkg/runtime/signal_amd64.cからsrc/pkg/runtime/signal_amd64x.cへファイル名が変更されました。
    • この変更は、特定のアーキテクチャやビルド環境に特化したコードであることを明確にするため、または以前の変更との競合を避けるために行われた可能性があります。
  2. ビルドタグの追加:

    • 元のファイルには// +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のビルドシステムは、これらの特定の環境でビルドする際にのみこのファイルを含めるようになります。
  3. シグナルハンドリングロジックの修正:

    • 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;

このコードブロックは、シグナルハンドラが呼び出された際に、シグナル発生時のコンテキスト(特に命令ポインタとスタックポインタ)を適切に処理するためのものです。

  1. sp = (uintptr*)SIG_RSP(info, ctxt);

    • シグナル情報(info)とコンテキスト(ctxt)から、シグナル発生時のスタックポインタ(SIG_RSP)を取得し、それをuintptr型のポインタとしてspに格納します。これは、スタックに値をプッシュするために使用されます。
  2. if(sizeof(uintreg) > sizeof(uintptr))

    • この条件文は、レジスタのサイズ(uintreg)がポインタのサイズ(uintptr)よりも大きい場合に真となります。
    • これは、特にamd64p32のような環境で重要です。amd64アーキテクチャではレジスタが64ビット幅ですが、amd64p32ではポインタが32ビット幅です。このような場合、レジスタの完全な値をスタックに保存する際に、ポインタサイズとの不一致による問題が発生する可能性があります。
  3. *--sp = 0;

    • 上記の条件が真の場合、つまりレジスタサイズがポインタサイズよりも大きい場合に、スタックポインタをデクリメント(スタックを拡張)し、その新しい位置に0をプッシュします。
    • この操作の目的は、レジスタの値をスタックに保存する際に、パディング(埋め草)を提供することであると考えられます。例えば、64ビットレジスタの値を32ビットポインタのスタックに保存する場合、上位32ビットが失われる可能性があります。この0のプッシュは、スタックアライメントを維持したり、あるいはレジスタの完全な値を保存するためのスペースを確保したりする役割を果たす可能性があります。これにより、シグナルからの復帰時にレジスタの状態が正しく復元されることを保証します。
  4. *--sp = SIG_RIP(info, ctxt);

    • 次に、シグナル発生時の命令ポインタ(SIG_RIP)をスタックにプッシュします。これは、シグナルハンドラから復帰した際に、プログラムが中断された正確な場所から実行を再開するために不可欠です。
  5. 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==