Partager via


_resetstkoflw

Récupère d'un dépassement de capacité de la pile.

Important

Cette API ne peut pas être utilisée dans les applications qui s’exécutent dans le Windows Runtime. Pour plus d’informations, consultez Fonctions CRT non prises en charge dans les applications de la plateforme Windows universelle.

Syntaxe

int _resetstkoflw( void );

Valeur retournée

Valeur différente de zéro si la fonction réussit, zéro si elle échoue.

Notes

La fonction _resetstkoflw récupère d’une condition de dépassement de capacité de la pile, ce qui permet à un programme de poursuivre son exécution au lieu d’échouer avec une erreur d’exception fatale. Si la _resetstkoflw fonction n’est pas appelée, il n’y a pas de pages de garde après l’exception précédente. La prochaine fois qu’il y a un dépassement de capacité de pile, il n’y a aucune exception du tout et le processus se termine sans avertissement.

Si un thread dans une application provoque une EXCEPTION_STACK_OVERFLOW exception, le thread a laissé sa pile dans un état endommagé. Cette exception est différente des autres exceptions telles que EXCEPTION_ACCESS_VIOLATION ou EXCEPTION_INT_DIVIDE_BY_ZERO, où la pile n’est pas endommagée. La pile est définie sur une valeur arbitrairement petite lorsque le programme est chargé pour la première fois. La pile se développe ensuite à la demande pour répondre aux besoins du thread. La croissance à la demande est implémentée en plaçant une page avec PAGE_GUARD accès à la fin de la pile actuelle. Pour plus d’informations, consultez Création de pages de garde.

Lorsque le code fait pointer le pointeur de pile vers une adresse sur cette page, une exception se produit et le système exécute les trois actions suivantes :

  • Supprime la PAGE_GUARD protection sur la page guard afin que le thread puisse lire et écrire des données dans la mémoire.

  • Alloue une nouvelle page de garde située une page en dessous de la dernière.

  • Réexécute l'instruction qui a déclenché l'exception.

Ainsi, le système peut augmenter automatiquement la taille de la pile pour le thread. Chaque thread d'un processus a une taille de pile maximale. La taille de la pile est définie au moment de la compilation par l’option /STACK (Allocations de pile) ou par l’instruction STACKSIZE dans le .def fichier du projet.

Lorsque cette taille de pile maximale est dépassée, le système exécute les trois actions suivantes :

  • Supprime la protection PAGE_GUARD sur la page de garde, comme décrit précédemment.

  • Essaie d'allouer une nouvelle page de garde en dessous de la dernière. Toutefois, l’allocation échoue, car la taille maximale de la pile a été dépassée.

  • Lève une exception afin que le thread puisse la gérer dans le bloc d'exception.

À ce stade, la pile n’a plus de page de garde. La prochaine fois que le programme augmente la pile où il écrit au-delà de la fin de la pile, il provoque une violation d’accès.

Appelez _resetstkoflw pour rétablir la page de garde chaque fois qu'une récupération est effectuée après une exception de dépassement de capacité de la pile. Cette fonction peut être appelée à partir du corps principal d’un __except bloc ou en dehors d’un __except bloc. Toutefois, il existe quelques restrictions sur son utilisation. _resetstkoflw ne doit pas être appelé à partir de :

  • Une expression de filtre.

  • Une fonction de filtre.

  • Une fonction appelée à partir d'une fonction de filtre.

  • Un bloc catch.

  • Un bloc __finally.

À ces points, la pile n’est pas encore suffisamment déwound.

Les exceptions de dépassement de pile sont générées en tant qu’exceptions structurées, et non en C++. _resetstkoflw Elles ne sont donc pas utiles dans un bloc ordinaire catch , car elles ne interceptent pas d’exception de dépassement de capacité de pile. Toutefois, si _set_se_translator elle est utilisée pour implémenter un traducteur d’exceptions structurées qui lève des exceptions C++ (comme dans le deuxième exemple), une exception de dépassement de pile entraîne une exception C++ qui peut être gérée par un bloc catch C++.

Il n’est pas sûr d’appeler _resetstkoflw dans un bloc catch C++ qui est atteint à partir d’une exception levée par la fonction de traduction d’exceptions structurées. Dans ce cas, l’espace de pile n’est pas libéré et le pointeur de pile n’est pas réinitialisé tant que l’extérieur du bloc catch n’est pas réinitialisé, même si les destructeurs ont été appelés pour des objets destructeurs avant le bloc catch. Cette fonction ne doit pas être appelée tant que l’espace de pile n’est pas libéré et que le pointeur de pile a été réinitialisé. Par conséquent, elle doit être appelée uniquement après avoir quitté le bloc catch. Autant d’espace de pile que possible doit être utilisé dans le bloc catch. Un dépassement de capacité de pile qui se produit dans le bloc catch qui tente lui-même de récupérer à partir d’un dépassement de capacité de pile précédent n’est pas récupérable. Le programme peut cesser de répondre, car le dépassement de capacité dans le bloc catch déclenche une exception qui lui-même est gérée par le même bloc catch.

Il existe des situations où _resetstkoflw il peut échouer même si elle est utilisée dans un emplacement correct, par exemple dans un __except bloc. Il se peut que l’espace de pile soit insuffisant pour s’exécuter _resetstkoflw sans écrire dans la dernière page de la pile, même après le déroulement de la pile. Ensuite, _resetstkoflw ne parvient pas à réinitialiser la dernière page de la pile en tant que page de garde et retourne 0, indiquant l’échec. L’utilisation sécurisée de cette fonction doit inclure la vérification de la valeur de retour au lieu de supposer que la pile est sûre à utiliser.

La gestion structurée des exceptions n’intercepte pas d’exception STATUS_STACK_OVERFLOW lorsque l’application est compilée /clr avec (voir /clr (Compilation Common Language Runtime)).

Par défaut, l’état global de cette fonction est limité à l’application. Pour modifier ce comportement, consultez État global dans le CRT.

Spécifications

Routine En-tête requis
_resetstkoflw <malloc.h>

Pour plus d’informations sur la compatibilité, consultez Compatibility.

Bibliothèques : toutes les versions des fonctionnalités de la bibliothèque CRT.

Exemple

L'exemple de code suivant montre l'utilisation recommandée de la fonction _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;
}

Exemple de sortie sans argument de programme :

loop #1

Le programme cesse de répondre sans exécuter d'autres itérations.

Avec des arguments de programme :

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

Description

L'exemple suivant illustre l'utilisation recommandée de _resetstkoflw dans un programme où les exceptions structurées sont converties en exceptions C++.

Code

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

Voir aussi

_alloca