2013-04-22 3 views
2

out-of-process 예외 처리기를 만들고 싶었고 하위 프로세스가 예외를 발생시킬 때 전용 예외 처리를 수행하는 watch-dog 프로세스를 만들었습니다. 이벤트를 통해 워치 독 프로세스를 성공적으로 호출했습니다. 내가 직면하고있는 문제는 다른 프로세스에 예외 정보 포인터를 전달하려고하는 것입니다. 문제 해결 FileMapping을 사용하는 _EXCEPTION_POINTERS *

는 여기 Passing a pointer to process spawned with 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 ; 

충돌 것입니다. 나는 이것이 가상 주소가 특정 프로세스이기 때문에 이것이라고 생각한다. 그러나이 경우 예외 정보를 다른 프로세스로 전달하고 미니 덤프를 작성하는 방법 ??

P.S : 나는 PEXCEPTION_RECORD 구조체를 별도로 전달하려고 시도했지만 작동하지 않습니다.

답변

1

바로, 다른 프로세스에서 포인터를 역 참조 할 수 없으며 충돌 한 프로세스에서만 유효합니다. MiniDumpWriteDump(), MINIDUMP_EXCEPTION_INFORMATION.ExceptionPointers 필드로 전달하는 것만으로 충분합니다. 기술적으로 ReadProcessMemory()를 사용할 수 있지만 충돌 한 프로세스에 대해 그렇게하는 것은 불필요하게 위험합니다. 간단한 해결책은 구조체에 예외 코드를 저장하고 예외 필터로 작성된 추가 필드를 추가하는 것입니다.

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

또한 OpenFileMapping 및 MapViewOfFile과 같은 winapi 함수를 호출하면 너무 위험합니다. 그들은 프로세스 힙의 힙 손상으로 인해 프로그램이 충돌 할 때 교착 상태가되는 경향이 있습니다. 힙 잠금이 유지되어 충돌 할 수있는 일반적인 이유 및 교착 상태. 프로그램 초기화시이 작업을 수행하십시오. 정리 작업도 신경 ​​쓸 필요가 없습니다. Windows는 미니 덤프를 가져온 후 워치 독 프로세스가 충돌 한 프로세스를 종료 할 때 처리합니다.

+0

Thans @ 한자 Passant! 나는 한 가지 명확한 설명만을하고있다. MINIDUMP_EXCEPTION_INFORMATION.ExceptionPointers 필드를 전달하려고 시도 했습니까? 자식 프로세스에서 읽을 수 있습니까 ?? –

+0

예, 필드가있는 이유입니다. 아니요, "클라이언트 프로세스"에서는 읽을 수 없습니다. 또는 내가 설명한 것처럼 감시 프로세스. MiniDumpWriteDump에서 사용되며 미니 덤프 파일에 기록됩니다. 따라서 디버거에서 미니 덤프를 열면 예외가 발생한 위치를 표시 할 수 있습니다. 디버거는 포인터를 소유하고있는 프로세스를 디버깅하기 때문에 포인터를 사용하는 데 문제가 없습니다. –

+0

그러면 Watchdog에서 MiniDumpWriteDump를 호출하는 데 필요한 단계와 방법은 무엇입니까? –

3

정말 Hans's answer에 주석 (거기 코멘트)을해야하지만 나는 대답으로 함께이를 넣어 것입니다하지만 일부 설명이 필요한 것 같다

질문에 게시 코드는 올바르게 값을 전달 struct mytest 구조체의 공유 메모리로의 변환.

두 번째 코드 :

프로세스 2 (예를 들어)

:

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

비록 오해를 표시합니다 : 당신이 포인터 passdata.except의 값을 읽을 수 있지만, 과정 2 이것은 임의의 32/64 비트 값이며 유효한 포인터가 아닙니다. 당신은 MiniDumpWriteDump 이것을 전달할 수

이 함수는 대상 프로세스 (PROC 1)의 상황이 포인터 값 eveluate 것이다. 하지만 프로세스 2에서 역 참조 할 수 없습니다.

프로세스 # 2에서 ExeptionCode 값이 필요하면 Hans의 예제가 해결책을 제시합니다. 그런 다음 proC# 1에서 포인터를 역 참조하고 공유 메모리에 쓰는 데이터에 값을 입력해야합니다.

+0

쿨, 고마워요 @ 마틴 바. 가이드대로 진행합니다. –

+0

마침내 끝냈습니다. 향후 누군가가 MiniDump를 쓰지 못하는 문제에 직면 한 경우 프로세스 보안 액세스 및 권한을 확인하십시오. –