返回 2026-05-16
⚙️ 工程

CreateFileMapping 总是报告 ERROR_ALREADY_EXISTS 的真相The case of the Create­File­Mapping that always reported ERROR_ALREADY_EXISTS

微软资深工程师 Raymond Chen 分析了一个罕见但令人困惑的问题:某些情况下 CreateFileMapping 会持续返回 ERROR_ALREADY_EXISTS,即使文件映射尚未存在。根本原因在于跨进程同步机制缺陷,当多个进程同时尝试创建同名映射时,竞争条件导致错误状态误报。解决方案涉及正确使用命名空间隔离与原子性检查。

Raymond Chen

一位客户报告称,每当他们的程序调用 CreateFileMapping 创建命名文件映射时,调用都会成功,但生成的映射大小并非他们所需。他们请求创建一个 1MB 大小的映射,但实际返回的只有 4KB,这导致程序在访问第 4097 个字节时崩溃。另外还有一个细节:他们在创建文件映射后调用 GetLastError(),会得到 ERROR_ALREADY_EXISTS,似乎表明该文件映射已经存在。但这种情况甚至在他们首次运行程序时就发生了,甚至在系统重启后也会立即出现,按理说不应该有残留的映射。

HANDLE h = CreateFileMappingW(INVALID_FILE_HANDLE, nullptr, PAGE_READWRITE,
            0, 65536, L"MyFileMapping");

我猜测他们之所以收到 ERROR_ALREADY_EXISTS,是因为映射本身已经存在。(真是不出所料!)

客户在全新重启后使用 Process Explorer 搜索所有进程,查看是否有任何进程已持有其文件映射句柄,结果发现确实有一个:那是他们网络摄像头配套的一款软件,并且它恰好使用了完全相同且毫无创意的文件映射名称。

客户在其文件映射名称后附加了一个 GUID,从而消除了意外名称冲突的可能性。(当然,仍可能存在有意图的名称冲突。对于拥有相同或更高级别权限的攻击者,你无法完全防范。)

延伸阅读:你可以给你的车命名,也可以给内核对象命名,但两者之间存在质的区别。

作者

Raymond 参与 Windows 的发展已有三十多年。2003 年,他创办了一个名为 The Old New Thing 的网站,其受欢迎程度远超他的想象,这一发展至今仍让他感到些许不安。该网站催生了一本同名书籍《The Old New Thing》(Addison Wesley, 2007)。他偶尔会在 Windows Dev Docs 的 Twitter 账号上出现,讲述一些看似无用实则无用的故事。

需要完整排版与评论请前往来源站点阅读。