共用方式為


_resetstkoflw

從堆疊溢位復原。

重要

這個 API 不能用於在 Windows 執行階段中執行的應用程式。 如需詳細資訊,請參閱 CRT functions not supported in Universal Windows Platform apps (通用 Windows 平台應用程式中不支援的 CRT 函式)。

語法

int _resetstkoflw( void );

傳回值

如果函式成功則為非零值,失敗則為 0。

備註

_resetstkoflw 函式從堆疊溢位狀況復原,讓程式繼續執行而不是因嚴重的例外狀況錯誤而失敗。 如果未呼叫函 _resetstkoflw 式,則先前的例外狀況之後沒有防護頁面。 下一次發生堆疊溢位時,完全沒有例外狀況,而且進程會在沒有警告的情況下終止。

如果應用程式中的線程造成 EXCEPTION_STACK_OVERFLOW 例外狀況,線程已將其堆疊留在損毀狀態。 此例外狀況與其他例外狀況不同,例如 EXCEPTION_ACCESS_VIOLATIONEXCEPTION_INT_DIVIDE_BY_ZERO,其中堆疊不會損毀。 程式第一次載入時,堆疊會設定為很小的值。 然後堆疊會視需要成長,以符合執行緒的需要。 隨選成長是藉由將具有存取權的頁面 PAGE_GUARD 放在目前堆疊的結尾來實作。 如需詳細資訊,請參閱 建立防護頁面

當程式碼造成堆疊指標指向這個頁面上的位址時,會發生例外狀況,且系統會執行下列三件事︰

  • PAGE_GUARD拿掉防護頁面上的保護,讓線程可以讀取和寫入記憶體中的數據。

  • 配置新的防護頁面,位於前一個防護頁面的下方一個頁面。

  • 重新執行引發例外狀況的指令。

如此一來,系統可以自動增加執行緒的堆疊大小。 處理序中的每個執行緒都有最大堆疊大小。 堆疊大小是在編譯階段由 /STACK [堆棧配置] 選項,或由 STACKSIZE 項目檔案中的 .def 語句所設定。

當超過這個最大堆疊大小時,系統會執行下列三件事︰

  • 移除防護頁面上的 PAGE_GUARD 保護,如先前所述。

  • 嘗試在前一個防護頁面下方配置新的防護頁面。 不過,配置失敗,因為已超過堆棧大小上限。

  • 引發例外狀況,使執行緒可以在例外狀況區塊中處理它。

此時,堆疊不再有防護頁面。 下一次程式將堆疊成長至寫入堆疊結尾以外的位置時,就會造成存取違規。

每當發生堆疊溢位例外狀況之後完成復原時,請呼叫 _resetstkoflw 還原防護頁面。 您可以從區塊的 __except 主體或區塊外部 __except 呼叫此函式。 不過,它的使用時機有一些限制。 _resetstkoflw 不應該從:

  • 篩選條件運算式。

  • 篩選函式。

  • 從篩選函式呼叫的函式。

  • catch 區塊。

  • __finally 區塊。

在這些點上,堆疊尚未完全解除復原。

堆疊溢位例外狀況會以結構化例外狀況的形式產生,而不是C++例外狀況,因此 _resetstkoflw 在一般 catch 區塊中並不有用,因為它不會攔截堆棧溢位例外狀況。 不過,如果使用 _set_se_translator 來實作會擲回C++例外狀況的結構化例外狀況轉換程式(如第二個範例所示),堆棧溢位例外狀況會導致C++例外狀況,而該例外狀況可由C++ catch 區塊處理。

在結構化例外狀況翻譯工具函式擲回的例外狀況所到達的 C++ catch 區塊中呼叫 _resetstkoflw 並不安全。 在此情況下,堆疊空間不會釋出,而且堆疊指標在 catch 區塊之外才會重設,即使已針對 catch 區塊之前的任何可解構物件呼叫解構函式也一樣。 在釋放堆疊空間並重設堆疊指標之前,不應該呼叫此函式。 因此,它只應該在結束 catch 區塊之後呼叫。 應該在 catch 區塊中使用盡可能少的堆疊空間。 在 catch 區塊中發生的堆疊溢位,本身嘗試從先前的堆疊溢位復原無法復原。 這可能會導致程式停止回應,因為 catch 區塊中的溢位會觸發相同 catch 區塊處理本身的例外狀況。

_resetstkoflw在某些情況下,即使使用於正確的位置,例如區塊內__except,仍可能會失敗。 即使回溯堆疊之後,可能沒有足夠的堆疊空間可以執行 _resetstkoflw ,而不需要寫入堆疊的最後一頁。 然後, _resetstkoflw 無法重設堆疊的最後一頁做為防護頁面,並傳回 0,表示失敗。 此函式的安全使用應該包括檢查傳回值,而不是假設堆疊是安全的使用。

使用 編譯應用程式/clr時,結構化例外狀況處理不會攔截STATUS_STACK_OVERFLOW例外狀況(請參閱/clr(Common Language Runtime 編譯)。

根據預設,此函式的全域狀態會限定於應用程式。 若要變更此行為,請參閱 CRT 中的全域狀態

需求

常式 必要的標頭
_resetstkoflw <malloc.h>

如需相容性詳細資訊,請參閱相容性

連結庫: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 isn't 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

描述

下列範例將示範 _resetstkoflw 在程式中的建議用法,在該程式中,結構化例外狀況會轉換成 C++ 例外狀況。

程式碼

// 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.

另請參閱

_alloca