18 Jan
2010
Posted in: 코드
By    2 Comments

DllMain, lpReserved는 어디에 사용될까?


DllMain, lpReserved는 어디에 사용될까?
by 신영진(YoungJin Shin), codewiz at gmail.com, @codemaru, http://www.jiniya.net

지난 주에 프로그램 기능을 확장하면서 이상한 현상을 겪게 되었다. DLL을 확장한 별도의 모듈 타입을 만들어 쓰는데 그 녀석이 CRT만 연결하면 언로딩할 때 문제가 생기는 것이었다. 정확하게는 DLL을 FreeLibrary 할 때에는 문제가 없는데, 프로그램이 종료될 때 문제가 생겼다.

디버거를 돌려보니 프로그램이 종료되는데 이미 언로딩된 그 DLL의 메모리를 참조하는 것이 문제였다. 정확하게는 Fiber Callback을 호출하면서 문제가 생겼다. 왜 이럴까, 라는 생각을 하다가 여친님께서 납시셨다는 소식과 함께 디버깅 세션을 종료했다.

오늘 출근해서 디버깅을 하고 소스를 보고 하다가 엄청난 사실을 알게 되었다. 문제는 DllMain에 있는 lpReserved에 있었다. 우리가 만든 확장 DLL은 이 lpReserved를 사용해서 뭔가를 하도록 되어 있는데 VC++ CRT 소스에는 아래와 같은 엄청난 라인이 숨어 있었던 것이다. #ifdef _DEBUG가 아니라 #ifndef _DEBUG란 사실에 주의해야 한다. 즉, lpreserved를 비교하는 루틴은 릴리즈 버전에만 포함된다는 사실이다. 결국은 우리가 이 lpresreved로 NULL이 아닌 포인터를 공급했고, 그래서 CRT 정리 루틴이 타지 않았고, 프로세스 종료 시에 CRT가 싸놓은 Fiber Callback을 타면서 크래시가 난 것 이었다.

#ifndef _DEBUG
    if ( lpreserved == NULL )
    {
#endif  /* _DEBUG */
        /*
         * The process is NOT terminating so we must clean up...
         */
        /* Shut down lowio */
        _ioterm();

        _mtterm();

        /* This should be the last thing the C run-time does */
        _heap_term();   /* heap is now invalid! */
#ifndef _DEBUG
    }
#endif  /* _DEBUG */

나의 순진한 믿음, lpReserved는 말 그대로 예약된 것일 거라는 사실이 화근이 되었다. 크게는 남의 것을 함부로 건드린 죄라고 할 수 있겠다. 어쨌든 이제는 알게 되었지만 lpReserved는 아무 곳에도 사용되지 않는 값은 아니다. 디버깅 정보에 의하면 lpreserved는 보통 0이고, 특별하게 프로세스가 종료될 때 같이 DLL이 정리되는 상황에서는 1이 넘어 왔다.

 


  • 트랙백 주소: http://www.jiniya.net/wp/archives/703/trackback

관련 글

  • Z

    벌받았네… ㅎㅎ…

  • http://lunapiece.net Lyn

    너한테 안알려준다고햇지 내가 안쓴다곤 안했다~ 뭐 이런느낌인가요 ㅎㅎ