Advanced Breakpoint

December 4 2007, 8:21 PM

 

1. 요약

Visual C++ 6.0 에는 원하는 위치에 break point를 설치하는 기능 외에 특정 변수의 값이 변경될 때 실행이 멈추도록 설정하는 기능이 있습니다. 이 글은 Advanced BreakPoint를 사용해서 메모리가 overwrite되는 버그를 해결하는 방법을 설명하고 있습니다.


2. 본문

우선은 지금 이 글에서 해결하려고 하는 문제 상황을 설명드리겠습니다.

struct Line 

{

char buf[16];

int nLen;

};
Line이라는 구조체는 문자열을 저장할 16byte의 buf와 문자열의 길이를 저장할 정수 nLen을 가지고 있습니다. 이 구조체를 다음과 같이 잘못 사용하고 있습니다.

int main(int argc, char* argv[]) 

{

char src[] = "0123456789012345";

int nSrcLen = strlen(src);



Line l;

l.nLen = nSrcLen;

strcpy( l.buf, src);



return 0;

}
strlen() 에서 구한 문자열의 길이는 16 이지만, strcpy()는 16 byte외에 NULL 문자까지 복사한다는 것이 문제의 근본적인 원인입니다. nlen 이 자리잡고 있는 영역에 NULL 문자가 써지는 무식한 버그가 발생합니다. 실제 상황에서라면 개발자는 nLen이 0으로 세팅되어 있다는 사실에 몹시 당황할 것입니다. ( 조금 놀라겠지요..)

Advanced BreakPoint를 사용해서 nLen의 값이 변하는 순간을 포착해 봅시다.

Alt+F9 를 누르면 Breakpoints 다이어로그가 보여집니다. [Data] Tab을 누르시고 [Enter the expression to be evaluated] 라는 Edit 창에 다음과 같은 수식을 적습니다.

l.nLen

그러면 가장 및의 리스트 박스에 새로운 breakpoint가 추가된 것을 알 수 있습니다. 이제 창을 닫고 debug 모드( F5)로 프로그램을 실행해 봅시다..

어떤 결과가 나오겠습니까?? 물론 지금 곧 바로 따라해 보신 분은 없겠지만, break point를 설치할 수 없다는 다이어로그와 함께 방금 설치한 breakpoint가 disable 된 것을 알 수 있습니다. 다시 Alt+F9를 눌러서 Breakpoints 다이어로그를 띄어보면, 방금 설치한 breakpoint를 나타내는 리스트 박스의 아이템 앞에 check 표시가 없어진 것을 볼 수 있을 겁니다. 바로 disable되었다는 의미입니다.

아마도 디버거는 l.nLen이라는 수식을 이해하지 못하는 것 같습니다. 그렇다면 좀 더 자세한 정보를 디버거에게 제공할 필요가 있습니다. 리스트에서 방금 설치한 breakpoint를 선택하신 후에 다시 [Data] tab을 누르십시오. l.nLen 이라고 쓰여진 에디트 창 옆에 조그만 화살표가 그려진 버튼을 누르십시오. 그리고 Advanced.. 을 선택하십시오. [Context]라는 그룹에 [Fuction] 에디트 창에 main이라고 쓰십시오. 이는 l.nLen이 main함수에 있는 바로 그 l.nLen 이라고 말해주는 겁니다. 그리고 다시 다 닫으십시오. 물론 리스트의 체크 박스를 다시 체크해 주어서 enable 상태로 만들어 주어야 겠지요.

이제 프로그램을 디버그 모드로 실행하면 처음 l.nLen 이 초기화되는 부분과 strcpy() 함수 내의 l.nLen을 NULL로 overwrite 되는 부분에서 각각 멈추게 될 것입니다. 다시 말해서 l.nLen의 값이 변하는 모든 경우에 멈춥니다.

Mov [edi], dl
이 바로 이 부분에서 l.nLen이 채워지는 것인데, dl의 내용이 NULL이고 edi가 l.nLen의 주소를 포함하고 있다면 바로 현장범이 되는 겁니다. 레지스터의 내용이 보고 싶으시다면 watch나 quick watch 창에서 @edi 혹은 @dl 식으로 써주시면 됩니다. Edi가 가르키는 곳의 내용이 알고 싶으시다면*(char*)@edi 처럼 써주시면 되겠습니다.

- 끝 -

참고적으로 구조체에서 char buf[16]처럼 buf를 16 바이트 크기로 만든 것은 visual c++ 6.0 은 기본적으로 구조체 멤버를 8-byte에 정렬시키기 때문입니다. 만약에 char buf[15] 라고 했다면, buf와 nLen 사이에는 1-byte의 padding byte가 있었을 것이고, nLen은 overwrite 되지 않았을 겁니다. 예제 코드를 복사해서 실험해 보시면 매우 유익할 것이라 믿습니다.


3. 예제 코드

#include "stdafx.h" 

#include <string.h>



struct Line

{

char buf[16];

int nLen;

};



int main(int argc, char* argv[])

{

char src[] = "0123456789012345";

int nSrcLen = strlen(src);



Line l;

l.nLen = nSrcLen;

strcpy( l.buf, src);



return 0;

}

4. 참조

Debuggin Applications – John Robbins [Microsoft press]

Posted in MFC

0 comments

No comments yet. Be the first one to comment!

Profile

corapollo
  • Male
  • 21 years old

Statistics

Entries 1
Comments 0
Page views 640
Last update Dec 4, 2007

Categories