Как завершить программу, когда она падает?(который должен просто провалить юнит-тест, а не застрять навсегда) - PullRequest
34 голосов
/ 25 августа 2010

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

Как этого избежать?


Вот пример диалога в Win7 с обычными настройками:

alt text

Если я отключу ключ реестра AeDebug, опция отладки JIT пропадает:

alt text

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

alt text

Ответы [ 3 ]

55 голосов
/ 03 сентября 2010

Сводка ответов jdehaan и Eric Brown, а также этот вопрос (см. Также этот вопрос ):

NB Эти решения могут влиять и на другие сообщения об ошибках, например, на ошибку загрузки DLL или открытия файла.

Вариант 1: глобальное отключение

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

Установите [HKLM|HKCU]\Software\Microsoft\Windows\Windows Error Reporting\DontShowUI в 1. Дополнительная информация: Настройки WER .

Опция2: Отключить для приложения

Требуется модификация программы сбоя, описанная в документации как лучшая практика, не подходящая для библиотечной функции.

Вызов SetErrorMode :SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); (или с SEM_FAILCRITICALERRORS).Дополнительная информация: Отключение диалогового окна сбоя программы (объясняется странное расположение вызовов).

Опция 2a: отключить для функции :

Требуетсямодификация программы сбоя, требуется Windows 7/2008 R2 (только для настольных приложений) или выше, описанная в документации как предпочтительная для SetErrorMode, подходящая для поточно-ориентированной библиотечной функции.

Вызов и сброс SetThreadErrorMode :

DWORD OldThreadErrorMode = 0;
SetThreadErrorMode(SEM_FAILCRITICALERRORS,& OldThreadErrorMode);
    …
SetThreadErrorMode (z_OldThreadErrorMode, NULL);

Дополнительная информация: мало доступно?

Опция 3: указать обработчик

Требуется модификация программы сбоя.

Используйте SetUnhandledExceptionFilter, чтобы установить собственный структурированный обработчик исключений, который просто завершается, возможно, с отчетами и, возможно, попыткой очистки.

Вариант 4: Поймать как исключение

Требуется модификация программы сбоя.Только для приложений .NET.

Оберните весь код в глобальный блок try / catch.Укажите HandleProcessCorruptedStateExceptionsAttribute и, возможно, также SecurityCriticalAttribute в методе, перехватывающем исключения.Дополнительная информация: Обработка исключений из-за поврежденного состояния

Примечание : это может не отловить сбои, вызванные Managed Debugging Assistants ;в этом случае их также необходимо отключить в приложении.

Вариант 5: остановить процесс создания отчетов

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

Завершать процесс создания отчетов об ошибках Windows при каждом его отображении:

var werKiller = new Thread(() =>
{
    while (true)
    {
        foreach (var proc in Process.GetProcessesByName("WerFault"))
            proc.Kill();
        Thread.Sleep(3000);
    }
});
werKiller.IsBackground = true;
werKiller.Start();

Это все еще не полностью пуленепробиваемое решение, поскольку консольное приложение может аварийно завершить работу с помощью другого сообщения об ошибкепо-видимому, отображается внутренней функцией NtRaiseHardError:

alt text

5 голосов
/ 25 августа 2010

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

Это единственный способ предотвратить исключение исключенияваше приложение и активация WER.

Дополнение:

Если исключение - это то, чего вы не хотите, кроме случая, вы можете использовать AssertNoThrow (NUnit) или подобное в другой платформе Unit Test, чтобы заключитькод, запускающий дочерние процессы.Таким образом, вы также включите его в свой отчет об испытаниях модулей.На мой взгляд, это самое чистое из возможных решений.

Дополнение 2: Как показывают комментарии ниже, я ошибся: вы не всегда можете отловить асинхронные исключения, это зависит от того, что позволяет среда.В .NET некоторые исключения не могут быть перехвачены, что делает мою идею бесполезной в этом случае ...

Для .NET: Существуют сложные обходные пути, связанные с использованием доменов приложений, которые приводят к выгрузке домена приложений вместо этого.сбоя всего приложения.Жаль ...

http://www.bluebytesoftware.com/blog/PermaLink,guid,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx

http://www.develop.com/media/pdfs/developments_archive/AppDomains.pdf


РЕДАКТИРОВАТЬ:

Я наконец получил его,В .NET 4.0 Вы можете добавить атрибут HandleProcessCorruptedStateExceptions из System.Runtime.ExceptionServices в метод, содержащий блок try / catch.Это действительно сработало!Может быть, не рекомендуется, но работает.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;

namespace ExceptionCatching
{
    public class Test
    {
        public void StackOverflow()
        {
            StackOverflow();
        }

        public void CustomException()
        {
            throw new Exception();
        }

        public unsafe void AccessViolation()
        {
            byte b = *(byte*)(8762765876);
        }
    }

    class Program
    {
        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            Test test = new Test();
            try {
                //test.StackOverflow();
                test.AccessViolation();
                //test.CustomException();
            }
            catch
            {
                Console.WriteLine("Caught.");
            }

            Console.WriteLine("End of program");

        }

    }      
}
3 голосов
/ 01 сентября 2010

Попробуйте установить

HKCU \ Software \ Microsoft \ Windows \ Отчеты об ошибках Windows \ DontShowUI

до 1. (Вы также можете установить тот же ключ в HKLM, но для этого требуются права администратора).

Это должно помешать WER показывать любой пользовательский интерфейс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...