首页 > 百科知识 正文

在CC中应避免句柄泄露,c语言习惯在定义符号常量时使用

时间:2024-04-19 10:00:01 阅读:288 作者:叶落情归

起因

获取.Net Runtime源码(2021.05.19写),看到"Always call CloseHandle in AsmMan::EmitManifest (#50372)",处理文件句柄泄露的代码.通过这个问题,说明即使在在C/C 开发的老司机也会在使用资源的,造成资源泄露的情况.

源码修复文件句柄泄露

在SourceTree看到,代码只是将CloseHandle移到更大的作用域.修复文件句柄泄露.

在CC中应避免句柄泄露,c语言习惯在定义符号常量时使用-第1张

避免文件句柄泄露

代码(部分代码):

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': 0xX\n", pManRes->szName, hr); } }

具体代码在Runtime/src/coreclr/ilasm/asmman.cpp文件EmitManifest方法中.

注意事项

在Windows平台,调用函数返回HANDLE/HMODULE等,在不需要的时候,一定要使用CloseHandle进行关闭,避免资源泄露.

在Linux平台,返回文件描述符的时候,在不使用的时候,记得使用close关闭.

在C语言,使用标准库,如fopen时,要用fclose进行关闭.

不管句柄还是文件描述符的,一定要成对使用.如open/close.

个人能力有限,如果您发现有什么不对,请私信我

如果您觉得对您有用的话,可以点个赞或者加个关注,欢迎大家一起进行技术交流

版权声明:该问答观点仅代表作者本人。如有侵犯您版权权利请告知 cpumjj@hotmail.com,我们将尽快删除相关内容。