심볼파일을 이용하여 디버깅을 하다보면 PDB 파일이 맞지 않아 디버깅을 진행하지 못하는 경우가 있다.

이때 아래 블로그에 나와 있는 것처럼 심볼파일을 강제 로딩하게 되면 디버깅이 가능해 진다.

소스가 변경되지 않았더라도 컴파일만 다시 하더라도 심볼파일의 타임 스탬프가 달라지기 때문에 심볼파일을 로딩하지 못 할때 유용하다.

블로그 이름  : 달토끼 대박나라

관련 글 링크 : http://kuaaan.tistory.com/380

 


Visual C++6.0 사용했을 때 원인을 알 수 없이 일정 기간이 지나면 Debug Error가 발생하는 경험을 한적이 있었습니다. 신입 시절 경험이 없는 터라 정말 고생 많이 했었습니다. 그때 참 이상하게도 CString을 사용하는 부분에서 Debug Error가 났었습니다. 그래서 대책방안으로 Thread나 Timer에서 CString을 사용하는 부분을 모두 문자열 배열로 바꿨던 기억이 납니다. 최근에 디버깅 작업을 하다가 좀더 확실하게 알게 되었습니다. 디버그 에러가 발생 했을 때의 콜스택들을 보니 대부분 아래와 같이 메모리 할당을 실패한 경우였습니다.

 

 

VC++6.0의 디버그 모드에서 new를 사용 할 경우 버그가 있다는 사실은 예전에 들어서 알고 있었는데 자세히 찾아보지 않아서 이번 기회에 검색해 보았습니다. 첨부한 문서와 같이 해당 버그는 이미 잘 알려진 버그로 VC++ 7.1에 수정되었다고 합니다.

 

아래에 나와 있는 것 처럼 Debug Mode로 실행 파일을 만들 경우 메모리를 할당 횟수가 2억회를 초과하게 되면 lRequest가 -1이 되면서 Exception Breakpoint에 의해 프로그램이 중단 되는 것이다.

 

 

해당 버그와 CString과의 관계는 아시다시피 CString 내부적으로 메모리를 동적으로 할당하기 때문에 밀접한 관계가 있는 것이죠.

 

실제로 테스트도 해보았는데 정말 VC++6.0으로 간단히 프로그램 작성해서 디버그 모드로

컴파일 하여 프로그램 실행 시켜보니 1시간만에 프로그램이 죽어 버리네요.

 

 

관련자료 및 글들은 해외 싸이트에서 많이 찾아 볼 수가 있는데 국내 싸이트에서는 좀처럼 찾기가 힘든것 같아서 이렇게 글을 올려 봅니다.

관련 링크

http://computer-programming-forum.com/81-vc/83f52a9d80a4edd0.htm

 

Bug in CRT Ms Visual CPP libraries.pdf

 

FIX- Visual CPP 6.0 응용 프...모드를 해제 한 후 중단 될 수 있습니다.pdf

 

FIX- Your Visual CPP 6.0 elease it in debug mode.pdf

 

MSVC run-time bug in Malloc in Debug Mode.pdf

Release Mode로 컴파일 하여 실행 파일을 만들었을 때 어려운 상황 중에 하나가 바로 프로그램이 비정상 종료 되는 문제이다.

Exception이 발생 될 때 Dump File을 생성되도록 프로그램을 작성해 두었지만 이 부분이 제대로 동작하지 않고 프로그램이 그냥 죽을 때가 있다. 아무런 메세지나 덤프파일 없이 프로그램이 종료 되는 것이다. (프로그램이 사라진다. -_-;;)

이런 문제는 내 경험으로 메모리 관련 문제가 있을 때 나타나는 문제 이다. 실제 테스트 프로그램을 작성하여 스택이나 힙을 Crah하게 되면 문제를 재연 할 수 있다.

만약 프로글램이 간단한 정도라면 문제가 어디에서 발생되었는지 쉽게 찾을 수 있겠지만 프로그램 구조가 복잡하고 특히 멀티쓰레드 환경이라면 문제의 원인을 찾기가 쉽지 않다.

이러한 경우에 procdump.exe 파일을 사용하면 도움이 된다.

Microsoft TechNet :: Windows SysInternals 블로그에서 다운 받을 수 있다. [여기]

https://technet.microsoft.com/en-us/sysinternals/dd996900    <- 링크가 안열리면 주소를 복사해서 사용하세요.

c> procdump.exe -ma -w -e -h ProcessName.exe D:\MY_CDA\

이렇게 입력하면 아래와 같은 뜻이 된다.

-ma : full dump file을 만들어라.

-w : 지정한 실행 파일이 실행 될 때 까지 기다려라

-e : Exception이 발생하면 dump을 만들어라.

