事件背景
一个小伙伴开开心心写了一段文件夹删除代码,不过在自测的时候出现了事故。
整个C盘文件被一扫而空,不得不重装系统,珍藏资料也难以找回。
问题排查
先上源码。警告:此源码切勿运行
#include <string>
std::wstring dirBackSlashAlign(const std::wstring& strDir)
{
std::wstring strTemp = strDir;
if (!strTemp.empty() && strTemp.back() != L'\\') {
strTemp.push_back(L'\\');
}
return strTemp;
}
void deleteDirRecursively(const std::wstring& dirName)
{
std::wstring strDirName = dirBackSlashAlign(dirName);
std::wstring strFindFiles = strDirName + L"*";
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(strFindFiles.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
std::wstring strFindFile = fd.cFileName;
if (strFindFile == L".." || strFindFile == L".") continue;
strFindFile = strDirName + strFindFile;
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
deleteDirRecursively(strFindFile);
}
else {
//防止误运行,此代码做屏蔽
//::SetFileAttributes(strFindFile.c_str(), FILE_ATTRIBUTE_NORMAL);
//::DeleteFile(strFindFile.c_str());
}
} while (FindNextFile(hFind, &fd));
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
//防止误运行,此代码做屏蔽
//::SetFileAttributes(dirName.c_str(), FILE_ATTRIBUTE_NORMAL);
//::RemoveDirectory(dirName.c_str());
}
void RunTest()
{
deleteDirRecursively(L"\\");
}
问题出在哪里呢?一步步推断看下。
- 删除函数本身正常
- 拿掉删除函数,进行调式发现遍历出了问题,对根目录做了递归遍历
- 为什么是根目录呢,入参传入了
\
,这个意思就是根目录 - 好了,破案了,传参误传了
- 这就好比是linux下进入到根目录,执行
rm -rf
,都是泪呀 - 如果传入的是空字符串呢,那就等于在当前目录执行
rm -rf
,也是泪呀
问题修复
知道了问题原因,就可以做修复了,做下入参有效性判断。
代码如下。
#include "Shlwapi.h"
#pragma comment(lib,"shlwapi.lib")
void deleteDirRecursively(const std::wstring& dirName)
{
//添加有效性检查
if (!PathFileExists(dirName.c_str()))
return;
if (L"\\" == dirName)
return;
//...
}
问题总结
针对这次P0级别的问题修复,对函数入参做防御性有效性判断永远都是对的。