C++Builder 10.4.2 clang编译旧代码触发ICE内部错误求解
该内部编译器错误(ICE)是C++ Builder 10.4.2版本clang编译器的已知兼容性问题,由函数修饰符顺序错误、依赖类型声明缺失或SAL注解兼容问题触发,可按以下步骤排查解决:
首先补全依赖头文件引用
必须在函数声明前引入Windows SDK核心头文件,确保BOOL、PSID、PSECURITY_DESCRIPTOR等类型被正确声明,clang编译器对未完全声明的类型容错性远低于经典编译器,类型缺失会直接触发ICE而非普通类型错误:#include <windows.h> #include <securitybaseapi.h> #include <sddl.h> #pragma comment(lib, "advapi32.lib")调整函数修饰符顺序
clang for Windows要求__declspec(dllexport)放在返回值类型最前方,WINAPI放在函数名前方,原代码的修饰符顺序不符合clang的语法解析规则,是触发ICE的核心原因,修正后的声明格式如下:extern "C" { __declspec(dllexport) BOOL WINAPI GetLogonSIDFromToken (HANDLE hToken, PSID *ppsid); __declspec(dllexport) BOOL WINAPI GetCurrentProcessLogonSID (PSID *ppsid); __declspec(dllexport) BOOL WINAPI GetLogonSIDFromAccountName(char *lpszUserName, PSID *ppsid); __declspec(dllexport) VOID WINAPI FreeLogonSID (PSID *ppsid); __declspec(dllexport) PSECURITY_DESCRIPTOR WINAPI AddAceToNewSecurityDescriptor(PSECURITY_DESCRIPTOR psd, PSID psid, DWORD dwType, DWORD dwFlags, DWORD dwMask); __declspec(dllexport) BOOL WINAPI SetUserObjectNullDacl(HANDLE hObject); __declspec(dllexport) BOOL WINAPI AddAceToUserObject(HANDLE hObject, PSID psid, DWORD dwType, DWORD dwFlags, DWORD dwMask); __declspec(dllexport) BOOL WINAPI AddAceToWindowStation(HWINSTA hwinsta, PSID psid); __declspec(dllexport) BOOL WINAPI AddAceToDesktop(HDESK hdesk, PSID psid); }移除SAL注解测试
若仍然触发ICE,先删除所有_In_、_Outptr_opt_类SAL注解,10.4.2版本的clang编译器对自定义函数的SAL注解支持存在bug,无注解的声明可正常编译后再根据需要逐步加注解。采用.def文件导出函数(可选替代方案)
若调整修饰符后仍有问题,可移除声明中的__declspec(dllexport),新增模块定义(.def)文件到项目中,在.def文件中声明导出函数,规避修饰符冲突问题,.def文件示例格式:LIBRARY YOUR_DLL_NAME EXPORTS GetLogonSIDFromToken @1 GetCurrentProcessLogonSID @2 GetLogonSIDFromAccountName @3 FreeLogonSID @4 AddAceToNewSecurityDescriptor @5 SetUserObjectNullDacl @6 AddAceToUserObject @7 AddAceToWindowStation @8 AddAceToDesktop @9单单元指定经典编译器(临时规避方案)
若以上方案都不生效,可将这几个函数的实现单独放到一个独立的.cpp单元中,右键该单元选择【属性】,设置该单元使用经典编译器编译,其余代码保留clang编译器即可正常生成目标程序。
内容的提问来源于stack exchange,提问作者Rob Lambden

