오늘의 개삽질.
VOXEL HORIZON프로젝트의 UWP버전을 빌드하던중 다음의 에러를 마주쳤다.
error C3621: ‘Windows::Foundation::EventHandler<Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs ^>::__abi_IDelegate’: only the default packing value (16) is allowed for WinRT types
에러 내용을 액면 그대로 해석하자면 WinRT타입 개체들(ref class)는 기본 팩킹 사이즈가 16bytes만 허용된다고. 처음엔 되게 황당했다. 이게 뭔 소리여? struct align이라고 표시해줬으면 좀더 빨리 눈치챘을텐데.
하여간 WinRT타입 개체들은 struct align이 x64일 경우 16bytes, x86일 경우 8bytes여야 한다는 얘기다. 나는 컴파일러의 struct align설정을 건드리지 않고 디폴트 그대로 두고 있으므로 컴파일 할 당시의 기본 상태는 x86일때 8bytes, x64일때 16bytes가 맞다. 이 에러가 발생할 수 없다.
즉 이 에러가 발생했다고 하는 것은 코드 어딘가에서 pragma pack()지시어를 잘못 사용했다는 뜻이 된다. 어딘가에서 pragma pack(push,n)한 다음에 pragma pack(pop)을 빼먹었겠지.
pragma pack()이 꽤 많은데 그 중에서 어느 녀석이 문제가 되는지 어떻게 찾는다? push / pop 짝이 맞는지 다 확인해야되는데.
다행히도 컴파일러에서 현재 struct align상태를 아웃풋 윈도우에 출력해주는 지시어가 있다.
pragma pack(show) 다. 이걸로 실수한 코드를 찾았다.
- 일단 프로젝트 전체에서 pragma pack()을 호출하는 코드를 몽땅 찾아냈다. cpp파일은 없고 h파일만 몇개 나온다.
- 그 h파일들의 맨 끝에 pragma pack(show)를 추가했다.
- 이제 빌드 아웃풋 윈도우에 warning C4810: value of pragma pack(show) == 16 라는 식으로 줄줄이 표시가 된다. 여기서 16이 아닌 경우를 찾는다. x64빌드에서 pragma pack()을 실수하지 않았다면 항상 16이 나와야 한다.
- C:\DEV\DAIKON_ROOT\VOXEL_HOIRIZON\MegayuchiDBAccess\typedef_dbaccess.h(138,9): warning C4810: value of pragma pack(show) == 1 로 표시되는 라인이 있다. 이하로는 몽땅 1 bytes align인걸로 나온다. 이 파일에서 pragma pack()을 잘못 사용했구만.
- 해당 h파일을 살펴보니 맨 아래 pragma pack(pop)부분을 잘못 써넣었다. 멍청하게도 pragma pack(pop,1)로 써놓고 있다. 아 이런건 컴파일러가 경고라도 띄워주면 안되냐…물론 내 잘못이긴 하지만.
- pragma pack(pop)으로 고치고 나니 최초의 에러도 사라졌다.
이 코드의 최초 코드가 작성한 데스크탑 프로젝트를 뒤져보니 거기도 pragma pack(pop,1)로 적어놨네.. 으아..뭐 도는덴 큰 문제는 없지. 그래봐야 exe하나고 대부분의 코드는 dll로 빠져있으니까. 하여간 잠재적 버그 하나 잡았다.