Перехват исключения StackOverflowException - PullRequest
6 голосов
/ 29 августа 2010

Как мне поймать StackOverflowException?

У меня есть программа, которая позволяет пользователю писать сценарии, и при запуске произвольного пользовательского кода я могу получить StackOverflowException.Часть исполняемого пользовательского кода, очевидно, окружена try - catch, но переполнение стека невозможно отследить при нормальных обстоятельствах.

Я посмотрел вокруг и этот является наиболее информативнымответ, который я мог найти, но все же привел меня в тупик;из статьи в блоге команды BCL я обнаружил, что должен использовать RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup для вызова кода и делегата, который будет вызываться даже после переполнения стека, но при попытке процесс завершается ссообщение переполнения стека без вызова делегата.Я попытался добавить PrePrepareMethodAttribute в метод обработчика, но это ничего не изменило.

Я также пытался использовать AppDomain и обрабатывать события UnhandledException и DomainUnload, но весь процесс уничтожается при переполнении стека.То же самое происходит, даже если я throw new StackOverflowException(); вручную и не получаю фактическое переполнение стека.

Ответы [ 4 ]

2 голосов
/ 29 августа 2010

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

ВОсновной метод вашей программы использовать

var currentDomain = AppDomain.CurrentDomain;

, а затем добавить обработчик к событию

currentDomain.UnhandledException + = handler;

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

2 голосов
/ 29 августа 2010

Запрограммируйте ваш движок сценария для отслеживания уровня рекурсии в сценарии.Если рекурсия превышает произвольно большое число, убейте скрипт, прежде чем он убьет вашу программу.В качестве альтернативы вы можете запрограммировать механизм сценариев для работы без стеков и хранить все данные стека сценария в System.Collections.Generic.Stack .Даже если вы используете отдельный стек, вы все равно захотите ограничить уровень рекурсии, который может иметь скрипт, но сбор стека даст вам в несколько сотен раз больше стека.

0 голосов
/ 29 августа 2010

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

Необходимо создать другой AppDomain поскольку вы не можете выгрузить сборку из загруженного домена и не хотите завершать работу основного домена приложения.

Вы создаете новый домен приложения, например:

var scriptDomain = AppDomain.CreateDomain("User Scripts");

ВыЗатем можно загрузить любой тип из сборки, которую вам нужно создать.Вы должны быть уверены, что загружаемый вами объект наследуется от MarshalByRefObject.

Я предполагаю, что ваш пользовательский скрипт заключен в объект, определенный следующим образом:

public abstract UserScriptBase : MarshaByRefObject
{
    public abstract void Execute();
}

Вы можетепоэтому загрузите любой пользовательский скрипт, подобный следующему:

object script = domain.CreateInstanceFromAndUnwrap(type.Location, type.FullName);

После всего этого вы можете подписаться на scriptDomain.UnhandledException и отслеживать любую неисправимую ошибку.

Использовать другой домен приложения не просто ивы, скорее всего, столкнетесь с некоторой проблемой загрузки / выгрузки (на DLL ссылаются оба домена).

Я рекомендую вам некоторый учебник , который вы можете найти в Интернете.

0 голосов
/ 29 августа 2010

Вам нужно запустить код в отдельном процессе.

...