Проблемы с передачей _EXCEPTION_POINTERS * с использованием FileMapping

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

Я приземлился здесь Передача указателя процессу, порожденному exec () и узнал, что передача указателей в разделяемой памяти имеет эту проблему:

«Если вы используете разделяемую память, вы не можете передать указатель. Указатель будет содержать виртуальный адрес, который отличается от одного процесса к другому. Вы должны обмениваться значениями смещения, основанными на начале области разделяемой памяти.

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

Теперь, как я могу преодолеть это?

Процесс 1:

    struct mytest
{
_EXCEPTION_POINTERS * except ;
DWORD ThreadId ;
DWORD ProcessId ;
}

OpenFileMapping ( ) ;

void * pBuf = MapViewOfFile ( ) ;

mytest passdata ;

CopyMemory ( pBuf , &passdata , sizeof ( passdata ) ) ;

UnMapView ( ) ;

CloseHandle ( ) ;

(Например) Процесс 2:

    cout << passdata->except->ExceptionRecord->ExceptionCode << endl ;

потерпит крах. Я понимаю, что это потому, что виртуальный адрес зависит от конкретного процесса. Но как в этом случае передать информацию об исключении другому процессу и написать мини-дамп ??

П.С .: Я даже пытался передавать структуры PEXCEPTION_RECORD отдельно, но это не работает.

2

Решение

Правильно, вы не можете разыменовать указатель в другом процессе, он действителен только в аварийном процессе. Достаточно только перейти в поле MiniDumpWriteDump (), MINIDUMP_EXCEPTION_INFORMATION.ExceptionPointers. Технически вы можете использовать ReadProcessMemory (), но делать это для сбойного процесса излишне рискованно. Простое решение — добавить в вашу структуру дополнительное поле, в котором хранится код исключения и записывается вашим фильтром исключений.

mytest passdata ;
passdata.except = ExceptionInfo;
// Note: added field
passdata.ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
passdata.ThreadId = GetCurrentThreadId();
// etc..

Также избегайте вызова функций winapi, таких как OpenFileMapping и MapViewOfFile, это слишком рискованно. Они склонны к тупиковой ситуации, когда программа аварийно завершает работу из-за повреждения кучи процесса. Распространенная причина сбоя и тупик, потому что блокировка кучи все еще удерживается. Просто сделайте это при инициализации программы. Вам также не нужно беспокоиться об очистке, Windows заботится об этом, когда ваш сторожевой процесс завершает сбойный процесс после получения минидампа.

1

Другие решения

Я соберу это в качестве ответа, хотя это действительно должен быть комментарий к Ответ Ганса (и комментарии там), но, кажется, нужно какое-то объяснение:

Код, размещенный в вопросе, правильно передает значение (я) struct mytest структурировать в общую память.

Второй фрагмент кода:

(Например) Процесс 2:

cout << passdata->except->ExceptionRecord->ExceptionCode << endl ;

Показывает недопонимание, хотя: в то время как вы можете прочитать значение указателя passdata.exceptв процессе 2 это просто произвольное 32/64 битное значение, оно не является допустимым указателем.

Вы Можно передать это MiniDumpWriteDumpэта функция будет элюировать значение этого указателя в контексте целевого процесса (proc 1). Но ты не могу Разыщите его в процессе № 2.

Пример Ганса дает решение, если вам нужно значение ExeptionCode в процессе # 2 вам нужно разыменовать указатель в proc # 1 и поместить значение в данные, которые вы записываете в общую память.

3