Можно ли поймать исключение нарушения прав доступа в.NET?
Есть ли что-нибудь, что я могу сделать, чтобы поймать AccessViolationException
? Это выбрасывается неуправляемой DLL, которую я не контролирую.
5 ответов
Ты не должен. Нарушение доступа является серьезной проблемой: это неожиданная попытка записи (или чтения) неверного адреса памяти. Как уже пояснил Джон, неуправляемая DLL могла уже повредить память процесса до того, как было поднято нарушение прав доступа. Это может привести к непредсказуемым последствиям в любой части текущего процесса.
Самое безопасное, что можно сделать, - это сообщить пользователю и сразу же выйти.
Некоторые подробности: Нарушение прав доступа - это исключение ОС (так называемое исключение SEH или структурированное исключение). Это другой тип исключения, чем исключения из управляемого CLR из System.Exception
, Вы будете редко видеть исключения SEH в чисто управляемом коде, но если это произойдет, например, в неуправляемом коде, CLR доставит его в управляемый код, где вы также сможете его перехватить 1.
Однако ловить исключения SEH в большинстве случаев не очень хорошая идея. Дальнейшие подробности объяснены в статье " Обработка исключений из- за поврежденного состояния" в журнале MSDN, где взят следующий текст:
CLR всегда доставлял исключения SEH для управляемого кода, используя те же механизмы, что и исключения, создаваемые самой программой. Это не проблема, пока код не пытается обработать исключительные условия, которые он не может разумно обработать. Большинство программ не могут безопасно продолжить выполнение после нарушения прав доступа. К сожалению, модель обработки исключений в CLR всегда поощряла пользователей обнаруживать эти серьезные ошибки, позволяя программам перехватывать любые исключения в верхней части иерархии System.Exception. Но это редко правильная вещь.
1 Это было верно до.NET 3.5. В.NET 4 поведение было изменено. Если вы все еще хотите использовать такие исключения, вам нужно добавить legacyCorruptedStateExceptionsPolicy=true
в app.config. Дальнейшие подробности в статье указаны выше.
Как отмечали другие, вы не должны "обрабатывать" это условие, но во время разработки удобно ловить его для устранения неполадок.
Вы можете пометить свой управляемый метод с помощью System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions
атрибут:
[HandleProcessCorruptedStateExceptions]
public void MyMethod()
{
try
{
NaughtyCall();
}
catch (AccessViolationException e)
{
// You should really terminate your application here
}
}
Да.
В вашем App.confg добавьте следующий код в <configuration>
тег:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
</runtime>
Теперь вы должны быть в состоянии отловить исключения из поврежденного состояния (CSE), как и любые другие.
Примечание. Если у вас уже есть тег времени выполнения, просто добавьте <legacyCorruptedStateExceptionsPolicy enabled="true"/>
к этому
Выше работает для.Net 4.5
Прежде всего, я полностью согласен с 0xA3. Но если нет выхода, вы можете обернуть грязную неуправляемую dll в свой собственный процесс и передавать данные через IPC (TCP/IP, namedpipes и т. Д.). Перехватите все исключения и сообщите хост-процессу. Таким образом, ваш хост-процесс в основном защищен от повреждения памяти.
Вы можете заключить вызов в неуправляемую DLL с помощью блока try-catch. AccessViolationException могут быть перехвачены нормально. Выполнение следующего кода показывает оба сообщения:
try
{
throw new AccessViolationException();
}
catch (Exception e)
{
MessageBox.Show(e.Message + e.StackTrace, e.Message, MessageBoxButtons.OK, MessageBoxIcons.Error);
}
MessageBox.Show("Still running..");
Редактирование:.NET 4 ввел изменение в поведении, больше невозможно отловить исключения поврежденного состояния, если вы специально не "попросите" об этом среду выполнения.