Ловля исключений “Переполнения стека” в рекурсивных функциях C++

Переработка Пула приложений перезапускает процесс w3wp.exe для того пула приложений , следовательно это будет только влиять на веб-сайты, работающие в том пуле приложений.

IISReset перезапускает ВСЕ процессы w3wp.exe и любое другое связанное с IIS обслуживание, т.е. Сервис FTP или NNTP.

я думаю, изменяясь web.config, или /bin не перерабатывает целый пул приложений, но я не уверен в этом.

10
задан Kirill V. Lyadvinsky 23 October 2009 в 08:42
поделиться

11 ответов

Само по себе это не исключение, но если вы просто хотите ограничить использование стека до фиксированной суммы, вы можете сделать что-то вроде этого:

#include <stdio.h>

// These will be set at the top of main()
static char * _topOfStack;
static int _maxAllowedStackUsage;

int GetCurrentStackSize()
{
   char localVar;
   int curStackSize = (&localVar)-_topOfStack;
   if (curStackSize < 0) curStackSize = -curStackSize;  // in case the stack is growing down
   return curStackSize;
}

void MyRecursiveFunction()
{
   int curStackSize = GetCurrentStackSize();
   printf("MyRecursiveFunction:  curStackSize=%i\n", curStackSize);

   if (curStackSize < _maxAllowedStackUsage) MyRecursiveFunction();
   else
   {
      printf("    Can't recurse any more, the stack is too big!\n");
   }
}

int main(int, char **)
{
   char topOfStack;
   _topOfStack = &topOfStack;
   _maxAllowedStackUsage = 4096;  // or whatever amount you feel comfortable allowing

   MyRecursiveFunction();
   return 0;
}
11
ответ дан 3 December 2019 в 14:00
поделиться

Даже если вы можете сделать это непереносимо, как в Windows, это все равно очень плохая идея. Лучшая стратегия - вообще не переполнять стек. Если вам нужна изоляция от какого-то кода, который вы не контролируете, запустите этот код в другом процессе, и вы сможете определить, когда он дает сбой. Но вы не хотите делать такие вещи в своем собственном процессе, потому что вы не знаете, какое ужасное повреждение состояния совершит нарушающий код, и это сделает вас нестабильным.

интересная, отчасти связанная запись в блоге Раймонда Чена из Microsoft о том, почему вам не следует пытаться проверять действительные указатели в приложении пользовательского режима в Windows.

6
ответ дан 3 December 2019 в 14:00
поделиться

В Windows вы можете использовать структурированную обработку исключений (SEH) с ключевыми словами __try и __except для установки вашей собственной процедуры обработки исключений, которая может обнаруживать переполнение стека, нарушение доступа и т. Д. И т. Д.

Это довольно аккуратно, чтобы избежать диалогового окна сбоя Windows по умолчанию и заменить его своим собственным, если нужно.

1
ответ дан 3 December 2019 в 14:00
поделиться

Вы должны всегда знать уровень вашей рекурсии и проверять, не превышает ли он некоторый порог. Максимальный уровень (порог) рассчитывается как отношение размера стека к памяти, необходимой для одного рекурсивного вызова.

Память, необходимая для одного рекурсивного вызова, - это память для всех аргументов функции плюс память для всех локальных переменных плюс память для адреса возврата + несколько байтов (около 4-8).

-1
ответ дан 3 December 2019 в 14:00
поделиться

Конечно, вы можете избежать проблемы рекурсии, преобразовав ее в цикл.

Не уверен, знаете ли вы об этом, но любое рекурсивное решение можно преобразовать в цикл на основе решение, и наоборот. Обычно желательно использовать решение на основе цикла, потому что его легче читать и понимать.

Независимо от использования рекурсии или цикла, вам необходимо убедиться, что условие выхода четко определено и всегда будет выполняться.

]
-1
ответ дан 3 December 2019 в 14:00
поделиться
If you use Visual C++
Goto C/C++ , Code Generation
Choose "Both..." in "Basic Runtime Checks"

Затем запустите свое приложение ...

-1
ответ дан 3 December 2019 в 14:00
поделиться

Сомневаюсь, что при переполнении стека программа не сможет даже обработать исключение. Обычно ОС закрывает такую ​​программу и сообщает об ошибке.
Это происходит в основном из-за бесконечных рекурсий.

1
ответ дан 3 December 2019 в 14:00
поделиться

На какой ОС? Например, вы можете сделать это в Windows, используя структурированную обработку исключений (или векторную обработку исключений). Обычно вы не можете сделать это с помощью встроенной обработки исключений C ++, если вам это нужно.

Изменить: Microsoft C ++ может превратить структурированное исключение в исключение C ++. Это было включено по умолчанию в VC ++ 6. Это не происходит по умолчанию с новыми компиляторами, но я почти уверен, что с небольшим количеством спелеологии вы могли бы снова включить его.

