버그 해결을 위한 모든 질문을 던져
+2 votes
536 views
흠.. 라이브 서비스 하다보니 그런 경우가 있더라구요..

원격디버깅으로 하면 분명 위치 잡아주는데...

덤프로는 안남더라구요..

덤프 파일 생성조차 시도 안하는...

흠.. 이런 경우는 어떤걸 살펴봐야 할까요?

조언좀..
asked (23 point)
재 태그 , 536 views

3 answers

+1 vote
우수 답변
윈도우 함수 안에서 죽거나 특수한 상황에서 미니덤프가 작동 하지 않고 윈도우 자체 덤프에서 처리 되어 미니덤프가 남지 않는 이슈가 있습니다.

예로 들어서 이런 경우

 printf( "%s", nNum );

윈도우 서버 설정을 수정 하면 윈도우 덤프 발생시 덤프 파일이 남도록 처리 가능합니다. 자세한 내용은 아래 링크 를 참고 해주세요

http://wendys.tistory.com/36
https://msdn.microsoft.com/ko-kr/library/windows/desktop/bb787181(v=vs.85).aspx

해당 내용이 정상 적으로 적용 되면 지정된 폴더 위치에 또는 디폴트 위치에 덤프 파일이 생성 됩니다.
answered (83 point)
수정됨

우왕! 저런기능이 있을 줄이야..

일단 아래 이야기한 에러 상황에도 덤프가 남습니다!!!

윈도우 10은 기본적으로 들어있는거 같더라구요..

그래서 reg 세팅 안해도 남는거 같더군요..

하지만 궁금한게 2008 서버에는 reg 확인 하니 없더라구요..

(그래서 안타깝게 그때 발생한 문제를 다시 확인 하지 못하는... ㅠ.ㅠ)

메뉴얼에 나온데로 LocalDumps 폴더 만들고 세팅하면 덤프가 남을까요?

(올려주신 msdn 링크에는 2008 서버 지원하는거 같지만 LocalDumps 라는 폴더가 없네요..)

뭐 읽어보니 비스타 이후는 세팅 하면 된다는거 같은데.. 쫌만 더 알려주세요 ㅠ.ㅠ

저는 잘되다 보니 더 이상은 조사 하지 않았습니다. 한가지 이슈가 있긴 했는데 콘솔로 서버 실행시 테스트 했을시 지정된 위치에 잘 남던데 서비스로 실행 하면 남지 않아서 찾아보니

C:\Windows\System32\config\systemprofile\AppData\Local\CrashDum

해당 위치에 덤프 파일이 남았습니다. 뭐 이런 비슷한 이슈가 아닐까요?
흠 일단 레지스터에 등록하고 한번 해봐야겠심다!

2008 서버에서는 기본적으로 세팅이 안되어있더라구요..

그래서 파일이 아에 안남은거 같아요..

저희도 서비스로 서버 돌리고 있었는데...

알려주셔서 감사합니다!!! ^^
+3 votes

아마 다 알고 계시는 내용일거 같지만  그래도 혹시 모르니 ... 

(이런거 관련해서 예전에 게임코디에 글 올려주셨던거 같았던 기억이 있는데 말입니다. ㅋㅋ)

 

1. 런타임 라이브러리가 자체적인 예외 코드에서 오류처리 하는 경우,

2. 런타임 라이브러리나 다른 코드에서 SetUnhandledExceptionFilter 를 사용해서 TopLevelExceptionFilter 를 바꿔버리는 경우.

1번은 런타임 라이브러리 핸들러 직접 셋팅하고, 2번은 SetUnhandledExceptionFilter 함수를 후킹해서 하면 되는데 이게 요즘 서버 OS 에서 안됨.

내 프로세스 내부에서는 100% 해결이 안되므로  외부 Just-in-time 디버거로 한번 더 잡아주는게 가장 확실하지 싶습니다.  옛날에는 닥터왓슨 썼었는데 64bit 용은 없는거 같아서 지금은 ProcDump 로 사용 중입니다. 제일 심플하고 덤프 확실하게 잡아줘서 좋습니다.

 

 

 

 

answered (222 point)

이것 저것 덤프 생성 하는 샘플 만들어서 해봤는데

아래 샘플은 Release 빌드했을 경우에는 안남는군요.. (Debug 빌드는 남네요..)

 

        std::vector<int> vecTestArray;
        vecTestArray.push_back(1);
        vecTestArray.push_back(2);
        vecTestArray.push_back(3);

        for (auto it = vecTestArray.begin(); it != vecTestArray.end(); ++it)
        {
            vecTestArray.erase(it);
        }

위에서 이야기 해주신 ProcDump 로도 생성 실패 하네요..

그냥 원격 디버깅 하거나 Debug 빌드해서 처리 해야할꺼 같은..

 

 

댓글이 너무 길어져서 답변으로 다시 달았습니다.
+3 votes

댓글로 달기에 너무 길어져서 댓글 남겨주신거 답변으로 다시 달았습니다.

 


이것 저것 덤프 생성 하는 샘플 만들어서 해봤는데

아래 샘플은 Release 빌드했을 경우에는 안남는군요.. (Debug 빌드는 남네요..)

 

        std::vector<int> vecTestArray;
        vecTestArray.push_back(1);
        vecTestArray.push_back(2);
        vecTestArray.push_back(3);

        for (auto it = vecTestArray.begin(); it != vecTestArray.end(); ++it)
        {
            vecTestArray.erase(it);
        }

위에서 이야기 해주신 ProcDump 로도 생성 실패 하네요..

