为何这段Windows API代码会引发堆损坏?
代码问题排查:VS2019启用AddressSanitizer时堆损坏异常
这段代码用于为单个文件调用多文件属性对话框。在Visual Studio 2019中启用地址 sanitizer(/fsanitize=address)编译时,会在系统DLL的MessageBoxW(...)行触发堆损坏异常:
未处理的异常在0x77BCC97F (ntdll.dll)处(ConsoleApplication2.exe中):0xC0000374: 堆已损坏(参数: 0x77C0A918)。
禁用sanitizer编译或使用VS2022编译时无此错误。
#include <windows.h> #include <Shlobj.h> int main() { CoInitialize(nullptr); IShellFolder* pDesktop; // namespace root for parsing the path HRESULT hr = SHGetDesktopFolder(&pDesktop); if (!SUCCEEDED(hr)) { return 0; } HWND m_hWnd = {}; LPCWSTR fileName = L"c:\\Windows\\notepad.exe"; LPWSTR fileNameDup = _wcsdup(fileName); LPITEMIDLIST newPIdL; IDataObject* pDataObject = {}; hr = pDesktop->ParseDisplayName(m_hWnd, nullptr, fileNameDup, nullptr, &newPIdL, nullptr); if (SUCCEEDED(hr)) { LPCITEMIDLIST list[] = { newPIdL }; hr = pDesktop->GetUIObjectOf(m_hWnd, 1, list, IID_IDataObject, nullptr, reinterpret_cast<void**>(&pDataObject)); if (SUCCEEDED(hr)) { hr = SHMultiFileProperties(pDataObject, 0); if (SUCCEEDED(hr)) { MessageBoxW(nullptr, L"Test", L"Test", 0); } pDataObject->Release(); } CoTaskMemFree(newPIdL); } pDesktop->Release(); free(fileNameDup); CoUninitialize(); return 0; }
代码本身的问题检查
从逻辑上看,这段代码没有明显错误:
- COM初始化与反初始化流程规范
- Shell接口对象的
Release调用、内存释放(CoTaskMemFree对应ParseDisplayName的返回值,free对应_wcsdup的分配)都匹配了正确的分配方式 SHMultiFileProperties的调用参数符合要求,IDataObject的获取与释放也没有遗漏
可能的错误原因
- VS2019 AddressSanitizer兼容性缺陷:旧版本的ASan和系统Shell组件(尤其是
SHMultiFileProperties涉及的对话框相关DLL)存在兼容性bug,VS2022对ASan做了更新修复,因此不会触发该问题。 - 堆管理机制冲突:ASan会替换程序默认的堆分配器,而系统Shell的某些内部操作可能使用了未被ASan正确拦截的堆操作,导致堆状态被破坏,后续
MessageBoxW调用时触发堆损坏检测。 - ParseDisplayName的指针修改误判:
IShellFolder::ParseDisplayName会修改传入的字符串指针(移动到解析完成后的位置),虽然代码中未使用修改后的指针,但ASan可能对这种指针变动场景存在误判。可以尝试改用SHParseDisplayName替代IShellFolder::ParseDisplayName,看是否能规避问题。
内容的提问来源于stack exchange,提问作者zenden2k
相关产品推荐
相关产品推荐

