어젠가 그젠가 MSDN 보다가 재미난 문서를 발견했습니다. 안전한 DllMain을 작성하는 방법에 관한 글인데, 이 곳에서 다운로드 받아서 보실 수 있습니다. DLL의 로딩 과정과 로더 락에 관한 설명을 곁들여서 왜 그런 일들이 문제를 일으키는지 자세히 설명해 준답니다. 심심하지 않으신 분들도 꼭 챙겨보세요. ㅋ~
아래는 문서 내용 중에 괜찮은 부분 같아서 퍼온 겁니다. 의외로 저런 작업들을 하는 코드를 만나는 경우가 많습니다. 대부분 문제가 발생하지 않더라도 어디선간 문제가 발생하고 있다는 것을 의미하는 거겠죠. 좀 더 자세한 시나리오와 함께 문제를 설명해줬으면 했는데 그런 부분이 없는 것이 약간 아쉽더군요.
경고!!!
DllMain에서 다음 작업들은 절대로 하지 말 것.
- LoadLibrary, LoadLibraryEx 호출. 데드락이나 크래시를 유발한다.
- 다른 스레드와 동기화. 데드락을 유발한다.
- 로더 락을 획득하려는 코드가 가지고 있는 동기화 오브젝트를 획득하려는 시도. 데드락을 유발한다.
- CoInitializeEx를 사용한 COM 스레드 초기화. 특정 조건이 충족될 경우 이 함수는 LoadLibraryEx를 호출한다.
- 레지스트리 함수들. 이 함수들은 advapi32.dll에 구현되어 있다. advapi32.dll이 초기화 되지 않았다면 크래시가 발생할 수 있다.
- CreateProcess 호출. 프로세스 생성은 다른 DLL을 로드할 수 있다.
- ExitThread 호출. DLL 디태치(detach) 과정 중에 스레드를 종료하면 로더 락을 다시 획득하도록 만들 수 있다. 이는 데드락이나 크래시가 유발된다.
- CreateThread 호출. 동기화만 하지 않는다면 스레드 생성은 괜찮을 수 있다. 하지만 위험하다.
- 네임드 파이프나 네임드 오브젝트 생성 (2000만 해당한다). 윈도우 2000에서 네임드 오브젝트 생성은 터미널 서비스 DLL에서 구현되어 있다. 해당 DLL이 초기화되어 있지 않다면 크래시.
- CRT에 포함된 메모리 관리 함수들. CRT DLL이 초기화되어 있지 않다면 크래시.
- user32.dll이나 gdi32.dll에 포함된 함수 호출. 일부 함수들은 다른 DLL을 로드하고, 이 사실은 크래시가 발생할 수 있다는 것을 의미한다.
- 관리된 코드 사용.
* 가장 아름다운 DllMain은 존재하지 않는 것이다 (비어 있는 함수 바디).
** 그래도 먼가 하고 싶다면 kernel32.dll에 포함된 함수 중에 위에서 언급되지 않은 것들만 쓰도록 한다. kernel32.dll이 초기화는 운영체제가 보장해 준다.
*** 글로벌 오브젝트에 대한 초기화 코드 또한 DllMain 과정에 포함된다. 따라서 글로벌 오브젝트의 생성자 내지는 초기화 함수 부분에 위에서 언급한 내용이 있어서는 안된다.
**** 초기화를 하지 말란 소린가? 아니다. 지연시키라는 말이다.
요 근래엔 정말 컴터 책은 한 권도 안 읽은 것 같네요. 참신한 책 있으면 추천 좀 해주세용. 《실용주의 프로그래머》나 《The Art Of Unix Programming》을 보면서 흘렸던 눈물이 그립군요. 그나마 제프리 아저씨의 신간이 있었지만, 그마저도 사실 전 전판에 비해서 큰 차이를 보기는 힘들었던 것 같습니당.