사실 이미 인지하고 있었던 문제였긴 한데, 최근에 몇 번 또 당해버렸다.

GoogleTest를 사용하면서 라이브러리를 미리 빌드해놓고 쓰는데 디버그 모드로 빌드한 것과 릴리즈 모드로 빌드한 것 두 가지로 만들고, 디버그 모드로 빌드한 것은 lib 파일 이름 뒤에 'd'를 붙여서 사용하고 있다.

현재 작성중인 코드를 디버그 모드로 빌드할 때는 GoogleTest 라이브러리도 디버그 모드로 빌드한 것을 써야 하고, 릴리즈 모드로 빌드할 때는 라이브러리 역시 릴리즈 모드로 빌드한 것을 써야 한다.

만약 이렇게 하지 않으면 컴파일은 잘 되는데 런타임에 프로그램이 에러를 뱉고 죽어버린다.
그 외에도 std::map을 넘겨받았는데 내용물이 완전 엉망이 되어서 받은 적도 있다.




그런데 CRT를 맞춰봐도 역시 동일하게 프로그램이 죽어버린다. 그러니까 GoogleTest의 라이브러리와 내 작업중인 프로젝트의 프로젝트 속성-C/C++-코드 생성-런타임 라이브러리를 "다중 스레드 DLL(/MD)"로 통일했는데도 계속 발생한다는 말이다.

그래서 이번엔 CRT를 맞춰준 상태에서 Preprocessor의 _DEBUG를 NDEBUG로 바꿔봤는데, 잘 실행이 된다.



여러 가지 조합을 테스트해본 결과 얻어낸 결론:
  1. 런타임 라이브러리를 맞춰줘야 한다. (이건 구글링 결과와 같다)
  2. 그리고 Preprocessor 에서 _DEBUG를 모두 넣어주던가 모두 빼줘야 한다.


2번의 경우 심증이 가는게 있는데, 바로 STL이다. STL의 경우 디버그 모드로 빌드하면 디버그 정보를 담고 경계 검사 등 이것저것 해주는게 많아지는 것으로 알고 있다.

만약 클래스나 구조체가 릴리즈와 디버그 모드일 때 담고 있는 데이터가 달라지게 될 경우, 라이브러리는 이미 코드가 고정되어있는 상태기 때문에 넘겨받은 자료구조 내의 실제로는 존재하지 않는 데이터에 접근한다거나 경계가 달라진다거나 해서 스택이 깨질 수 있다. 이건 실험을 통해 가능하다는 것을 확인했다.

이게 무슨말이냐면, 예를 들어 A라는 라이브러리를 디버그 모드로 빌드했다고 가정하면 이 녀석은 STL 헤더를 디버그용으로 인클루드해서 빌드를 해놓게 된다. 그런데 릴리즈 모드로 B라는 실행 파일이 이 라이브러리를 사용하게 되면 STL 헤더를 릴리즈용으로 인클루드한다. 그러면 쾅~ 서로 자료구조가 같다고 가정하고 링크했지만 실제 자료구조는 다르기 때문에 발생하게 된다. 소켓 통신을 하는데 보내는 사람과 받는 사람이 생각하는 프로토콜 구조가 다른 것과 비슷하다고 할 수 있다.


일단 골치아프지 않으려면 라이브러리도 디버그용과 릴리즈용을 구분해서 쓰는게 좋겠다.



반응형

+ Recent posts