Приводит ли этот пример Microsoft CFileDialog к потенциальному нарушению памяти

Я испытал ряд случайных сбоев с использованием класса 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:  %s\r\n\r\n"), start );
p++;

int fileCount = 1;
while( ( p < pBufEnd ) && ( *p ) )
{
start = p;
while( ( p < pBufEnd ) && ( *p ) )
p++;
if( p > start )
_tprintf(_T("%2d. %s\r\n"), fileCount, start );
p++;
fileCount++;
}
}

От мое чтение об этом, заявление fileName.ReleaseBuffer(); делает память, указанную в буферной переменной pнедопустимый, так что оставшийся код подвержен нарушениям памяти. В то же время я бы также предположил, что Microsoft проверила бы такие примеры до их публикации. Я что-то упускаю здесь очевидное? Есть ли какая-либо причина для использования CString здесь над простым new с последующим delete после того, как буфер больше не требуется?

2

Решение

Пример кода не является официальной документацией. Этот образец неверен. документация правильно:

Адрес, возвращаемый GetBuffer может быть недействительным после звонка ReleaseBuffer потому что дополнительный CSimpleStringT операции могут вызвать CSimpleStringT буфер для перераспределения.

Образец использует CString (поверх необработанных указателей и ручного управления памятью) для автоматического управления памятью и безопасности исключений. Последнее намного сложнее понять с помощью ручного управления памятью (хотя этот пример также не дает права на исключительную ситуацию).

Если вы хотите исправить пример кода в соответствии с договором, необходимо внести следующие изменения:*

  1. замещать wchar_t* pBufEnd = p + FILE_LIST_BUFFER_SIZE - 2; с const wchar_t* pBufEnd = fileName.GetString() + FILE_LIST_BUFFER_SIZE - 2;,
  2. замещать wchar_t* start = p; с const wchar_t* start = fileName.GetString();
  3. Заменить все оставшиеся вхождения p в коде после вызова диалога с новой переменной, инициализированной как const wchar_t* current = fileName.GetString();).

Это распространенная ошибка. Всякий раз, когда разработчик считает, что им нужно char* своего рода, они упускают из виду, что им нужно const char* вместо этого, который почти каждый тип строки предоставляет с помощью функции-члена.


Обратите внимание, что в примере кода есть другие ошибки, которые не были явно учтены в этом ответе (например, несоответствие типов символов, как описано в другом ответ).


* Реализация C ++, которая получает список выбранных файлов, может быть найдена в этом ответ.

3

Другие решения

Вы можете заметить разницу между спецификацией и реализацией. Код выше работает, потому что CString реализация позволяет это, хотя CString спецификация запрещает это.

И чтобы подчеркнуть качество примера: он смешивает TCHAR а также wchar_t, В tprintf("%s", start) строка start должен быть TCHAR* но пример использует wchar_t* start

2

По вопросам рекламы [email protected]