-h : Hang (응답없음)이 발생하면 dump를 만들어라.

이렇게 해서 생성된 덤프파일을 windbg.exe를 이용하여 분석해 보면 프로그램의 어디 부분에서 문제가 된 것인지 쉽게 알 수가 있다.

google-breakpad나 CrashRpt를 사용하려 하였으나 이 방법도 꽤나 간단 명료해서 마음에 든다.

배치 파일을 함께 활용하면 프로세스와 procdump.exe를 동시에 기동 시킬 수 있어서 프로그램 수정 없이 연동 시킬 수 있다.

Windows SysInternals 블로그에 나와 있는 툴들은 쓰면 쓸수록 놀랍다. Mark Russinovich 씨 고맙습니다.

MFC 확장 DLL을 이용하여 작업하는 경우가 많은데

DLL안에 Dialog를 만들 때 마다 말썽이다.

이번에는 DLL 안에서 Dialog의 Create함수를 호출 하였으나 Assertion이 발생하였다.

결론은 Dialog의 Resource 핸들 때문이었는데

DLL을 링크해서 사용할때 Extention Class를 EXE의 Global Type에서 특정 클래스의 멤버 변수로

선언해 줌으로써 문제를 해결 하였다.

몇가지 삽질했던 점과 새롭게 알게된 사실을 정리해보자.

멀쩡하게 컴파일되던 프로젝트가 Error가 발생한다.

분명히 뭔가를 한것 같은데 기억은 잘 안난다. 

소스코드를 크게 수정한것도 아닌데 말이다...ㅜㅜ

예전에도 이 문제 때문에 한참을 고생했던 기억이 난다.

그런데 어떻게 해결 했는지는 기억이 나지 않는다.

이번에 또 같은 문제를 만난김에 기록해 둬야 겠다.

컴파일을 하면 아래 사진과 같이 LNK2001 Error가 발생한다.

LNK2001 Error는 정의는 되어 있는데 선언이 되어 있지 않은 경우에 발생한다.

컴파일 에러는 발생하지 않지만 Link 동작시에 선언부가 없어서 에러가 발생하는 것이다.

프로젝트 어디에도 해당 함수나 클래스를 사용하는 곳이 없는데....

아무리 뒤져봐도 소스상의 문제는 찾을 수 없었다. 다행히 작업전에 백업해 두었던 소스가 있어서 

컴페어로 비교를 해보니 clw 파일이 틀린거다.

A라는 프로젝트에 B라는 프로젝트를 추가해서 사용하고 있었는데

A라는 프로젝트의 clw 파일에 B프로젝트의 파일이 들어가 있지 않은가.

그래서 A프로젝트의 File View를 열어서 보니 문제의 파일(Trouble.cpp)이 프로젝트에 들어가 있는것을 볼 수 있었다.

이파일을 삭제해 주었더니 문제가 해결되었다. 예전에 마우스 클릭을 잘못해서 문제가 발생된것으로 생각했지만.

VC6.0의 버그인것으로 생각된다. 다시는 이문제로 고생하지 말아야지..




///////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

방금 작업하다가 같은 현상이 발생 되었는데 A 프로젝트를 활성화 시켜서 작업하다가

B 프로젝트의 파일을 고치는 작업을 하다보면 Visual Studio가 해당파일을 추가하겠냐고 물어본다.

메세지 박스를 잘 읽어보지 않고 YES 버튼을 누른것이 화근이구나....-_-;;;;;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

실제로 띄는 메세지는 아래와 같다.

이메세지가 뜨는 경우는

1. A프로젝트와 B 프로젝트에 CCommon 이라는 클래스가 있다.

2. A프로젝트가 활성화 된 상태에서 B 프로젝트의 Common.cpp를 수정하고 있다.

3. CCommon class에 멤버변수를 추가하고 싶어서 F12를 이용하여 CComm의 헤더파일로 이동한다.

    이때 헤더파일은 B 프로젝트의 Common.h가 아니라 A 프로젝트의 Common.h이다.

4. B 프로젝트의 Common.cpp를 모두 수정하고 Ctrl+F7을 눌러서 컴파일을 시도하면 위 메세지가 뜬다.

5. Yes를 누르게 되면 A프로젝트에 해당 파일이 추가 되면서 LNK Error 및 컴파일 Error를 유발 시킨다.



Dumping objects ->

{555841} client block at 0x06416A90, subtype 0, 12 bytes long.

a CEvent object at $06416A90, 12 bytes long

{555840} normal block at 0x06428730, 120 bytes long.

 Data: <                > F4 81 FF 01 CD CD CD CD E9 03 00 00 00 00 00 00 

Object dump complete.



이렇게 메모리 누수가 발생한 위치 정보가 없는 것은 어떻게 처리해야 할까?

+ Recent posts