Страницы

Поиск по вопросам

понедельник, 23 декабря 2019 г.

Перехват исключение из неуправляемого кода .NET

#c_sharp #net


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

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

Пробовал добавлять аттрибуты HandleCorruptState и ловить AccessViolation, Win32Exception,
ExternalException, Exception, по отдельности и все вместе взятое и ничего, процесс
просто падает. 

Версия .NET 4.6.1. 

P.S. Ловил AccessViolation в первую очередь, так как при неправильных параметрах
передаваемых в плюсовую либу она кидала именно это исключение. Вывод в лог при UnhandledException
тоже есть и в логах пусто.

ВОПРОС: Как решить эту проблему? Либо поймать исключение, либо как-то изолировать
рабочую область чтобы ее можно было бы перезагрузить.

Код: https://pastebin.com/MZB9VwY9
    


Ответы

Ответ 1



Такой вылет может происходить при повреждении управляемой кучи. Куча может повредиться если вы передаете библиотеке управляемый массив, а она что-то записывает за его границами. Или запоминает адрес и обращается к нему когда там уже ничего не лежит. Если вы подозреваете подобную ситуацию - попробуйте добавить методу, который ловит исключения, атрибут [HandleProcessCorruptedStateExceptions] - это поможет отловить такую ситуацию. Но это лишь средство диагностики, программа с поврежденной кучей неработоспособна. Если дело и правда в повреждении кучи, то сделать можно вот что. Во-первых, надо проверить (прочитав в документации) как долго библиотека собирается держать у себя переданные ей массивы. Если дольше чем один вызов метода - то надо выделять ей копию массива при помощи Marshal.AllocHGlobal. То же самое касается любых передаваемых по ссылке структур. Во-вторых, если есть подозрение что все вызовы правильные, а проблема - в выходе за границу, то нужно выделять память через VirtualAlloc, оставив с обоих сторон по зарезервированной странице. Это поможет превратить выход за границы массива в немедленный AccessViolationException, который можно обработать. Но краш C++ библиотеки не обязательно сопровождается исключением. Вот еще возможные способы: std::quick_exit, std::exit, std::abort, std::terminate И все - только стандартные способы, а ведь есть еще и WINAPI... Если библиотека использует что-либо из выше перечисленного - ее надо изолировать в отдельный дочерний процесс, и перезапускать его при падениях. Заодно избавитесь от возможных утечек памяти на стороне библиотеки. Общаться с дочерним процессом можно через Remoting, WCF или по велосипедному бинарному протоколу.

Комментариев нет:

Отправить комментарий