DllMain에서 하지 말아야 할 것

@codemaru · February 05, 2009 · 5 min read

어젠가 그젠가 MSDN 보다가 재미난 문서를 발견했습니다. 안전한 DllMain을 작성하는 방법에 관한 글인데, 이 곳에서 다운로드 받아서 보실 수 있습니다. DLL의 로딩 과정과 로더 락에 관한 설명을 곁들여서 왜 그런 일들이 문제를 일으키는지 자세히 설명해 준답니다. 심심하지 않으신 분들도 꼭 챙겨보세요. ㅋ~

아래는 문서 내용 중에 괜찮은 부분 같아서 퍼온 겁니다. 의외로 저런 작업들을 하는 코드를 만나는 경우가 많습니다. 대부분 문제가 발생하지 않더라도 어디선간 문제가 발생하고 있다는 것을 의미하는 거겠죠. 좀 더 자세한 시나리오와 함께 문제를 설명해줬으면 했는데 그런 부분이 없는 것이 약간 아쉽더군요.

경고!!!
DllMain에서 다음 작업들은 절대로 하지 말 것.

  1. LoadLibrary, LoadLibraryEx 호출. 데드락이나 크래시를 유발한다.
  2. 다른 스레드와 동기화. 데드락을 유발한다.
  3. 로더 락을 획득하려는 코드가 가지고 있는 동기화 오브젝트를 획득하려는 시도. 데드락을 유발한다.
  4. CoInitializeEx를 사용한 COM 스레드 초기화. 특정 조건이 충족될 경우 이 함수는 LoadLibraryEx를 호출한다.
  5. 레지스트리 함수들. 이 함수들은 advapi32.dll에 구현되어 있다. advapi32.dll이 초기화 되지 않았다면 크래시가 발생할 수 있다.
  6. CreateProcess 호출. 프로세스 생성은 다른 DLL을 로드할 수 있다.
  7. ExitThread 호출. DLL 디태치(detach) 과정 중에 스레드를 종료하면 로더 락을 다시 획득하도록 만들 수 있다. 이는 데드락이나 크래시가 유발된다.
  8. CreateThread 호출. 동기화만 하지 않는다면 스레드 생성은 괜찮을 수 있다. 하지만 위험하다.
  9. 네임드 파이프나 네임드 오브젝트 생성 (2000만 해당한다). 윈도우 2000에서 네임드 오브젝트 생성은 터미널 서비스 DLL에서 구현되어 있다. 해당 DLL이 초기화되어 있지 않다면 크래시.
  10. CRT에 포함된 메모리 관리 함수들. CRT DLL이 초기화되어 있지 않다면 크래시.
  11. user32.dll이나 gdi32.dll에 포함된 함수 호출. 일부 함수들은 다른 DLL을 로드하고, 이 사실은 크래시가 발생할 수 있다는 것을 의미한다.
  12. 관리된 코드 사용.

* 가장 아름다운 DllMain은 존재하지 않는 것이다 (비어 있는 함수 바디).
** 그래도 먼가 하고 싶다면 kernel32.dll에 포함된 함수 중에 위에서 언급되지 않은 것들만 쓰도록 한다. kernel32.dll이 초기화는 운영체제가 보장해 준다.
*** 글로벌 오브젝트에 대한 초기화 코드 또한 DllMain 과정에 포함된다. 따라서 글로벌 오브젝트의 생성자 내지는 초기화 함수 부분에 위에서 언급한 내용이 있어서는 안된다.
**** 초기화를 하지 말란 소린가? 아니다. 지연시키라는 말이다.

요 근래엔 정말 컴터 책은 한 권도 안 읽은 것 같네요. 참신한 책 있으면 추천 좀 해주세용. 《실용주의 프로그래머》나 《The Art Of Unix Programming》을 보면서 흘렸던 눈물이 그립군요. 그나마 제프리 아저씨의 신간이 있었지만, 그마저도 사실 전 전판에 비해서 큰 차이를 보기는 힘들었던 것 같습니당.

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중