그냥 원격 디버깅 하거나 Debug 빌드해서 처리 해야할꺼 같은..

 

지금 올려주신 코드의 문제는 잘못된 이터레이터로 erase 를 시도 하다가 내부 코드 memmove 에  쓰레기 값이 입력 되어서 힙을 쓸어버렸습니다.  결론적으로 보면 

int *p = new int

memset(p, 0, 엄청큰값);  

과 같은 상황이네요

 

(디버그 빌드에서 덤프가 남는건 그냥 vector 에서 iterator 에 대한 디버깅용 예외처리를 해줘서 잡힌겁니다.)

 

 

저도 말씀처럼 덤프가 안남는 현상이 나타나서  계속 추적을 해보니...

잘못된 코드로 힙을 쓸어가다가 메모리 접근영역을 벗어나는 순간 우리가 등록한 ExceptionFilter 가 호출은 되었습니다.  그런데 ExceptionFilter 안에서 덤프 남기려고 호출하는 CreateFile 또는 MiniDumpWriteDump 함수 안에서도 동적 메모리를 사용 하다보니 HeapAlloc 을 호출 하였는데  힙이 망가져서 힙 메모리 할당을 실패하고 덤프도 못남기고 죽어버는 상황이네요

ProcDump 역시 해당 프로세스 힙 접근 실패로 덤프를 남기지 못하는 에러코드가 나타납니다.

 

지금 문제는 내가 힙을 손상시켰고, ExecptionFilter 에서도 손상된 힙을 사용하려다 실패하는게 문제 입니다.  그럼 서로 다른힙을 쓰게끔 해주면 해결이 될거 같은데 ...  프로세스힙이나 CRT 힙을 변경할 방법이 없네요 ㅋ

 

그래서 일단 확인을 위해서 별도의 힙을 따로 만들고  new 연산자를 오버로딩해서  new 에 대한 힙을 새로만든 힙으로 변경해서 돌려보았습니다.

HANDLE g_hNewHeap;
void* operator new(size_t sz)
{
	void *p = HeapAlloc(g_hNewHeap, 0, sz);
	return p;
}
void operator delete(void *p)
{
	HeapFree(g_hNewHeap, 0, p);
}
int main()
{
	g_hNewHeap = HeapCreate(0, 1024, 0);

	std::vector<int> vecTestArray;
	vecTestArray.push_back(1);
	vecTestArray.push_back(2);
	vecTestArray.push_back(3);

	for (auto it = vecTestArray.begin(); it != vecTestArray.end(); ++it)
	{
		vecTestArray.erase(it);
	}
	return 0;
}

 

new 에 대한 힙을 분리 해주니 해당 힙을 개판을 쳐도  덤프남기기 위해 사용하는 힙은 정상이기 때문에 미니덤프 함수가 잘 작동하고 잘 저장 됩니다~. 물론 개판을 치다가 아주아주 우연하게 프로세스힙 까지 건드리면 같은 상황 이겠으나 가능성은 거의 없을 것이고요.

new 오버로딩 방법 말고  crt 내부 힙 핸들을 변경할 방법이 있으면 아주 깔끔하게 좋을거 같은데...   이 부분은 좀더 찾아봐야겠습니다. 

answered (222 point)
수정됨
쪼금 궁금한게 추가적으로 생겨서..

ProcDump도 out-of-process dump 형식으로 덤프파일 생성 하는거 아닌가요?

그럼 프로세서 힙이 깨져도 생성 되어야 하는거 아닐까라능 생각이 드는데..

google breakpad가 out-of-process dump를 지원한다고 하는데... ProcDump와 같은 상황일까요?

(이건 테스트를 해봐야겠네요...)

new delete 재정의는 케이스에 따라 사용 못하는 경우가 있을 수 있으니.. 깔끔 하진 않네요..

(역시 Debug로 빌드해서 올리는게...)

-----------------------------------------------------------------------

google breakpad도 테스트 해봤지만 역시 안남는군요.. 그냥 깨지면 그걸로 끝인가 봅니다..
보통 외부 디버거들이 프로세스에 접근해서 메모리를 얻어올때 ReadProcessMemory 같은 함수들을 사용하는데,  프로세스 영역 메모리를 통으로 얻어서 저장하는 방식이 아니고  힙 리스트를 얻어낸 뒤에  힙 블록들을 순회하면서 메모리를 얻어온는 방식 입니다. 결국 힙 데이터가 엉망이 되면 힙 블록 리스트 역시 엉망으로 얻어질 것으로 생각 됩니다.  

할당되지 않은 영역에 대해 잘못된 포인터로 ReadProcessMemory 를 호출 해보면 메모리 접근 에러나 나오는데 지금 ProcDump 에서도 그 에러가 표시되는걸로 봐서 이와 같은 상황이라고 생각 됩니다.

위 new / delete 오버로딩 방법은  원인 파악을 위한 코드로 올려드린 것이오니 입맞에 맞게 해결 보시면 될듯 합니다. 물론 디버그 모드 빌드도 한 가지 방법이 될 수 있는 것이고요.   저 같은 경우는 메모리 관리자를 직접 만들어서 사용하고 있다보니 new / delete 의 오버로딩도 그리 나쁜 방법은 아니라고 생각 됩니다.

버그 해결을 위해 도움을 구하고, 도움을 주세요. 우리는 그렇게 발전합니다.

throw bug 는 프로그래밍에 대한 전분야를 다룹니다. 질문,논의거리,팁,정보공유 모든 것이 가능합니다. 프로그래밍과 관련이 없는 내용은 환영받지 못합니다.

147 질문
247 answers
274 댓글
261 users