_resetstkoflw
スタック オーバーフローから復元します。
重要 |
---|
この API は、Windows のランタイムで実行するアプリケーションで使用することはできません。詳細については、でサポート /ZW CRT 関数" "を参照してください。 |
int _resetstkoflw ( void );
戻り値
失敗した場合は、関数が成功した場合は、ゼロ。
解説
_resetstkoflw 関数は、スタック オーバーフローが発生した状態からプログラムを回復させ、実行中の操作を致命的な例外エラーが発生したとして失敗させるのではなく、続行できるようにします。_resetstkoflw の関数を呼び出さなければ、ガード ページは、前の例外の後にありません。次にスタック オーバーフローが発生したときに例外は発生しないので、プロセスは警告なしで終了します。
アプリケーションのスレッドにより EXCEPTION_STACK_OVERFLOW の例外が発生した場合、スレッドは損なわれた状態でスタックが保持されていました。これは、スタックが傷つかない EXCEPTION_ACCESS_VIOLATION または EXCEPTION_INT_DIVIDE_BY_ZEROなどの例外とは対照的です。スタックは必要に応じて小さい値にプログラムが最初に読み込まれたときに設定されます。スタックは、スレッドのニーズを満たすために必要に応じて大きくなります。これは、現在のスタックの末尾に PAGE_GUARD のアクセス権を使用して、ページを設定することによって実装されます。詳細については、ガード ページの作成を参照してください。
コードによりスタック ポインター、このページのアドレスをポイントすると例外が発生すると、システムは、3 種類のことを実行します:
スレッドがメモリにデータを読み書きできるようにガード ページの PAGE_GUARD の保護を削除します。
最後の 1 の下の 1 ページ上番発生衛兵のページを割り当てます。
例外を発生させた命令を再実行します。
この方法では、システム スレッドに対してスタック サイズを自動的にインクリメントできます。プロセスの各スレッドに最適なスタック サイズがあります。スタック サイズは /STACK (スタック割り当て)、または .def ファイルの STACKSIZE のステートメントによってプロジェクトのコンパイル時に設定されます。
この最大のスタック サイズを超えると、システムは、3 種類のことを実行します:
前に説明したようにガード ページの PAGE_GUARD の保護を削除します。
最後のブックマークの下に上番衛兵のページを割り当てるとします。ただし、これは最ものスタック サイズを超えたため失敗します。
スレッドが例外のブロックで処理できるように例外が発生します。
その場合、スタックには、ガードのページがないことに注意してください。スタックがそこでアクセス違反、スタックの末尾を超えるガードのページ、プログラムの書き込みとその原因になる最後に、によって、プログラムがあるときに。
復元がスタック オーバーフローの例外の後に発生するたびにガード ページを復元するには _resetstkoflw を呼び出します。この関数は、__except ブロック __except ブロックまたは外部本体の中から呼び出すことができます。ただし使用する必要がある場合、いくつかの制限があります。_resetstkoflw は、から呼び出す必要があります:
フィルター式。
フィルター関数。
フィルター関数から呼び出される関数。
[catch] ブロック。
__finally ブロック。
これらの点で、スタックは完全にほどかれません。
スタック オーバーフロー例外はスタック オーバーフロー例外をキャッチできないため、構造化例外 C++ の例外ではなくため、_resetstkoflw が [catch] の通常のブロックには存在しないため生成されます。ただし、C++ 例外 (2 番目の例のように) 構造化例外のスローを翻訳者に実行すると、_set_se_translator を使用している場合、スタック オーバーフロー例外は、. C++ catch ブロック処理できる C ++.の例外が発生します。
構造化例外の翻訳者の関数によってスローされる例外から到達した C ++.の catch ブロックの _resetstkoflw の呼び出しは安全ではありません。この場合、スタック領域が解放されず、スタック ポインター、catch ブロックの外部でデストラクターが、破棄できるオブジェクトで前に catch ブロックが、呼び出されるまでリセットされません。この関数は、スタック領域が解放され、スタック ポインターがリセットされるまで呼び出す必要があります。したがって、catch ブロックの終了後のみ呼び出す必要があります。できるだけ少ないスタック領域、catch ブロックと catch ブロックのオーバーフローが、同じ catch ブロック処理される例外発生すると同時に、前のでスタック オーバーフローから回復する catch ブロック実行スタック オーバーフローが使用される回復可能でないように、プログラムの応答が停止するとなる可能性があります。
_resetstkoflw が内部で使用して、__except ブロックまたはの適切な位置、エラーになる場合があります。スタックをアンワインドを実行した後でも、スタックの最後のページに記述せずに _resetstkoflw を実装するための十分なスタック領域がまだない場合 _resetstkoflw は、スタックの最後のページをリセットしないため、ガードのページ 0 を返す、エラーを示します。したがって、この関数の安全な用途は、スタックを使用しても安全であると想定する代わりに戻り値をチェックすることを含める必要があります。
構造化例外処理では、アプリケーションが /clr か /clr:pure してコンパイルする場合 STATUS_STACK_OVERFLOW の例外をキャッチしません (/clr (共通言語ランタイムのコンパイル)を参照)。
必要条件
ルーチン |
必須ヘッダー |
---|---|
_resetstkoflw |
<malloc.h> |
互換性の詳細については、「C ランタイム ライブラリ」の「互換性」を参照してください。
CRT ライブラリの機能**ライブラリ:**のすべてのバージョン。
使用例
次の例では _resetstkoflw 関数の推奨される使用法を示しています。
// crt_resetstkoflw.c
// Launch program with and without arguments to observe
// the difference made by calling _resetstkoflw.
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
void recursive(int recurse)
{
_alloca(2000);
if (recurse)
recursive(recurse);
}
// Filter for the stack overflow exception.
// This function traps the stack overflow exception, but passes
// all other exceptions through.
int stack_overflow_exception_filter(int exception_code)
{
if (exception_code == EXCEPTION_STACK_OVERFLOW)
{
// Do not call _resetstkoflw here, because
// at this point, the stack is not yet unwound.
// Instead, signal that the handler (the __except block)
// is to be executed.
return EXCEPTION_EXECUTE_HANDLER;
}
else
return EXCEPTION_CONTINUE_SEARCH;
}
int main(int ac)
{
int i = 0;
int recurse = 1, result = 0;
for (i = 0 ; i < 10 ; i++)
{
printf("loop #%d\n", i + 1);
__try
{
recursive(recurse);
}
__except(stack_overflow_exception_filter(GetExceptionCode()))
{
// Here, it is safe to reset the stack.
if (ac >= 2)
{
puts("resetting stack overflow");
result = _resetstkoflw();
}
}
// Terminate if _resetstkoflw failed (returned 0)
if (!result)
return 3;
}
return 0;
}
出力例
プログラム引数がありません:
loop #1
プログラムではそれ以上の期間のイテレーションを実行せずに応答を停止します。
プログラム引数の場合:
loop #1
resetting stack overflow
loop #2
resetting stack overflow
loop #3
resetting stack overflow
loop #4
resetting stack overflow
loop #5
resetting stack overflow
loop #6
resetting stack overflow
loop #7
resetting stack overflow
loop #8
resetting stack overflow
loop #9
resetting stack overflow
loop #10
resetting stack overflow
説明
次の例では、構造化例外は C++ の例外に変換されるプログラムで _resetstkoflw の推奨される使用法を示しています。
コード
// crt_resetstkoflw2.cpp
// compile with: /EHa
// _set_se_translator requires the use of /EHa
#include <malloc.h>
#include <stdio.h>
#include <windows.h>
#include <eh.h>
class Exception { };
class StackOverflowException : Exception { };
// Because the overflow is deliberate, disable the warning that
// this function will cause a stack overflow.
#pragma warning (disable: 4717)
void CauseStackOverflow (int i)
{
// Overflow the stack by allocating a large stack-based array
// in a recursive function.
int a[10000];
printf("%d ", i);
CauseStackOverflow (i + 1);
}
void __cdecl SEHTranslator (unsigned int code, _EXCEPTION_POINTERS*)
{
// For stack overflow exceptions, throw our own C++
// exception object.
// For all other exceptions, throw a generic exception object.
// Use minimal stack space in this function.
// Do not call _resetstkoflw in this function.
if (code == EXCEPTION_STACK_OVERFLOW)
throw StackOverflowException ( );
else
throw Exception( );
}
int main ( )
{
bool stack_reset = false;
bool result = false;
// Set up a function to handle all structured exceptions,
// including stack overflow exceptions.
_set_se_translator (SEHTranslator);
try
{
CauseStackOverflow (0);
}
catch (StackOverflowException except)
{
// Use minimal stack space here.
// Do not call _resetstkoflw here.
printf("\nStack overflow!\n");
stack_reset = true;
}
catch (Exception except)
{
// Do not call _resetstkoflw here.
printf("\nUnknown Exception!\n");
}
if (stack_reset)
{
result = _resetstkoflw();
// If stack reset failed, terminate the application.
if (result == 0)
exit(1);
}
void* pv = _alloca(100000);
printf("Recovered from stack overflow and allocated 100,000 bytes"
" using _alloca.");
return 0;
}
出力例
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Stack overflow!
Recovered from stack overflow and allocated 100,000 bytes using _alloca.
同等の .NET Framework 関数
該当なし標準 C 関数を呼び出すには、PInvoke を使用します。詳細については、「プラットフォーム呼び出しの例」を参照してください。