Bagikan melalui


_resetstkoflw

Pulih dari luapan tumpukan.

Penting

API ini tidak dapat digunakan dalam aplikasi yang dijalankan di Windows Runtime. Untuk informasi selengkapnya, lihat Fungsi CRT yang tidak didukung di aplikasi Platform Windows Universal.

Sintaks

int _resetstkoflw( void );

Nilai hasil

Bukan nol jika fungsi berhasil, nol jika gagal.

Keterangan

Fungsi _resetstkoflw pulih dari kondisi luapan tumpukan, memungkinkan program untuk melanjutkan alih-alih gagal dengan kesalahan pengecualian fatal. _resetstkoflw Jika fungsi tidak dipanggil, tidak ada halaman penjaga setelah pengecualian sebelumnya. Lain kali ada luapan tumpukan, tidak ada pengecualian sama sekali dan proses berakhir tanpa peringatan.

Jika utas dalam aplikasi menyebabkan pengecualian, utas EXCEPTION_STACK_OVERFLOW telah meninggalkan tumpukannya dalam keadaan rusak. Pengecualian ini berbeda dari pengecualian lain seperti EXCEPTION_ACCESS_VIOLATION atau EXCEPTION_INT_DIVIDE_BY_ZERO, di mana tumpukan tidak rusak. Tumpukan diatur ke nilai yang sangat kecil ketika program pertama kali dimuat. Tumpukan kemudian tumbuh sesuai permintaan untuk memenuhi kebutuhan utas. Pertumbuhan sesuai permintaan diimplementasikan dengan menempatkan halaman dengan PAGE_GUARD akses di akhir tumpukan saat ini. Untuk informasi selengkapnya, lihat Membuat halaman penjaga.

Ketika kode menyebabkan penunjuk tumpukan menunjuk ke alamat di halaman ini, pengecualian terjadi dan sistem melakukan tiga hal berikut:

  • Menghapus perlindungan pada halaman penjaga sehingga utas PAGE_GUARD dapat membaca dan menulis data ke memori.

  • Mengalokasikan halaman penjaga baru yang terletak satu halaman di bawah halaman terakhir.

  • Menjalankan kembali instruksi yang memunculkan pengecualian.

Dengan cara ini, sistem dapat meningkatkan ukuran tumpukan untuk utas secara otomatis. Setiap utas dalam proses memiliki ukuran tumpukan maksimum. Ukuran tumpukan diatur pada waktu kompilasi oleh /STACK opsi (Alokasi Tumpukan), atau dengan STACKSIZE pernyataan dalam .def file untuk proyek.

Ketika ukuran tumpukan maksimum ini terlampaui, sistem melakukan tiga hal berikut:

  • Menghapus perlindungan PAGE_GUARD pada halaman penjaga, seperti yang dijelaskan sebelumnya.

  • Mencoba mengalokasikan halaman penjaga baru di bawah halaman terakhir. Namun, alokasi gagal karena ukuran tumpukan maksimum telah terlampaui.

  • Menimbulkan pengecualian sehingga utas dapat menanganinya di blok pengecualian.

Pada saat itu, tumpukan tidak lagi memiliki halaman penjaga. Lain kali program menumbuhkan tumpukan ke tempatnya menulis di luar akhir tumpukan, itu menyebabkan pelanggaran akses.

Panggil _resetstkoflw untuk memulihkan halaman penjaga setiap kali pemulihan dilakukan setelah pengecualian luapan tumpukan. Fungsi ini dapat dipanggil dari dalam isi __except utama blok atau di luar __except blok. Namun, ada beberapa batasan kapan harus digunakan. _resetstkoflw tidak boleh dipanggil dari:

  • Ekspresi filter.

  • Fungsi filter.

  • Fungsi yang dipanggil dari fungsi filter.

  • Sebuah catch blok.

  • Sebuah __finally blok.

Pada titik-titik ini, tumpukan belum cukup unwound.

Pengecualian luapan tumpukan dihasilkan sebagai pengecualian terstruktur, bukan pengecualian C++, jadi _resetstkoflw tidak berguna dalam blok biasa catch karena tidak akan menangkap pengecualian luapan tumpukan. Namun, jika _set_se_translator digunakan untuk menerapkan penerjemah pengecualian terstruktur yang melempar pengecualian C++ (seperti dalam contoh kedua), pengecualian luapan tumpukan menghasilkan pengecualian C++ yang dapat ditangani oleh blok tangkapan C++.

Tidak aman untuk memanggil _resetstkoflw blok tangkapan C++ yang dicapai dari pengecualian yang dilemparkan oleh fungsi penerjemah pengecualian terstruktur. Dalam hal ini, ruang tumpukan tidak dibebaskan dan penunjuk tumpukan tidak diatur ulang sampai di luar blok tangkapan, meskipun destruktor telah dipanggil untuk objek yang dapat dihancurkan sebelum blok tangkapan. Fungsi ini tidak boleh dipanggil sampai ruang tumpukan dibebaskan dan penunjuk tumpukan telah direset. Oleh karena itu, harus dipanggil hanya setelah keluar dari blok tangkapan. Ruang tumpukan sesedikcil mungkin harus digunakan di blok tangkapan. Luapan tumpukan yang terjadi di blok tangkapan yang sedang mencoba memulihkan dari luapan tumpukan sebelumnya tidak dapat dipulihkan. Ini dapat menyebabkan program berhenti merespons, karena luapan di blok tangkapan memicu pengecualian yang ditangani oleh blok tangkapan yang sama.

Ada situasi di mana _resetstkoflw dapat gagal bahkan jika digunakan di lokasi yang benar, seperti dalam blok __except . Mungkin tidak ada cukup ruang tumpukan yang tersisa untuk dijalankan _resetstkoflw tanpa menulis ke halaman terakhir tumpukan, bahkan setelah melepas tumpukan. Kemudian, _resetstkoflw gagal mengatur ulang halaman terakhir tumpukan sebagai halaman penjaga, dan mengembalikan 0, menunjukkan kegagalan. Brankas penggunaan fungsi ini harus mencakup pemeriksaan nilai pengembalian alih-alih mengasumsikan bahwa tumpukan aman digunakan.

Penanganan pengecualian terstruktur tidak akan menangkap STATUS_STACK_OVERFLOW pengecualian saat aplikasi dikompilasi dengan /clr (lihat /clr (Kompilasi Runtime Bahasa Umum)).

Secara default, status global fungsi ini dicakup ke aplikasi. Untuk mengubah perilaku ini, lihat Status global di CRT.

Persyaratan

Rutin Header yang diperlukan
_resetstkoflw <malloc.h>

Untuk informasi kompatibilitas selengkapnya, lihat Kompatibilitas.

Pustaka: Semua versi fitur pustaka CRT.

Contoh

Contoh berikut menunjukkan penggunaan fungsi yang _resetstkoflw direkomendasikan.

// 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;
}

Contoh output tanpa argumen program:

loop #1

Program berhenti merespons tanpa menjalankan iterasi lebih lanjut.

Dengan argumen program:

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

Deskripsi

Contoh berikut menunjukkan penggunaan _resetstkoflw yang direkomendasikan dalam program di mana pengecualian terstruktur dikonversi ke pengecualian C++.

Kode

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

Baca juga

_alloca