yuchi's Development Home
글 수 201
한달쯤 된 일이다.우리팀은 G모 회사의 E...모 게임의 배틀넷 솔루션을 제공하고 서포트하는 일을 했다.물론 나는 네트웍쪽에선 손뗀지 오래였기 때문에 신경 끊고 있었다.
한 회사 내에서도 다른 팀을 지원하는 일은 상당히 힘들다. 한 회사도 아닌 다른 회사의 팀을 지원한다는 일은...당연히 훨씬 힘들도 짜증나는 일이다.
일반적으로 자신들의 소스는 완벽하다고 생각한다.그건 우리쪽이나 저쪽이나 마찬가지다.어느쪽이 잘못했다할건 없다.그것이 프로그래머들의 자존심이고 결론적으로 버그를 낸쪽이 누군지 밝혀지면 열라 개쪽먹고 끝나는 그런 스토리이다.버그에 관련된 논쟁 혹은 언쟁이란 말이다.
다시 한달쯤 전으로 돌아가서...G모사의 개발팀과 우리팀의 네트웍쪽 파트와는 위에서 언급한바와 비슷한 상황에 처했다.우리쪽에선 솔루션의 코어를 DLL만으로 제공했기 때문에 그쪽의 의심은 더 컸다.In Process COM이었기 때문에 그쪽 코드에 문제가 있든 이쪽 DLL에 문제가 있든...해당 프로세스는 멋대로 돌아가는 그런 상황이었다.
문제는 생각보다 빨리 잡히지 않았고 우리쪽에선....적어도 우리 코드엔 문제가 없다고 결론지었다.그리고...
우리쪽의 결백(?)을 입증하기 위해 나와 동료 한명이 그 회사로 갔다.
DLL의 내부 코드는 대부분 내가 코딩했기 때문에 나와도 상관이 있었다.나 나름대로는 상당히 테스트를 많이 한 모듈이었다.확신을 갖고있는것은 아니지만 우리 회사의 다른 프로젝트에서도 1년 가까이 사용하고 있었으므로 특별한 문제가 있다고 생각진 않았다.
어쨌든 G..모 사에 도착해서 비졀씨를 디버거로 exe를 따라갔다.듣던대로 콜백함수안에 진입했을때 인자로 받은 값들이 엉망이었다.일단 프로젝트 세팅을 살폈다.struct align이나 기타 설정을 확인하기 위함이었다.별 문제는 없어보였다.
일단 DLL소스 코드를 가져갔으나 헤더파일 문제로 그쪽에서 컴파일 할수는 없었다.그냥 바이너리 코드 레벨에서 디버깅을 하기로 했다.몇번 실행을 해보다가 이상한 점을 발견했다.콜백함수의 프로토타입은 인자 3개를 받도록 되어있었는데 디버거로 진입해
보니 인자 한개짜리 함수로 돌아가고 있었다..
'어라라라라라라라?...씨봉..비졀씨가 돌았나...'
스택을 역으로 트레이스해서 함수를 호출했던 코드로 돌아갔다. 정상적으로 인자 3개를 push하고 있었다.
다시 콜백함수로 돌아와서..디스어셈블된 코드를 봤다.그때...
확실히 확인했다.
인자 두개를 EBX레지스터와 EDX레지스터에서 꺼내고 있었다.
'쉬파....__fastcall이다....'
먼저 프로젝트 세팅을 확인할때 흘낏 보고 그냥 지나쳐버린..calling convention이 __fastcall이었던 것이다.
내가 만든 코드는...콜백함수로 c/c++의 기본 calling convention인 __cdecl 함수를 넣어주게 되어있었다.음..하지만 __cdecl이라고 딱 명시는 하지 않았기 때문에..만일에 컴파일러에서 내가 만든 헤더파일을 인클루드하고...프로젝트 세팅에서 calling convention을 __fastcall 로 바꿔버린다면 DLL측에선 콜백함수가 __cdecl인줄 알지만 실제로는 __fastcall함수가 돌아가게 된다.
참고로 __fastcall에 대해서 설명하자면...인자 두개까지는 bx레지스터와 dx레지스터를 통해 전달하는 호출방식이다.__cdecl은 인자를 모두 스택에 넣고 함수에 진입하면 스택에서 꺼낸다.
그래서...인자로 받은 값이 엉망이었던 것이다.인자 두개는 스택에 있었던 것을...레지스터에서 카피해오니 그게 엉뚱한 값이었던 것이고 pop을 하지 않았으므로 스택 포인터가 어긋나기 시작해서 콜백함수 한번 갔다오면 DLL에선 오동작하는것이었다.
프로젝트 세팅을 __fastcall로 몽땅 세팅해놓은줄도 모르고 우리한테 DLL이 이상하다고 했던 그쪽팀 사람들이 1차적으로 잘못한 일이었지만 나한테도 약간은 잘못이 있었다.콜백함수로 받는 함수타입을 __cdecl로 표기했어야했는데...프로젝트 전체를 __fastcall이나 __stdcall로 설정해놓고 쓰는 경우는 겪어보질 못해서..실수라면 실수였다.
WIndows API를 비롯한 모든 콜백함수들의 타입에 WINAPI가 붙는 이유를 그때서 깨달았다.WINAPI는 __stdcall을 디파인 한것이다.즉 컴파일러의 디폴트 세팅에 상관없이 모든 함수는 __stdcall임을 명시한것이다.
이 일로...자신감이 추락했던 나는..버그 잡았다고 의기양양하게 돌아올수 있었고 자신감도 약간 회복했다.콜백함수에 calling convention을 표기하지 않으면 이런 문제가 생길수도 있다는 것 또한 배웠다.
오가는 시간 빼고 버그 잡는데는 한시간도 안걸렸지만 이 일로 인해서 날려먹은 시간은 몇일이나 된다.
만약 그쪽 프로그래머가 어셈블된 코드를 확인했더라면 쉽게 잡을 수 있었던 버그였다.과연...어셈블리는 디버깅의 필수도구란 여러사람의 주장과 나의 주장이 옳음을 재확인했다.
간만에 자존심 회복하고 잘난체도 할 수 있었던 즐거운 디버깅이었다.
* 여치님에 의해서 게시물 이동되었습니다 (2004-01-09 01:20)
한 회사 내에서도 다른 팀을 지원하는 일은 상당히 힘들다. 한 회사도 아닌 다른 회사의 팀을 지원한다는 일은...당연히 훨씬 힘들도 짜증나는 일이다.
일반적으로 자신들의 소스는 완벽하다고 생각한다.그건 우리쪽이나 저쪽이나 마찬가지다.어느쪽이 잘못했다할건 없다.그것이 프로그래머들의 자존심이고 결론적으로 버그를 낸쪽이 누군지 밝혀지면 열라 개쪽먹고 끝나는 그런 스토리이다.버그에 관련된 논쟁 혹은 언쟁이란 말이다.
다시 한달쯤 전으로 돌아가서...G모사의 개발팀과 우리팀의 네트웍쪽 파트와는 위에서 언급한바와 비슷한 상황에 처했다.우리쪽에선 솔루션의 코어를 DLL만으로 제공했기 때문에 그쪽의 의심은 더 컸다.In Process COM이었기 때문에 그쪽 코드에 문제가 있든 이쪽 DLL에 문제가 있든...해당 프로세스는 멋대로 돌아가는 그런 상황이었다.
문제는 생각보다 빨리 잡히지 않았고 우리쪽에선....적어도 우리 코드엔 문제가 없다고 결론지었다.그리고...
우리쪽의 결백(?)을 입증하기 위해 나와 동료 한명이 그 회사로 갔다.
DLL의 내부 코드는 대부분 내가 코딩했기 때문에 나와도 상관이 있었다.나 나름대로는 상당히 테스트를 많이 한 모듈이었다.확신을 갖고있는것은 아니지만 우리 회사의 다른 프로젝트에서도 1년 가까이 사용하고 있었으므로 특별한 문제가 있다고 생각진 않았다.
어쨌든 G..모 사에 도착해서 비졀씨를 디버거로 exe를 따라갔다.듣던대로 콜백함수안에 진입했을때 인자로 받은 값들이 엉망이었다.일단 프로젝트 세팅을 살폈다.struct align이나 기타 설정을 확인하기 위함이었다.별 문제는 없어보였다.
일단 DLL소스 코드를 가져갔으나 헤더파일 문제로 그쪽에서 컴파일 할수는 없었다.그냥 바이너리 코드 레벨에서 디버깅을 하기로 했다.몇번 실행을 해보다가 이상한 점을 발견했다.콜백함수의 프로토타입은 인자 3개를 받도록 되어있었는데 디버거로 진입해
보니 인자 한개짜리 함수로 돌아가고 있었다..
'어라라라라라라라?...씨봉..비졀씨가 돌았나...'
스택을 역으로 트레이스해서 함수를 호출했던 코드로 돌아갔다. 정상적으로 인자 3개를 push하고 있었다.
다시 콜백함수로 돌아와서..디스어셈블된 코드를 봤다.그때...
확실히 확인했다.
인자 두개를 EBX레지스터와 EDX레지스터에서 꺼내고 있었다.
'쉬파....__fastcall이다....'
먼저 프로젝트 세팅을 확인할때 흘낏 보고 그냥 지나쳐버린..calling convention이 __fastcall이었던 것이다.
내가 만든 코드는...콜백함수로 c/c++의 기본 calling convention인 __cdecl 함수를 넣어주게 되어있었다.음..하지만 __cdecl이라고 딱 명시는 하지 않았기 때문에..만일에 컴파일러에서 내가 만든 헤더파일을 인클루드하고...프로젝트 세팅에서 calling convention을 __fastcall 로 바꿔버린다면 DLL측에선 콜백함수가 __cdecl인줄 알지만 실제로는 __fastcall함수가 돌아가게 된다.
참고로 __fastcall에 대해서 설명하자면...인자 두개까지는 bx레지스터와 dx레지스터를 통해 전달하는 호출방식이다.__cdecl은 인자를 모두 스택에 넣고 함수에 진입하면 스택에서 꺼낸다.
그래서...인자로 받은 값이 엉망이었던 것이다.인자 두개는 스택에 있었던 것을...레지스터에서 카피해오니 그게 엉뚱한 값이었던 것이고 pop을 하지 않았으므로 스택 포인터가 어긋나기 시작해서 콜백함수 한번 갔다오면 DLL에선 오동작하는것이었다.
프로젝트 세팅을 __fastcall로 몽땅 세팅해놓은줄도 모르고 우리한테 DLL이 이상하다고 했던 그쪽팀 사람들이 1차적으로 잘못한 일이었지만 나한테도 약간은 잘못이 있었다.콜백함수로 받는 함수타입을 __cdecl로 표기했어야했는데...프로젝트 전체를 __fastcall이나 __stdcall로 설정해놓고 쓰는 경우는 겪어보질 못해서..실수라면 실수였다.
WIndows API를 비롯한 모든 콜백함수들의 타입에 WINAPI가 붙는 이유를 그때서 깨달았다.WINAPI는 __stdcall을 디파인 한것이다.즉 컴파일러의 디폴트 세팅에 상관없이 모든 함수는 __stdcall임을 명시한것이다.
이 일로...자신감이 추락했던 나는..버그 잡았다고 의기양양하게 돌아올수 있었고 자신감도 약간 회복했다.콜백함수에 calling convention을 표기하지 않으면 이런 문제가 생길수도 있다는 것 또한 배웠다.
오가는 시간 빼고 버그 잡는데는 한시간도 안걸렸지만 이 일로 인해서 날려먹은 시간은 몇일이나 된다.
만약 그쪽 프로그래머가 어셈블된 코드를 확인했더라면 쉽게 잡을 수 있었던 버그였다.과연...어셈블리는 디버깅의 필수도구란 여러사람의 주장과 나의 주장이 옳음을 재확인했다.
간만에 자존심 회복하고 잘난체도 할 수 있었던 즐거운 디버깅이었다.
* 여치님에 의해서 게시물 이동되었습니다 (2004-01-09 01:20)