Слишком маленький буфер при копировании строки с использованием wcsncpy_s - PullRequest
4 голосов
/ 09 июля 2010

Этот код C ++ отчасти хромает, но мне нужно его поддерживать.Кажется, я не могу понять проблему "слишком маленький буфер".Я использую Visual Studio 2010. Я придумаю минимальный код, необходимый для воспроизведения на основе значений, которые я вижу в отладчике.Извините, я не буду проверять сам фрагмент.Кроме того, поскольку мой системный буфер обмена «занят» во время отладки, я не могу просто копировать и вставлять, поэтому некоторые ошибки могут появиться где-то, но я буду перепроверять вещи.Поверьте мне, вы не хотите видеть всю функцию - это слишком долго, чтобы иметь какой-либо смысл:)

От tchar.h

#define _tcsncpy_s wcsncpy_s

От afxstr.h:

typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;

Из WinNT.h:

typedef WCHAR TCHAR, *PTCHAR;

Ох, чувак, эти макросы никогда не заканчиваются.Я остановлюсь здесь.Наконец, из myfile.cpp:

CString str; // Actually a function parameter with value "07/02/2010"
DWORD nIndex = 10;
DWORD nLast = 0;
LPCTSTR psz = (LPCTSTR) str; // Debugger says that it also gets "07/02/2010".

CString s;
_tcsncpy_s(
    s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
    nIndex - nLast,
    psz + nLast,
    (size_t) (nIndex - nLast)
);

С этим я нажимаю на утверждение, и отладчик открывает tcsncpy_s.inl со следующим кодом в конце:

  53    ...
  54    if (available == 0)
  55    {
  56        if (_COUNT == _TRUNCATE)
  57        {
  58            _DEST[_SIZE - 1] = 0;
  59            _RETURN_TRUNCATE;
  60        }
  61        RESET_STRING(_DEST, _SIZE);
=>62        _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
  63    }
  64    _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
  65    _RETURN_NO_ERROR;
  66 }
  67
  68

Точки отладчикав строке 62: _RETURN_BUFFER_TOO_SMALL.К сожалению, я не могу просматривать ценности вещей, пока в tcsncpy_s.inl.Возможно, опытный кодер мог бы сказать мне, что здесь происходит?Я полагаю (возможно, неправильно), что этот код довольно старый, и не написан с учетом Unicode.Каков наилучший способ исправить это прилипание к старым дерьмовым ружьям N (пожалуйста, никаких трюков с C ++ 0X или других причудливых вещей) - я просто хочу наложить патч на пулевое ранение.

Ответы [ 3 ]

3 голосов
/ 09 июля 2010

Четвертый аргумент strncpy_s - это количество символов, которые нужно скопировать из исходного буфера, и он не учитывает завершающий ноль - т. Е. На практике, если исходный буфер содержит строку с (nIndex - nLast) или будет скопировано больше символов, затем (nIndex - nLast), а затем также будет добавлен нулевой символ. Поэтому целевой буфер должен быть готов к приему (nIndex - nLast + 1) символов, чтобы также учитывать этот ноль.

Теперь, похоже, ваш +1 делает это, но вы должны также отразить это во втором аргументе strncpy_s, который сообщает, насколько велик буфер. Измените его на (nIndex - nLast + 1), и оно должно работать.

3 голосов
/ 09 июля 2010

Размер, передаваемый в wcsncpy_s (), - это размер буфера, а не количество символов, которое буфер может сохранить.Включает нулевой терминатор.Вам нужно добавить 1.

2 голосов
/ 09 июля 2010

Из документов на wcsncpy_s() (http://msdn.microsoft.com/en-us/library/5dae5d43.aspx):

Эти функции пытаются скопировать первые D символов strSource в strDest, где D - это меньшее число и длина strSource. Если эти символы D поместятся в strDest (размер которого указан как numberOfElements) и все еще оставят место для нулевого терминатора , то эти символы будут скопированы и добавлен завершающий ноль; в противном случае strDest [0] устанавливается в нулевой символ, и вызывается недопустимый обработчик параметров

Таким образом, количество должно быть указано в символах (элементах), а не в байтах, что вы уже делаете, а размер целевого буфера должен учитывать нулевой символ-терминатор, для которого вы создаете место в буфере, но не говоря wcsncpy_s() (известный здесь как _tcsncpy()) о:

_tcsncpy_s(
    s.GetBuffer((int) (nIndex - nLast + 1)), // I added the " + 1" part hoping to fix a bug, but that changed nothing
    nIndex - nLast + 1,
    psz + nLast,
    (size_t) (nIndex - nLast)
);
...