Это правда, что когда это происходит, вы Нет места в стеке. Отчасти поэтому я упомянул векторную обработку исключений. Каждый поток получает свой собственный стек, а обработчик векторных исключений может работать в отдельном потоке, из которого возникло исключение. Однако даже SEH вы можете обработать исключение переполнения стека - ему просто нужно вручную создать поток, чтобы выполнить большую часть работы.

4
ответ дан 3 December 2019 в 14:00
поделиться

На самом деле нет портативного способа сделать это. Рекурсивная функция, выходящая из-под контроля, обычно вызывает недопустимый доступ к памяти, когда она пытается выделить кадр стека за пределами адресного пространства стека. Обычно это просто приводит к сбою вашей программы с ошибкой сегментации / нарушением доступа в зависимости от ОС. Другими словами, он не будет генерировать исключение C ++, которое может быть обработано стандартным способом языком.

11
ответ дан 3 December 2019 в 14:00
поделиться

Это постоянно выполняется в большинстве современных операционных систем. Если вы хотите сделать это самостоятельно, вам нужно знать максимальный «безопасный» адрес для вашего стека (или аналогичным образом выполнить некоторую математику, чтобы определить, сколько раз вы можете безопасно вызывать функцию), но это может быть очень сложно, если вы не управляете стеком вызовов самостоятельно, поскольку ОС обычно (по уважительной причине) скрывает это от вас.

Если вы программируете в пространстве ядра, это становится значительно проще, но еще кое-что спрашиваю, зачем ты делаешь. Если у вас есть переполнение стека, это, вероятно, из-за неправильного алгоритмического решения или из-за ошибки в коде.

edit: только что понял, что вы хотите «поймать исключение», которое возникает. Я не думаю, что мой ответ напрямую отвечает на это вообще (существует ли вообще это исключение? Я бы вместо этого полагал на впечатляющий провал), но я оставлю это для понимания. Если вы хотите его удалить, дайте мне знать в комментариях, и я сделаю это.

поскольку ОС обычно (по уважительной причине) скрывает это от вас.

Если вы программируете в пространстве ядра, это становится значительно проще, но все же я сомневаюсь, зачем вы это делаете. Если у вас есть переполнение стека, это, вероятно, из-за неправильного алгоритмического решения или из-за ошибки в коде.

edit: только что понял, что вы хотите «поймать исключение», которое возникает. Я не думаю, что мой ответ напрямую отвечает на это вообще (существует ли вообще это исключение? Я бы вместо этого полагал на впечатляющий провал), но я оставлю это для понимания. Если вы хотите его удалить, дайте мне знать в комментариях, и я сделаю это.

поскольку ОС обычно (по уважительной причине) скрывает это от вас.

Если вы программируете в пространстве ядра, это становится значительно проще, но все же я сомневаюсь, зачем вы это делаете. Если у вас есть переполнение стека, это, вероятно, из-за неправильного алгоритмического решения или из-за ошибки в коде.

edit: только что понял, что вы хотите «поймать исключение», которое возникает. Я не думаю, что мой ответ напрямую отвечает на это вообще (существует ли вообще это исключение? Вместо этого я бы предположил впечатляющий провал), но я оставлю это для понимания. Если вы хотите его удалить, дайте мне знать в комментариях, и я сделаю это.

это, вероятно, из-за неправильного алгоритмического решения или из-за ошибки в коде.

edit: только что понял, что вы хотите «поймать исключение», которое возникает. Я не думаю, что мой ответ напрямую отвечает на это вообще (существует ли вообще это исключение? Вместо этого я бы предположил впечатляющий провал), но я оставлю это для понимания. Если вы хотите его удалить, дайте мне знать в комментариях, и я сделаю это.

это, вероятно, из-за неправильного алгоритмического решения или из-за ошибки в коде.

edit: только что понял, что вы хотите «поймать исключение», которое возникает. Я не думаю, что мой ответ напрямую отвечает на это вообще (существует ли вообще это исключение? Я бы вместо этого полагал на впечатляющий провал), но я оставлю это для понимания. Если вы хотите его удалить, дайте мне знать в комментариях, и я сделаю это.

0
ответ дан 3 December 2019 в 14:00
поделиться

There isn't a portable way. However, there are a few nonportable solutions.

First, as others have mentioned, Windows provides a nonstandard __try and __except framework called Structured Exeption Handling (your specific answer is in the Knowledge Base).

Second, alloca -- if implemented correctly -- can tell you if the stack is about to overflow:

bool probe_stack(size_t needed_stack_frame_size)
{
    return NULL != alloca(needed_stack_frame_size);
};

I like this approach, because at the end of probe_stack, the memory alloca allocated is released and available for your use. Unfortunately only a few operating systems implement alloca correctly. alloca never returns NULL on most operating systems, letting you discover that the stack has overflown with a spectacular crash.

Third, UNIX-like systems often have a header called ucontext.h with functions to set the size of the stack (or, actually, to chain several stacks together). You can keep track of where you are on the stack, and determine if you're about to overflow. Windows comes with similar abilities a la CreateFiber.


As of Windows 8, Windows has a function specifically for this (GetCurrentThreadStackLimits)

7
ответ дан 3 December 2019 в 14:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: