x86_64-w64-mingw32-g++交叉编译下fstream判断文件存在失效问题
问题根因
你遇到的是Debian系官方源打包的x86_64-w64-mingw32交叉编译工具链的已知缺陷:其附带的libstdc++标准库没有正确处理Windows平台下文件打开失败的状态同步,打开不存在的文件时不会正确设置std::fstream的失败位,导致所有流状态判断都返回成功。
这个问题和WSL环境无关,是Debian对mingw-w64工具链的打包补丁缺失导致的,原生Windows下的MinGW工具链没有这个问题。
可行解决方案
以下方案均不需要提前判断文件存在再打开,不会引入TOCTOU(时间差攻击)风险:
- 切换使用posix线程模型的交叉编译器
Debian源同时提供win32和posix两种线程模型的mingw交叉编译器,posix版本的libstdc++修复了流状态同步的bug,直接安装对应包后使用即可:
安装命令:
apt update && apt install g++-mingw-w64-x86-64-posix
编译时改用x86_64-w64-mingw32-g++-posix代替默认的编译器即可,不需要修改业务代码。
2. 编译时切换使用libc++标准库
如果不想更换编译器,可以在编译链接时添加参数,使用LLVM的libc标准库代替默认的libstdc,也可以解决这个问题:
编译命令示例:
x86_64-w64-mingw32-g++ test.cpp -o test.exe -stdlib=libc++ -lc++abi
- 通过Win32错误码补充校验
如果必须使用默认的win32线程模型编译器和libstdc++,可以在打开文件后读取当前线程的Win32错误码做补充校验,不需要额外打开文件,底层CreateFile调用的错误码会被正确保留:
示例代码:
#include <fstream> #include <iostream> #include <windows.h> int main(){ std::fstream in_file("test.noexists", std::ios::in|std::ios::binary); bool open_ok = static_cast<bool>(in_file); if (open_ok) { DWORD last_err = GetLastError(); // 排除文件/路径不存在的错误场景 if (last_err == ERROR_FILE_NOT_FOUND || last_err == ERROR_PATH_NOT_FOUND) { open_ok = false; } } if (open_ok) { std::cout << "File exists" << std::endl; } else { std::cout << "File doesn't exist" << std::endl; } }
内容的提问来源于stack exchange,提问作者Daniel Carrasco Marín
相关产品推荐
相关产品推荐

