_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
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk