Возможная ошибка переполнения буфера в std :: use_facet :: out ()

Я думаю, что нашел ошибку переполнения буфера в объекте VC ++ 10 std :: locale. Я был бы благодарен за второе мнение относительно того, делаю ли я что-то не так.

Приведенный ниже код упрощен, чтобы продемонстрировать проблему. Я пытаюсь преобразовать символ wchar_t (UTF-16) в кодовую страницу (Windows) ANSI 51949 (a.k.a. EUC-KR). Кодовая страница была выбрана потому, что она использует двухбайтовую (DBCS) кодировку.

Я намеренно предоставляю один буфер символов для двухбайтового результата, ожидая, что он потерпит неудачу со статусом «частичный» или «ошибка».

Вместо этого он возвращает состояние «ОК», записывает после конца буфера и вызывает исключение для поврежденного стека, когда он пытается выйти.

#include <iostream>
#include <locale>
#include <cwchar>

typedef std::codecvt<wchar_t, char, mbstate_t> cvt_t;

void PrintResult(cvt_t::result r)
{
switch (r)
{
case cvt_t::ok:
std::cout << "ok\n";
break;
case cvt_t::partial:
std::cout << "partial\n";
break;
case cvt_t::error:
std::cout << "error\n";
break;
case cvt_t::noconv:
std::cout << "noconv\n";
break;
}
}
int main()
{
const wchar_t src = L'안';
char          dst = 0;
std::locale   loc("Korean_Korea.51949");
mbstate_t     state = { 0 };

const cvt_t &facet = std::use_facet<cvt_t>(loc);
cvt_t::result res;

const wchar_t *pSrc;
char *pDst;

res = facet.out(state, &src, &src+1, pSrc, &dst, &dst+1, pDst);
PrintResult(res);

return 0;
}

Заходя внутрь facet.out () с помощью отладчика, я обнаруживаю себя (на нескольких уровнях ниже) в следующей функции:

virtual result __CLR_OR_THIS_CALL do_out(_Statype& _State,
const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
{   // convert [_First1, _Last1) to bytes [_First2, _Last)
_DEBUG_RANGE(_First1, _Last1);
_DEBUG_RANGE(_First2, _Last2);
_Mid1 = _First1, _Mid2 = _First2;
result _Ans = _Mid1 == _Last1 ? ok : partial;
int _Bytes;

while (_Mid1 != _Last1 && _Mid2 != _Last2)
if ((int)MB_CUR_MAX <= _Last2 - _Mid2)
if ((_Bytes = _Wcrtomb(_Mid2, *_Mid1,
&_State, &_Cvt)) < 0)
return (error); // locale-specific wcrtomb failed
else
++_Mid1, _Mid2 += _Bytes, _Ans = ok;
else
{   // destination too small, convert into buffer
_Byte _Buf[MB_LEN_MAX];
_Statype _Stsave = _State;

if ((_Bytes = _Wcrtomb(_Buf, *_Mid1,
&_State, &_Cvt)) < 0)
return (error); // locale-specific wcrtomb failed
else if (_Last2 - _Mid2 < _Bytes)
{   // converted too many, roll back and return previous
_State = _Stsave;
return (_Ans);
}
else
{   // copy converted bytes from buffer
_CSTD memcpy(_Mid2, _Buf, _Bytes);
++_Mid1, _Mid2 += _Bytes, _Ans = ok;
}
}
return (_Ans);
}

Проблема, кажется, заключается в следующем:

На линии if ((int)MB_CUR_MAX <= _Last2 - _Mid2)MB_CURR_MAX (который # определяется для функции ___ mb_cur_max_func (), возвращает «1», а не «2», ожидаемый для символа DBCS.

_CRTIMP int __cdecl ___mb_cur_max_func(void)
{
/*
* Note that we don't need _LocaleUpdate in this function.
* The main reason being, that this is a leaf function in
* locale usage terms.
*/
_ptiddata ptd = _getptd();
pthreadlocinfo ptloci = ptd->ptlocinfo;

__UPDATE_LOCALE(ptd, ptloci);

return ptloci->mb_cur_max;
}

Эта функция, кажется, обращается к глобальной локали, а не к локали, предоставленной при инициализации фасета.

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

std::locale::global(loc);

Все работает нормально (и не работает со статусом «частичный»).

Таким образом, мне кажется, что эта конкретная реализация out() неправильно использует глобальный языковой стандарт для определения MB_CUR_MAX вместо языкового стандарта, предоставленного при создании объекта — и, таким образом, вызывает ошибку переполнения буфера.

Кто-нибудь может указать на мою ошибку (ы) в этом?

——————————
Обновление 20 мая 2013
——————————

Я сообщил об этом MS как ошибка 787227.

Увидеть http://connect.microsoft.com/VisualStudio/feedback/details/787227/buffer-overflow-bug-in-std-use-facet-out

——————————
Обновление 27 июля 2015
——————————

У меня есть электронное письмо от Microsoft, в котором говорится, что эта ошибка исправлена ​​в новой RTM Visual Studio 2015. (Yay)

2

Решение

Задача ещё не решена.

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

Других решений пока нет …