这Microsoft CFileDialog 示例是否会导致潜在的内存冲突
Does this Microsoft CFileDialog example lead to a potential memory violation
我在使用 MFC CFileDialog 类时遇到了许多随机崩溃,所以我从这个页面查看了他们的示例代码,内容如下;
#define MAX_CFileDialog_FILE_COUNT 99
#define FILE_LIST_BUFFER_SIZE ((MAX_CFileDialog_FILE_COUNT * (MAX_PATH + 1)) + 1)
CString fileName;
wchar_t* p = fileName.GetBuffer( FILE_LIST_BUFFER_SIZE );
CFileDialog dlgFile(TRUE);
OPENFILENAME& ofn = dlgFile.GetOFN( );
ofn.Flags |= OFN_ALLOWMULTISELECT;
ofn.lpstrFile = p;
ofn.nMaxFile = FILE_LIST_BUFFER_SIZE;
dlgFile.DoModal();
fileName.ReleaseBuffer();
wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2;
wchar_t* start = p;
while( ( p < pBufEnd ) && ( *p ) )
p++;
if( p > start )
{
_tprintf(_T("Path to folder where files were selected: %srnrn"), start );
p++;
int fileCount = 1;
while( ( p < pBufEnd ) && ( *p ) )
{
start = p;
while( ( p < pBufEnd ) && ( *p ) )
p++;
if( p > start )
_tprintf(_T("%2d. %srn"), fileCount, start );
p++;
fileCount++;
}
}
根据我的阅读,语句fileName.ReleaseBuffer();
使缓冲区变量中指向的内存p
无效,因此其余代码很容易遇到内存冲突。 同时,我也假设Microsoft在发布这些示例之前会检查它们。 我在这里错过了一些明显的东西吗? 是否有任何理由在这里使用CString
而不是简单的new
,然后在不再需要缓冲区后使用delete
?
示例代码不是正式文档。此示例是错误的。文档是正确的:
GetBuffer
返回的地址在调用ReleaseBuffer
后可能无效,因为其他CSimpleStringT
操作可能会导致重新分配CSimpleStringT
缓冲区。
此示例使用CString
(通过原始指针和手动内存管理)进行自动内存管理和异常安全。后者很难通过手动内存管理实现正确(尽管此示例也没有正确获得异常安全性)。
如果要修复示例代码以遵守协定,需要进行以下更改:*
- 将
wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2;
替换为const wchar_t* pBufEnd = fileName.GetString() + FILE_LIST_BUFFER_SIZE - 2;
。 - 将
wchar_t* start = p;
替换为const wchar_t* start = fileName.GetString();
- 将对话框调用后代码中所有剩余出现的
p
替换为初始化为const wchar_t* current = fileName.GetString();
的新变量。
这是一个常见的错误。每当开发人员认为他们需要某种char*
时,他们就会忽略他们需要一个const char*
,几乎每个字符串类型都通过成员函数提供。
请注意,示例代码中还有其他错误,尚未在此答案中明确解决(例如另一个答案中解释的字符类型不匹配)。
*检索所选文件列表的C++实现可以在此答案中找到。
您可能会注意到规范和实现之间的差异。上面的代码之所以有效,是因为CString
实现允许它,即使CString
规范禁止它。
并突出示例的质量:它混合了TCHAR
和wchar_t
。在tprintf("%s", start)
字符串start
必须是TCHAR*
但该示例使用wchar_t* start
相关文章:
- C++尝试深度复制唯一指针时出现内存访问冲突
- C++中的内存分配(引发异常:读取访问冲突)
- 在尝试使用CUDA分配内存时,我遇到了访问冲突写入位置错误
- 使用加速进程间创建消息队列 - 内存访问冲突
- C 指针转换会导致内存访问冲突
- 为什么创建进程 API 调用会导致内存访问冲突?
- 访问共享内存时出现读取访问冲突
- 这Microsoft CFileDialog 示例是否会导致潜在的内存冲突
- Python C++扩展 - 内存泄漏或访问冲突
- 如何修复<程序名称>中的"<内存位置>未处理的异常。Visual Studio 2017 中的访问冲突写入位置<内存位置>"
- C 程序内存冲突依赖于 std::cout (?)
- 使用 std::map 作为本地成员的内存访问冲突
- 编译哈希算法时出现内存访问冲突错误
- 使用内存访问冲突错误
- 堆栈引发内存访问冲突
- 使用 Boost::序列化时内存访问冲突
- 调用std::vector::empty()时内存访问冲突读取位置
- 简单加密程序集程序-写入内存位置时发生访问冲突
- 动态分配内存时发生访问冲突
- 修复 std::map 中的冲突内存泄漏