网站首页 > 博客文章 正文
起因
获取.Net Runtime源码(2021.05.19写),看到"Always call CloseHandle in AsmMan::EmitManifest (#50372)",处理文件句柄泄露的代码.通过这个问题,说明即使在在C/C++开发的老司机也会在使用资源的,造成资源泄露的情况.
源码修复文件句柄泄露
在SourceTree看到,代码只是将CloseHandle移到更大的作用域.修复文件句柄泄露.
代码(部分代码):
m_dwMResSizeTotal = 0;
m_dwMResNum = 0;
for (i = 0; (pManRes = m_ManResLst.PEEK(i)); i++)
{
BOOL fOK = TRUE;
mdToken tkImplementation = mdFileNil;
if (!pManRes->m_fNew) continue;
pManRes->m_fNew = FALSE;
WszMultiByteToWideChar(g_uCodePage, 0, pManRes->szAlias, -1, wzUniBuf, dwUniBuf);
if (pManRes->szAsmRefName)
{
tkImplementation = GetAsmRefTokByName(pManRes->szAsmRefName);
if (RidFromToken(tkImplementation) == 0)
{
report->error("Undefined AssemblyRef '%s' in MResource '%s'\n", pManRes->szAsmRefName, pManRes->szName);
fOK = FALSE;
}
}
else if (pManRes->szFileName)
{
tkImplementation = GetFileTokByName(pManRes->szFileName);
if (RidFromToken(tkImplementation) == 0)
{
report->error("Undefined File '%s' in MResource '%s'\n", pManRes->szFileName, pManRes->szName);
fOK = FALSE;
}
}
else // embedded mgd.resource, go after the file
{
HANDLE hFile = INVALID_HANDLE_VALUE;
int j;
WCHAR wzFileName[2048];
WCHAR* pwz;
pManRes->ulOffset = m_dwMResSizeTotal;
for (j = 0; (hFile == INVALID_HANDLE_VALUE) && (pwzInputFiles[j] != NULL); j++)
{
wcscpy_s(wzFileName, 2048, pwzInputFiles[j]);
pwz = wcsrchr(wzFileName, DIRECTORY_SEPARATOR_CHAR_A);
#ifdef TARGET_WINDOWS
if (pwz == NULL) pwz = wcsrchr(wzFileName, ':');
#endif
if (pwz == NULL) pwz = &wzFileName[0];
else pwz++;
wcscpy_s(pwz, 2048 - (pwz - wzFileName), wzUniBuf);
hFile = WszCreateFile(wzFileName, GENERIC_READ, FILE_SHARE_READ,
0, OPEN_EXISTING, 0, 0); //打开文件
}
if (hFile == INVALID_HANDLE_VALUE)
{
report->error("Failed to open managed resource file '%s'\n", pManRes->szAlias);
fOK = FALSE;
}
else
{
if (m_dwMResNum >= MAX_MANIFEST_RESOURCES) //MAX_MANIFEST_RESOURCES 为1024
{
report->error("Too many resources (implementation limit: %d); skipping file '%s'\n", MAX_MANIFEST_RESOURCES, pManRes->szAlias);
fOK = FALSE;
}
else
{
m_dwMResSize[m_dwMResNum] = SafeGetFileSize(hFile, NULL);
if (m_dwMResSize[m_dwMResNum] == 0xFFFFFFFF)
{
report->error("Failed to get size of managed resource file '%s'\n", pManRes->szAlias);
fOK = FALSE;
}
else
{
m_dwMResSizeTotal += m_dwMResSize[m_dwMResNum] + sizeof(DWORD);
m_wzMResName[m_dwMResNum] = new WCHAR[wcslen(wzFileName) + 1];
wcscpy_s(m_wzMResName[m_dwMResNum], wcslen(wzFileName) + 1, wzFileName);
m_fMResNew[m_dwMResNum] = TRUE;
m_dwMResNum++;
}
//CloseHandle(hFile);
//原先在这里使用CloseHandle 关闭打开的文件句柄,在读取的文件数量小于1024时,是不会出现文件句柄泄露的情况
//在打开文件数量大于的时,代码不会在else作用域执行,才会出现文件句柄泄露
//所以将CloseHandle的作用域放大,就能避免文件句柄泄露
}
CloseHandle(hFile);
}
}
if (fOK || ((Assembler*)m_pAssembler)->OnErrGo)
{
WszMultiByteToWideChar(g_uCodePage, 0, pManRes->szName, -1, wzUniBuf, dwUniBuf);
hr = m_pAsmEmitter->DefineManifestResource( // S_OK or error.
(LPCWSTR)wzUniBuf, // [IN] Name of the resource.
tkImplementation, // [IN] mdFile or mdAssemblyRef that provides the resource.
pManRes->ulOffset, // [IN] Offset to the beginning of the resource within the file.
pManRes->dwAttr, // [IN] Flags.
(mdManifestResource*)&(pManRes->tkTok)); // [OUT] Returned ManifestResource token.
if (FAILED(hr))
report->error("Failed to define manifest resource '%s': 0x%08X\n", pManRes->szName, hr);
}
}
具体代码在Runtime/src/coreclr/ilasm/asmman.cpp文件EmitManifest方法中.
注意事项
在Windows平台,调用函数返回HANDLE/HMODULE等,在不需要的时候,一定要使用CloseHandle进行关闭,避免资源泄露.
在Linux平台,返回文件描述符的时候,在不使用的时候,记得使用close关闭.
在C语言,使用标准库,如fopen时,要用fclose进行关闭.
不管句柄还是文件描述符的,一定要成对使用.如open/close.
个人能力有限,如果您发现有什么不对,请私信我
如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流
猜你喜欢
- 2024-09-12 世界上最好的编程语言PHP图层裁剪服务搭建详解
- 2024-09-12 php之多级目录下查找文件中是否含有某个字符串功能实现
- 2024-09-12 phpcms v9类别调用方法(php class 调用)
- 2024-09-12 某设备产品漏洞挖掘-从JS文件挖掘RCE
- 2024-09-12 PHP页面缓存简单实现(php页面缓存简单实现方法)
- 2024-09-12 Laravel 创建自己的扩展包 package
- 2024-09-12 php 一步步实现mvc架构——view篇
- 2024-09-12 php写的mysql备份恢复的类(php备份mysql数据库)
- 2024-09-12 29、php类加载器实现(php类自动加载)
- 2024-09-12 轻松搭建基于 Serverless 的 ThinkPHP 应用
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- powershellfor (55)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)