[インデックス 18935] ファイルの概要
このコミットは、GoランタイムがWindows/386アーキテクチャ上で例外処理を行う方法を、従来のStructured Exception Handling (SEH) からVectored Exception Handling (VEH) へと変更するものです。この変更は、Goの独自のスタック管理とSEHの間の根本的な非互換性を解決し、ランタイムの安定性と保守性を向上させることを目的としています。これにより、Windows 2000のサポートが終了し、Windows XP以降が必須となりました。
コミット
commit 3750904a7efc36aa4f604497b53a9dc1ea67492b
Author: Russ Cox <rsc@golang.org>
Date: Mon Mar 24 21:22:16 2014 -0400
runtime: use VEH, not SEH, for windows/386 exception handling
Structured Exception Handling (SEH) was the first way to handle
exceptions (memory faults, divides by zero) on Windows.
The S might as well stand for "stack-based": the implementation
interprets stack addresses in a few different ways, and it gets
subtly confused by Go's management of stacks. It's also something
that requires active maintenance during cgo switches, and we've
had bugs in that maintenance in the past.
We have recently come to believe that SEH cannot work with
Go's stack usage. See http://golang.org/issue/7325 for details.
Vectored Exception Handling (VEH) is more like a Unix signal
handler: you set it once for the whole process and forget about it.
This CL drops all the SEH code and replaces it with VEH code.
Many special cases and 7 #ifdefs disappear.
VEH was introduced in Windows XP, so Go on windows/386 will
now require Windows XP or later. The previous requirement was
Windows 2000 or later. Windows 2000 immediately preceded
Windows XP, so Windows 2000 is the only affected version.
Microsoft stopped supporting Windows 2000 in 2010.
See http://golang.org/s/win2000-golang-nuts for details.
Fixes #7325.
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3750904a7efc36aa4f604497b53a9dc1ea67492b
元コミット内容
このコミットは、GoランタイムがWindows/386環境での例外処理にStructured Exception Handling (SEH) ではなくVectored Exception Handling (VEH) を使用するように変更します。SEHはスタックベースの例外処理メカニズムであり、Goのスタック管理と相性が悪く、過去に多くのバグの原因となっていました。VEHはUnixのシグナルハンドラに似ており、プロセス全体で一度設定すればよく、Goのスタック管理との競合が少ないため、より堅牢な例外処理を実現します。この変更により、SEH関連のコードが削除され、多くの特殊ケースや条件付きコンパイルディレクティブが不要になります。また、VEHはWindows XPで導入されたため、GoのWindows/386版はWindows XP以降を必要とするようになり、Windows 2000のサポートは終了しました。
変更の背景
Goランタイムは、その効率的な並行処理モデルを実現するために、独自の軽量なゴルーチンスタック管理を採用しています。ゴルーチンは小さなスタックで開始し、必要に応じて動的にスタックを拡張します(コピーイングスタック)。しかし、Windowsの従来の例外処理メカニズムであるStructured Exception Handling (SEH) は、スタックベースであり、例外ハンドラがスタック上の特定の情報に依存していました。
Goのスタック管理とSEHの間の非互換性は、特にWindows/386環境で深刻な問題を引き起こしていました。Goランタイムがスタックを切り替える際、SEHが期待するスタックレイアウトと実際のスタックが一致しないことがあり、これがランタイムの不安定性やクラッシュの原因となっていました。具体的には、divmod.exe
のようなテストプログラムが、ゼロ除算エラーに対してGoのパニック/リカバリメカニズムが機能せず、Windowsの未処理例外としてクラッシュする問題(Issue #7325)が発生していました。これは、GoのSEHハンドラがSEHチェーンから削除されてしまうことに起因していました。
この問題は、Goのスタックコピアが例外ハンドラのスタックを正しくトレースバックできないことにも関連していました。Go開発チームは、SEHがGoのスタック使用と根本的に両立できないと判断し、より現代的でスタックに依存しないVectored Exception Handling (VEH) への移行を決定しました。
また、VEHはWindows XPで導入された機能であり、Windows 2000では利用できませんでした。Windows 2000は2010年にMicrosoftのサポートが終了しており、Goコミュニティ内でもWindows 2000のユーザーベースが非常に少ないという認識がありました。そのため、古いOSのサポートを維持することによる開発負担と、VEHへの移行によるランタイムの安定性向上というメリットを比較検討した結果、Windows 2000のサポートを終了し、Windows XP以降を必須とすることが決定されました。
前提知識の解説
Structured Exception Handling (SEH)
Structured Exception Handling (SEH) は、Windowsが提供する例外処理メカニズムの一つで、主にC/C++言語の拡張として提供されてきました。ハードウェア例外(メモリ違反、ゼロ除算など)やソフトウェア例外を処理するために使用されます。
- スタックベース: SEHはスタックフレームにハンドラを登録する形式を取ります。例外が発生すると、システムはコールスタックを遡り、最も最近にインストールされた例外ハンドラを探します。
- キーワード: Microsoft Visual C++では、
__try
,__except
,__finally
といったキーワードを用いてSEHを実装します。 - スレッド固有: SEHハンドラはスレッドごとに設定され、管理されます。
__finally
ブロック: 例外の発生有無にかかわらず、必ず実行されるコードブロックを定義できます。リソースの解放などに利用されます。- 32ビットSEH: スタック上に
_EXCEPTION_REGISTRATION_RECORD
構造体のリンクリストを構築してハンドラを管理します。 - 問題点: Goのような独自のスタック管理を行うランタイムでは、スタックのレイアウトが頻繁に変化するため、SEHが期待するスタック情報との不整合が生じやすく、不安定性の原因となることがありました。
Vectored Exception Handling (VEH)
Vectored Exception Handling (VEH) は、Windows XPで導入された、SEHを拡張するより新しい例外処理メカニズムです。
- プロセス全体: SEHがスレッド固有であるのに対し、VEHハンドラはプロセス全体に適用されます。例外が発生すると、コールスタック上のどこで発生したかに関わらず、登録されたVEHハンドラが呼び出されます。
- 登録:
AddVectoredExceptionHandler
関数を使用して、実行時にVEHハンドラを登録します。 - 優先順位: VEHハンドラはSEHハンドラよりも高い優先順位を持ちます。例外が発生した場合、まずVEHハンドラが呼び出され、その後にSEHハンドラが呼び出されます。
- スタック非依存: VEHハンドラは特定のスタックフレームに紐付けられていないため、Goのようなカスタムスタック管理を行うシステムにとって、SEHよりもはるかに適しています。
- 用途: グローバルな例外監視、デバッグ、ロギング、セキュリティ目的などに利用されます。
Goのスタック管理
Goランタイムは、効率的な並行処理を実現するために、独自のゴルーチンスタック管理モデルを採用しています。
- 動的スタック成長: Goのゴルーチンは、OSスレッドのように固定された大きなスタックを割り当てるのではなく、小さな初期スタック(例えば2KB)で開始します。
- コピーイングスタック: ゴルーチンがより多くのスタック領域を必要とする場合、Goランタイムは新しいより大きなメモリセグメントを割り当て、既存のスタック内容を新しい場所にコピーし、古いセグメントを解放します。このメカニズムにより、多数のゴルーチンが過剰なメモリを消費することなく並行して実行できます。
- OSスレッドとの区別: Goのゴルーチンは、OSスレッドよりもはるかに軽量です。Goランタイムは、少数のOSスレッド上に多数のゴルーチンを多重化して実行します。
- Windows固有の考慮事項: Windows上では、Goランタイムがスタックを直接管理し、OSが提供する個別のスタックには依存しません。これにより、Goのスタック管理とWindowsのSEHとの間に非互換性が生じることがありました。
Windows 2000サポート終了の背景
GoがWindows 2000のサポートを終了した背景には、技術的な問題とコミュニティの合意がありました。
- VEHの非互換性: 前述の通り、Goのスタック管理とSEHの間の問題は、VEHへの移行によって解決されました。しかし、VEHはWindows XPで導入された機能であり、Windows 2000では利用できませんでした。このため、Windows 2000をサポートし続けることは、Goランタイムの安定性を犠牲にするか、あるいはWindows 2000専用の複雑な例外処理ロジックを維持する必要があることを意味しました。
- OSのサポート終了: Microsoftは2010年にWindows 2000のサポートを公式に終了していました。これは、セキュリティアップデートやバグ修正が提供されないことを意味し、GoがこのOSをサポートし続けることの意義が薄れていました。
- ユーザーベースの減少: Goコミュニティ内では、Windows 2000をGoの開発やデプロイに使用しているユーザーが非常に少ないという認識がありました。
- 開発負担: 古く、サポートされていないOSとの互換性を維持することは、Go開発者にとって不釣り合いな負担となっていました。特に、その環境に特有のデバッグに関する専門知識が不足していることも問題でした。
これらの理由から、Go 1.3以降ではWindows 2000のサポートを終了し、Windows XP以降を必須とすることが決定されました。
技術的詳細
このコミットにおける技術的な変更の核心は、GoランタイムがWindows上での例外処理にSEHを完全に廃止し、VEHを導入した点にあります。
-
SEH関連コードの削除:
src/pkg/runtime/cgocall.c
からSEHUnwind
構造体やruntime·getseh()
,runtime·setseh()
の呼び出しが削除されました。これは、Cgo呼び出し中にSEHの状態を保存・復元するロジックが不要になったためです。src/pkg/runtime/runtime.h
からSEH
およびSEHUnwind
構造体の定義、そしてGOOSARCH_windows_386
マクロやruntime·getseh()
,runtime·setseh()
の宣言が削除されました。これにより、SEHに関連するデータ構造やAPIがランタイムから完全に排除されました。src/pkg/runtime/proc.c
では、mstart
やneedm
関数内でm->seh
を設定する#ifdef GOOSARCH_windows_386
ブロックが削除されました。これは、各M(マシン、OSスレッドに相当)にSEHフレームを関連付ける必要がなくなったためです。src/pkg/runtime/sys_windows_386.s
から、SEHフレームのセットアップと削除を行うアセンブリコード(runtime·install_exception_handler
、runtime·remove_exception_handler
、runtime·getseh
、runtime·setseh
)が削除されました。src/pkg/runtime/syscall_windows_test.go
から、SEHの復元をテストするTestCallbackPanicLocked
内のSEH関連のチェックが削除されました。
-
VEHの導入:
src/pkg/runtime/os_windows.c
にruntime·AddVectoredExceptionHandler
の動的インポートが追加されました。これは、VEHハンドラを登録するためのWindows APIです。runtime·osinit()
関数内で、runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
が呼び出されるようになりました。これにより、Goのシグナルハンドラであるruntime·sigtramp
がVEHハンドラとして登録されます。引数(uintptr)1
は、ハンドラが最初に追加されることを意味します。src/pkg/runtime/sys_windows_386.s
のruntime·sigtramp
関数が、VEHハンドラとして機能するように変更されました。この関数は、Windowsから呼び出されるVEHハンドラのエントリポイントとなり、例外レコードとコンテキストポインタを受け取ります。- 以前のSEHベースの
sigtramp
は、スタック上のSEHフレームを操作していましたが、新しいVEHベースのsigtramp
は、プロセス全体で例外を処理する役割を担います。 runtime·sighandler
を呼び出し、例外の種類に応じてGoのパニック処理やクラッシュ処理を行います。DBG_PRINTEXCEPTION_C
(0x40010006) のようなデバッガ向け例外を無視するロジックが追加されました。- ハンドラが例外を処理した場合は
-1
を返し、他のハンドラに渡す場合は0
を返すというVEHの規約に従うようになりました。
- 以前のSEHベースの
-
Windows 2000互換性の影響:
- VEHはWindows XPで導入されたため、この変更によりGoのWindows/386版はWindows XP以降のOSを必要とするようになりました。Windows 2000はVEHをサポートしていないため、Go 1.3以降はWindows 2000では動作しなくなりました。これは、Goランタイムの安定性向上と引き換えに、古いOSのサポートを終了するというトレードオフでした。
これらの変更により、GoランタイムはWindows上での例外処理をより堅牢かつシンプルに行えるようになり、Goのスタック管理との競合による不安定性の問題が解消されました。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は、以下のファイルに集中しています。
src/pkg/runtime/cgocall.c
: SEH関連の構造体SEHUnwind
の使用と、runtime·getseh()
、runtime·setseh()
の呼び出しが削除されました。src/pkg/runtime/os_windows.c
:runtime·AddVectoredExceptionHandler
の動的インポートが追加され、runtime·osinit()
関数内でVEHハンドラとしてruntime·sigtramp
が登録されるようになりました。また、SEH関連のSetProcessPriorityBoost
の動的ロードが簡素化されました。src/pkg/runtime/os_windows_386.c
:runtime·sighandler
関数がVEHハンドラからの呼び出しを想定して変更され、例外処理のロジックが調整されました。src/pkg/runtime/proc.c
:m
構造体からseh
フィールドへの参照が削除され、SEHフレームの管理ロジックが排除されました。src/pkg/runtime/runtime.h
:SEH
およびSEHUnwind
構造体の定義、GOOSARCH_windows_386
マクロ、runtime·getseh()
、runtime·setseh()
の宣言が削除されました。src/pkg/runtime/sys_windows_386.s
:runtime·sigtramp
アセンブリ関数がVEHハンドラとして再実装され、SEHフレームのセットアップ/削除を行うアセンブリ関数(runtime·install_exception_handler
、runtime·remove_exception_handler
、runtime·getseh
、runtime·setseh
)が削除されました。src/pkg/runtime/syscall_windows_test.go
: SEHの復元をテストするロジックが削除されました。
具体的な変更例:
src/pkg/runtime/os_windows.c
の変更 (VEHハンドラの登録)
--- a/src/pkg/runtime/os_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -8,6 +8,7 @@
#include "os_GOOS.h"
#include "../../cmd/ld/textflag.h"
+#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
@@ -86,26 +90,18 @@ getproccount(void)
void
runtime·osinit(void)
{
- void *kernel32;
- void *SetProcessPriorityBoost;
-
runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
+ runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
runtime·ncpu = getproccount();
-
- kernel32 = runtime·stdcall(runtime·LoadLibraryA, 1, "kernel32.dll");
- if(kernel32 != nil) {
- // Windows dynamic priority boosting assumes that a process has different types
- // of dedicated threads -- GUI, IO, computational, etc. Go processes use
- // equivalent threads that all do a mix of GUI, IO, computations, etc.
- // In such context dynamic priority boosting does nothing but harm, so we turn it off.
- SetProcessPriorityBoost = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "SetProcessPriorityBoost");
- if(SetProcessPriorityBoost != nil) // supported since Windows XP
- \truntime·stdcall(SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
- runtime·GetQueuedCompletionStatusEx = runtime·stdcall(runtime·GetProcAddress, 2, kernel32, "GetQueuedCompletionStatusEx");
- }
+
+ // Windows dynamic priority boosting assumes that a process has different types
+ // of dedicated threads -- GUI, IO, computational, etc. Go processes use
+ // equivalent threads that all do a mix of GUI, IO, computations, etc.
+ // In such context dynamic priority boosting does nothing but harm, so we turn it off.
+ runtime·stdcall(runtime·SetProcessPriorityBoost, 2, (uintptr)-1, (uintptr)1);
}
src/pkg/runtime/runtime.h
の変更 (SEH関連構造体の削除)
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -83,8 +83,6 @@ typedef struct Hchan Hchan;
typedef struct Complex64 Complex64;
typedef struct Complex128 Complex128;
typedef struct LibCall LibCall;
-typedef struct SEH SEH;
-typedef struct SEHUnwind SEHUnwind;
typedef struct WinCallbackContext WinCallbackContext;
typedef struct Timers Timers;
typedef struct Timer Timer;
@@ -241,18 +239,6 @@ struct LibCall
uintptr err; // error number
};
-struct SEH
-{
- void* prev;
- void* handler;
-};
-
-struct SEHUnwind
-{
- SEHUnwind* link;
- SEH* seh;
-};
-
// describes how to handle callback
struct WinCallbackContext
{
@@ -303,15 +289,6 @@ struct G
uintptr end[];
};
-// Define a symbol for windows/386 because that is the only
-// system with SEH handling, and we end up checking that
-// repeatedly.
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-#define GOOSARCH_windows_386
-#endif
-#endif
-
struct M
{
G* g0; // goroutine with scheduling stack
@@ -394,8 +371,6 @@ struct M
int8* notesig;
byte* errstr;
#endif
- SEH* seh;
- SEHUnwind* sehunwind;
uintptr end[];
};
@@ -975,16 +950,6 @@ void* runtime·funcdata(Func*, int32);
int32 runtime·setmaxthreads(int32);
G* runtime·timejump(void);
-// On Windows 386, we have functions for saving and restoring
-// the SEH values; elsewhere #define them away.
-#ifdef GOOSARCH_windows_386
-SEH* runtime·getseh(void);
-void runtime·setseh(SEH*);
-#else
-#define runtime·getseh() nil
-#define runtime·setseh(x) do{}while(0)
-#endif
-
#pragma varargck argpos runtime·printf 1
#pragma varargck type "c" int32
#pragma varargck type "d" int32
コアとなるコードの解説
src/pkg/runtime/os_windows.c
の変更
このファイルは、GoランタイムがWindowsオペレーティングシステムと対話するための低レベルな関数を含んでいます。
変更前は、SetProcessPriorityBoost
のような一部のWindows APIが動的にロードされていました。これは、それらのAPIがすべてのWindowsバージョンで利用可能ではないためです。
変更後、最も重要なのは runtime·AddVectoredExceptionHandler
の動的インポートと、runtime·osinit()
関数内でのその呼び出しです。
#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
この行は、kernel32.dll
から AddVectoredExceptionHandler
関数を動的にロードするための指示です。Goランタイムは、実行時にこの関数へのポインタを取得し、それを使用してVEHハンドラを登録します。
runtime·stdcall(runtime·AddVectoredExceptionHandler, 2, (uintptr)1, (uintptr)runtime·sigtramp);
このコードは、Goランタイムの初期化時に実行されます。
runtime·AddVectoredExceptionHandler
: 登録するVEHハンドラ関数へのポインタです。2
: 関数の引数の数です。(uintptr)1
:FirstHandler
パラメータに相当し、このハンドラがVEHチェーンの最初に追加されることを意味します。これにより、Goのハンドラが他のVEHハンドラやSEHハンドラよりも先に例外を処理する機会を得ます。(uintptr)runtime·sigtramp
: Goランタイムのシグナルハンドラであるruntime·sigtramp
関数へのポインタです。この関数が、Windowsからの例外通知を受け取る実際のハンドラとなります。
この変更により、Goランタイムは起動時にプロセス全体にわたる例外ハンドラを登録し、Goのスタック管理に起因するSEHの問題を回避できるようになります。
src/pkg/runtime/runtime.h
の変更
このヘッダーファイルは、Goランタイムの内部データ構造とAPIの定義を含んでいます。
変更前は、SEHに関連する SEH
および SEHUnwind
構造体、そして GOOSARCH_windows_386
マクロが定義されていました。
-typedef struct SEH SEH;
-typedef struct SEHUnwind SEHUnwind;
// ...
-struct SEH
-{
- void* prev;
- void* handler;
-};
-
-struct SEHUnwind
-{
- SEHUnwind* link;
- SEH* seh;
-};
// ...
-#ifdef GOOS_windows
-#ifdef GOARCH_386
-#define GOOSARCH_windows_386
-#endif
-#endif
// ...
- SEH* seh;
- SEHUnwind* sehunwind;
// ...
-#ifdef GOOSARCH_windows_386
-SEH* runtime·getseh(void);
-void runtime·setseh(SEH*);
-#else
-#define runtime·getseh() nil
-#define runtime·setseh(x) do{}while(0)
-#endif
これらの定義は、SEHがGoランタイムの内部でどのように管理されていたかを示しています。SEH
構造体はSEHフレームのリンクリストを構成し、SEHUnwind
はCgo呼び出し時のSEH状態の保存に使用されていました。GOOSARCH_windows_386
マクロは、Windows/386固有のSEHロジックを条件付きでコンパイルするために使用されていました。
これらの定義が削除されたことは、GoランタイムがSEHを完全に放棄し、その内部状態からSEHに関連するすべての概念を取り除いたことを意味します。これにより、コードベースが大幅に簡素化され、SEHに起因する複雑なバグの可能性が排除されました。
src/pkg/runtime/sys_windows_386.s
の変更
このアセンブリファイルは、Windows/386アーキテクチャに特化した低レベルなランタイム関数を含んでいます。特に runtime·sigtramp
関数は、例外処理のコア部分です。
変更前は、runtime·sigtramp
はSEHハンドラとして機能し、スタック上のSEHフレームを操作していました。また、runtime·install_exception_handler
や runtime·remove_exception_handler
といったSEHフレームをセットアップ/削除する関数が存在しました。
変更後、runtime·sigtramp
はVEHハンドラとして再実装されました。
TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
MOVL ptrs+0(FP), DI
SUBL $28, SP
MOVL 0(DI), BX // ExceptionRecord*
MOVL 4(DI), CX // Context*
// ... (省略: 例外発生時のPCチェックロジック)
// save callee-saved registers
MOVL BX, 12(SP)
MOVL BP, 16(SP)
MOVL SI, 20(SP)
MOVL DI, 24(SP)
// fetch g
get_tls(DX)
MOVL m(DX), AX
CMPL AX, $0
JNE 2(PC)
CALL runtime·badsignal2(SB)
MOVL g(DX), DX
// call sighandler(ExceptionRecord*, Context*, G*)
MOVL BX, 0(SP)
MOVL CX, 4(SP)
MOVL DX, 8(SP)
CALL runtime·sighandler(SB)
// restore callee-saved registers
MOVL 24(SP), DI
MOVL 20(SP), SI
MOVL 16(SP), BP
MOVL 12(SP), BX
vehret:
ADDL $28, SP
// RET 4 (return and pop 4 bytes parameters)
BYTE $0xC2; WORD $4
RET // unreached; make assembler happy
この新しい runtime·sigtramp
は、WindowsのVEHメカニズムによって直接呼び出されます。
ExceptionRecord*
とContext*
へのポインタを引数として受け取ります。これらは例外に関する詳細情報と、例外発生時のCPUレジスタの状態を含んでいます。- Goの
g
(ゴルーチン)とm
(OSスレッド)のコンテキストを取得し、runtime·sighandler
C関数を呼び出します。これにより、Goランタイムのより高レベルな例外処理ロジックが実行されます。 runtime·sighandler
からの戻り値に基づいて、例外が処理されたか(-1
)または他のハンドラに渡されるべきか(0
)をWindowsに通知します。RET 4
は、VEHハンドラの呼び出し規約に従って、スタックから4バイトの引数をポップして戻ることを意味します。
また、SEHフレームを操作していた以下の関数が完全に削除されました。
TEXT runtime·install_exception_handler(SB)
TEXT runtime·remove_exception_handler(SB)
TEXT runtime·getseh(SB)
TEXT runtime·setseh(SB)
これらのアセンブリ関数の削除は、SEHベースの例外処理メカニズムがGoランタイムから完全に排除されたことを明確に示しています。
関連リンク
- runtime: windows/386 SEH corruption · Issue #7325 · golang/go: http://golang.org/issue/7325
- objections to removing Go support for Windows 2000 (x86-32)?: http://golang.org/s/win2000-golang-nuts
参考にした情報源リンク
- Structured Exception Handling (SEH) vs. Vectored Exception Handling (VEH): https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGz7ISV980_l4Cvqtf8E2s8M6-w8qyshAaIlVWfG4WacDuEXVGW5mqTJalu50Dpl5ABGzBsiaiQYEWO1oym2PQME17tKE-NHO1EImMRtbTQNLE61MYadmH_WFeHGYhKPL80ldwnLvU4UptcsWgvGpLN_hZ13CPxvWguazVOINpzM3NaZVJnYGDM
- Go stack usage Windows: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEV0G62dZ4APNLHq9M5LzoMHl7urvjVsJsJYrw1C7_UAFuxsoOpwAeDqZHx_58aAMnDdLNZr0uvArfH8RG2cSmoC62dZRHU5sJPnSIw_TFN5adUWZcdQO9Hjczr_4YTZVug6OooMX9_hl6AnxM=
- runtime: windows/386 SEH corruption · Issue #7325 · golang/go: http://golang.org/issue/7325
- objections to removing Go support for Windows 2000 (x86-32)?: http://golang.org/s/win2000-golang-nuts
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHlqLCbDP5sPfDJ1yW_8W_ZUnYw7rryknRMZvKNDP4gzBmysY-JatZ61I1DiA0ETe1FzER3oYyByo7YbTA1yTpkNdzoDhYjkfniGXejJKHuzIPp4JSkLLlCe77zVce3Pk9-piTI4iWIom4imC5UBItX6TTIYnG12Y9NUzKEDhKyPr3BdZQ5ziOzY7E4wkjYPp_ddpHDA-BHPh3tEa_BXfM-Xw==
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEeCjvmYuP2RTHfj2xovF5E4LNUBqeTsUZAcjafQWO5C5W_yF3Ivq9qjb1lhYghHDEyi_WjzniEVdygqOdQQEsm382fAFEfGe3B56AacKNyj9_25LzQIyLlMPTVrdTJ_N1tJ11OusWQDcpNS0Xy9LGbWO-5H5sEtBtvO2ZzYxb8yWjCyYezOhD083m9y0nTpmG3qd-4pw==
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEoYcSR5M4XapudNZE1Ant2xMe5N6FCPdgXKIOXqNc49vhMJ5lZ1JxFEEDx1j0lVc-0IKksEXNHp64ji8KSQOPb4DDS6wVl-b4sTaUCEV0LFrXn4-0IauHEsRQ0Uoc2CGxKk9oHdKg1PEGC4JP7msiP-s6UqOfweHwmZCJqslGZSskCzfdYRA==
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEcSucUxZGG_-5Iz9v-l35QDdmGzweFTnA86EAkAtUN_nD1abv8iw8BeUCkLg1L0vwnQVYWZKLinhfqCg6MS0eURat4Ryn9ZO6USiZ3iuXjZYH6JlKADH4y-7nny2psEsPUpoaQMcPu8C7hXWMDXizzJC0EZgux
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGiOTpjGCXoN4QLbdpUhnQN5iPbgAijJrlDprdpm2tscl-lJqs8nbOmJxS5GmLkkrffc52hkaNjnkkdPbZTguqAQoVi8VjHX7q8IyBIuIDH_cBWzMs6s9MNUJNh2d4VFiyqiqkzCiry88kaagUCt48Q_p9i_KrNrrvWX7I=
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH3odeLAcBFouJj8jwNyqRC7_a-n6MuOAn2LV2WAY4q0qq2LM2F6lwmqercJtSzbH6Mil_bq6j0EBXYxGCVvRK3UKzJuuZl4cmpmgMKa5Dnn-CLUL7nDe-CaJnKZFdSAFqpfyKXLDsEH6d49KSs_B8USYUBdJn6x9AGQe3jW38ZvUikuqVblqW2oPu5Smvvjf5S6X0ObEzQgIYBJgrD2jVM1_3KPI81-hnhmQ_sKw7GnjC5q8kVCG0OBP6FIdeqXNQ8
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFV1PhkKGOtK92ccT-RQNqUgywxt9kqgSwd-dMzcYkL7xvi_UxqpsIjQZC2wkSC4_laDdad7d0j0ND8RjUbQAp_9gWd6sVgNM6mEl33-QS2ZLziwzBUCbUFqr7MlOCVVJ4F4ITwNlEW1kuVVvqA9mTfUJ0R5NPW_INxDrueWfbM1SGcW-TiH7rAZnZL
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFiw997mftH9LJ8_2hQBhkDLJUqHR1-GKbO7TeYtXqCMoKksoo0GD0rx_vHREnKQSgplLHWjsQeD2oierHEWE5sfgSQTGnDTNXEL1DBa4Sr9r58IQlTZhlnUgXSnkNTriyU5pChKw==
- SEH vs VEH: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGhaWc8KJSyyFKxCHoCv4imitC_PJZ-Fe3GaepVJiUFLhkHeAJbkTXpGZCUU7Js1sh3QMGdxCGzE0vqhQ6jZMFAFeBTsMinyUqk_z2wgD-sTKHtgTDkuVSVK56T467eEXvFUqUNrpAWiPj3mfBYkB8Wjvc2KO9FutYYddchySMt--upfR3AVN7zc6nt
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEcXxDAf1_KSq23oiNI8sa0zd7nUgO_hK_7xzcD5Mhh4Cns-y3Bhetz2AJweU7sCMiW6vewqcV_390zTnmDPujlLDtiGal1JeUhhvNt8_OBbjqlCji8YxzUsqhjwJ91BgYdmDomlafTgnU_IZZ1t5CleSQPzA==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE-i2IlRoYsn_dOQKt5HjuLF6z3repZ2JZMF_2nARpoimCIMWBssESAbcxgRWjnl2eO_7rICG-RV5TOJn0eSAUYP6xC-MhW73eJbbYl9cs3UrS34oKvTOsmz11SkJVllP1qfotm4iLJcLr2njY5kl3E
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEjWYzam1FZ9y1e2v29OYhawfvmdNPlbYtp7cwy_IBK7wAwr81lgVnl0hiIWqq-YYD2gsEipkiekHtzGKNvBpd8oa5bCxAGByOjXo7emX4AdLNBNElTQdlsJeL_dyodiQXnCWAeOYnBWo0P_jyi2KO1hM9eSfh8r8G6E5VIvfwc-qUy9kRwsI03-itTTUr-atbFq
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFHV1i6ym8K7zXFPnQDE0xlCrKam62tt2tADlhJxuepxuTDzPv0Ji2tFr9CfwsbiufNYFkv7ibx7gYiChM09JidyZWT4pvA2HCinTMw3iktyg-pPPTYhScP0KNIRADdhvxF9o1iQkcYCvzqJjiDSjJduWXgWlOixg==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHquJcIJEQ0DzpzRmxre2V5dt8sJ1KQw3WqPEwLvhQLNs9BjWcUwrJIwW9tKEvxkTK6vV8kypo-hBHkmKTFJA1Y9pNwT9n3GKRYPJ12qwglUWqdaTHwE0XvpiHVRxzZr34yyD6RyS1W
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHyskPL7dlzwFEa3bKa5A0ds9Xy50m8W5scv_uikYJrj6zWvXgUvNU5ZS6DSX-CQuBrEkp8Q6xXgtgpLLqSz_iu3Eb7tcQkL0qJWMtoBoplCbzeol0DbV4Q6vPKmaR73XWp5z4A4RMb3jccG4Ytxwe5HCP3oYkDhdAjXQG4pmPSKd5ofQJSgWjYlVT6BWcoJzT8
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEfUP3YqAoxgDJPM2_uU8fmGDLdC26_vI58BYcVbmDREbivBFnPHYLC-HKX1jJ8Uw_1XDHkqKvs-CpQLbs5xR3K-y9ywt3fOUieoGnT71k5ZMRda7NrH4R10hiTBw==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEWfmDj7-0QzaF4pMUvIasidm_m_9XhqwxjgJIq4WAlF5JZRAV0pSaS2RCnLB1NX-pfF_MQ6ywceoD2rZF5R6IHpU-g62oaqjPm-_GkOis2FQpmrH3wv4FY15Qy_jC_O2kkz9OQsGFzw9SulhIaSCWpYwmwT7Ck_tJP2eN1dPfaWz3qrvSDoo9A2SM4
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEzySToQtzNKHt_RqAYQ_R18VOQJsgDTdh0B6ADzHuMLibaCtfRWYK--383lBQxv9Pl3zao7ldFLHhXHU64q7WgE3RcO4oBSvZxUtr0qGmJhfIcl_lxH3oEgQ==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFGlX7AnlKloGGmD1sNq0nFlZFZEeeyY0Mq6fALP4GWRL8M8MPmaBWeVEvQ456FAzwn-kw2o4daEnmw2Al-giPu7vLG5MdFeYcvPwvPeaDuRDam78R1LUR10BzAd8d8WCTFV7-Em-3HKI1L3GUYRgKaPK9VqZIjw2DrEndspVSrs0CvzsUUJKA-gXOwjHInFqIgDbU=
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHyskPL7dlzwFEa3bKa5A0ds9Xy50m8W5scv_uikYJrj6zWvXgUvNU5ZS6DSX-CQuBrEkp8Q6xGgtgpLLqSz_iu3Eb7tcQkL0qJWMtoBoplCbzeol0DbV4Q6vPKmaR73XWp5z4A4RMb3jccG4Ytxwe5HCP3oYkDhdAjXQG4pmPSKd5ofQJSgWjYlVT6BWcoJzT8
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEWfmDj7-0QzaF4pMUvIasidm_m_9XhqwxjgJIq4WAlF5JZRAV0pSaS2RCnLB1NX-pfF_MQ6ywceoD2rZF5R6IHpU-g62oaqjPm-_GkOis2FQpmrH3wv4FY15Qy_jC_O2kkz9OQsGFzw9SulhIaSCWpYwmwT7Ck_tJP2eN1dPfaWz3qrvSDoo9A2SM4
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEzySToQtzNKHt_RqAYQ_R18VOQJsgDTdh0B6ADzHuMLibaCtfRWYK--383lBQxv9Pl3zao7ldFLHhXHU64q7WgE3RcO4oBSvZxUtr0qGmJhfIcl_lxH3oEgQ==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFGlX7AnlKloGGmD1sNq0nFlZFZEeeyY0Mq6fALP4GWRL8M8MPmaBWeVEvQ456FAzwn-kw2o4daEnmw2Al-giPu7vLG5MdFeYcvPwvPeaDuRDam78R1LUR10BzAd8d8WCTFV7-Em-3HKI1L3GUYRgKaPK9VqZIjw2DrEndspVSrs0CvzsUUJKA-gXOwjHInFqIgDbU=
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHyskPL7dlzwFEa3bKa5A0ds9Xy50m8W5scv_uikYJrj6zWvXgUvNU5ZS6DSX-CQuBrEkp8Q6xGgtgpLLqSz_iu3Eb7tcQkL0qJWMtoBoplCbzeol0DbV4Q6vPKmaR73XWp5z4A4RMb3jccG4Ytxwe5HCP3oYkDhdAjXQG4pmPSKd5ofQJSgWjYlVT6BWcoJzT8
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEWfmDj7-0QzaF4pMUvIasidm_m_9XhqwxjgJIq4WAlF5JZRAV0pSaS2RCnLB1NX-pfF_MQ6ywceoD2rZF5R6IHpU-g62oaqjPm-_GkOis2FQpmrH3wv4FY15Qy_jC_O2kkz9OQsGFzw9SulhIaSCWpYwmwT7Ck_tJP2eN1dPfaWz3qrvSDoo9A2SM4
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEzySToQtzNKHt_RqAYQ_R18VOQJsgDTdh0B6ADzHuMLibaCtfRWYK--383lBQxv9Pl3zao7ldFLHhXHU64q7WgE3RcO4oBSvZxUtr0qGmJhfIcl_lxH3oEgQ==
- Go stack growth: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFGlX7AnlKloGGmD1sNq0nFlZFZEeeyY0Mq6fALP4GWRL8M8MPmaBWeVEvQ456FAzwn-kw2o4daEnmw2Al-giPu7vLG5MdFeYcvPwvPeaDuRDam78R1LUR10BzAd8d8WCTFV7-Em-3HKI1L3GUYRgKaPK9VqZIjw2DrEndspVSrs0CvzsUUJKA-gXOwjHInFqIgDbU=