다음을 통해 공유


_resetstkoflw

스택 오버플로에서 복구합니다.

Important

이 API는 Windows 런타임에서 실행되는 애플리케이션에서 사용할 수 없습니다. 자세한 내용은 유니버설 Windows 플랫폼 앱에서 지원되지 않는 CRT 함수를 참조하세요.

구문

int _resetstkoflw( void );

반환 값

함수가 성공하면 0이 아닌 값이고, 실패하면 0입니다.

설명

_resetstkoflw 함수는 스택 오버플로 조건으로부터 복구하여 프로그램이 예외 오류와 함께 실패하는 대신 계속 실행되도록 합니다. 함수가 _resetstkoflw 호출되지 않으면 이전 예외 이후의 가드 페이지가 없습니다. 다음에 스택 오버플로가 있을 때는 예외가 전혀 없으며 프로세스가 경고 없이 종료됩니다.

애플리케이션의 스레드가 예외를 발생시키는 EXCEPTION_STACK_OVERFLOW 경우 스레드는 스택을 손상된 상태로 남겼습니다. 이 예외는 스택이 EXCEPTION_ACCESS_VIOLATION 손상되지 않는 다른 예외와 EXCEPTION_INT_DIVIDE_BY_ZERO다릅니다. 프로그램이 처음 로드될 때 스택은 임의로 작은 값으로 설정됩니다. 그런 다음 스택은 스레드의 요구 사항을 충족하도록 요구에 맞게 증가합니다. 주문형 증가는 현재 스택의 끝에 액세스 권한이 있는 PAGE_GUARD 페이지를 배치하여 구현됩니다. 자세한 내용은 가드 페이지 만들기를 참조 하세요.

코드로 인해 스택 포인터가 이 페이지의 주소를 가리키는 경우 예외가 발생하고 시스템에서 다음 세 가지 작업이 수행됩니다.

  • 스레드가 PAGE_GUARD 데이터를 읽고 메모리에 쓸 수 있도록 보호 페이지에서 보호를 제거합니다.

  • 마지막 페이지에서 한 페이지 아래에 위치한 새 가드 페이지를 할당합니다.

  • 예외를 발생시킨 명령을 다시 실행합니다.

이러한 방식으로 시스템은 자동으로 스레드에 대한 스택의 크기를 늘릴 수 있습니다. 프로세스의 각 스레드는 최대 스택 크기를 가집니다. 스택 크기는 컴파일 시간에 /STACK (스택 할당) 옵션 또는 프로젝트에 대한 파일의 STACKSIZE .def 문에 의해 설정됩니다.

이 최대 스택 크기를 초과하면 시스템에서 다음 세 가지 작업을 수행합니다.

  • 앞에서 설명한 대로 가드 페이지에 대한 PAGE_GUARD 보호를 제거합니다.

  • 새 가드 페이지를 마지막 가드 페이지 아래에 할당하려고 합니다. 그러나 최대 스택 크기가 초과되었으므로 할당이 실패합니다.

  • 스레드가 예외 블록에서 처리할 수 있도록 예외를 발생시킵니다.

이 시점에서 스택에는 더 이상 가드 페이지가 없습니다. 다음에 프로그램이 스택의 끝을 넘어 쓰는 위치로 스택을 확장하면 액세스 위반이 발생합니다.

스택 오버플로 예외가 발생한 후 복원이 수행될 때마다 가드 페이지를 복원하려면 _resetstkoflw를 호출합니다. 이 함수는 블록의 __except 본문 내부 또는 블록 외부에서 __except 호출할 수 있습니다. 그러나 사용할 때 몇 가지 제한 사항이 있습니다. _resetstkoflw 다음에서 호출하면 안 됩니다.

  • 필터 식

  • 필터 함수

  • 필터 함수에서 호출한 함수

  • catch 블록

  • __finally 블록

이 시점에서 스택은 아직 충분히 해제되지 않았습니다.

스택 오버플로 예외는 C++ 예외가 아닌 구조적 예외로 생성되므로 _resetstkoflw 스택 오버플로 예외를 catch하지 않으므로 일반 catch 블록에서는 유용하지 않습니다. 그러나 두 번째 예제와 같이 C++ 예외를 throw하는 구조적 예외 변환기를 구현하는 데 사용되는 경우 _set_se_translator 스택 오버플로 예외로 인해 C++ catch 블록에서 처리할 수 있는 C++ 예외가 발생합니다.

구조적 예외 변환기 함수에서 throw된 예외에서 도달한 C++ catch 블록에서 호출 _resetstkoflw 하는 것은 안전하지 않습니다. 이 경우 스택 공간이 해제되지 않고 catch 블록 외부까지 스택 포인터가 다시 설정되지 않습니다. 스택 공간이 해제되고 스택 포인터가 다시 설정될 때까지 이 함수를 호출하면 안 됩니다. 따라서 catch 블록을 종료한 후에만 이 함수를 호출해야 합니다. 가능한 한 적은 스택 공간을 catch 블록에 사용해야 합니다. 이전 스택 오버플로에서 복구하려고 시도하는 catch 블록에서 발생하는 스택 오버플로는 복구할 수 없습니다. catch 블록의 오버플로가 동일한 catch 블록에서 처리되는 예외를 트리거하므로 프로그램이 응답을 중지할 수 있습니다.

블록 내에서와 같이 올바른 위치에서 사용하는 경우에도 실패할 수 있는 _resetstkoflw __except 상황이 있습니다. 스택을 해제한 후에도 스택의 마지막 페이지에 기록하지 않고 실행할 _resetstkoflw 스택 공간이 부족할 수 있습니다. 그런 다음 스택 _resetstkoflw 의 마지막 페이지를 가드 페이지로 다시 설정하지 못하고 실패를 나타내는 0을 반환합니다. 이 함수의 안전한 사용에는 스택을 사용하는 것이 안전하다고 가정하는 대신 반환 값 확인이 포함되어야 합니다.

구조화된 예외 처리는 애플리케이션이 컴파일될 때 예외를 STATUS_STACK_OVERFLOW catch하지 않습니다(공용 언어 런타임 컴파일 참조 /clr )./clr

기본적으로 이 함수의 전역 상태는 애플리케이션으로 범위가 지정됩니다. 이 동작을 변경하려면 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

설명

다음 예제에서는 구조화된 예외가 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.

참고 항목

_alloca