Top.Mail.Ru
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
V745. A 'wchar_t *' type string is...
menu mobile close menu
Проверка проектов
Дополнительная информация
toggle menu Оглавление

V745. A 'wchar_t *' type string is incorrectly converted to 'BSTR' type string.

19 Янв 2016

Анализатор обнаружил, что со строкой типа wchar_t * начинают работать как со строкой типа BSTR. Это очень подозрительно, и код, скорее всего, содержит ошибку. Чтобы лучше понять, в чем заключается опасность, сначала вспомним, что такое BSTR.

Далее мы процитируем статью с сайта MSDN. Важно понять, в чём проблема, так как предупреждение V745 часто сигнализирует о серьёзных ошибках.

typedef wchar_t OLECHAR;
typedef OLECHAR * BSTR;

BSTR (basic string или binary string) — это строковый тип данных, который используется в COM, Automation и Interop-функциях. Тип BSTR следует использовать во всех интерфейсах. Представление BSTR:

  • Префикс длины. Целое число размером 4 байта, которое отображает длину следующей за ним строки в байтах. Префикс длины указывается непосредственно перед первым символом строки и не учитывает символ-ограничитель.
  • Строка данных. Строка символов в кодировке Unicode. Может содержать множественные вложенные нулевые символы.
  • Ограничитель. Два нулевых символа.

Тип BSTR является указателем, который указывает на первый символ строки, а не на префикс длины.

Память для BSTR-строк выделяется с помощью функций выделения памяти COM, поэтому они могут возвращаться методами без необходимости контроля над выделением памяти.

Представленный ниже код является неправильным:

BSTR MyBstr = L"I am a happy BSTR";

Данный пример собирается (компилируется и линкуется) успешно, но не будет работать должным образом, поскольку у строки отсутствует префикс длины. Если проверить расположение в памяти данной переменной с помощью отладчика, он покажет отсутствие префикса длины размером 4 байта перед началом строки данных.

Правильный вариант кода должен выглядеть так:

BSTR MyBstr = SysAllocString(L"I am a happy BSTR");

Теперь отладчик покажет наличие префикса длины, который равен значению 34. Оно соответствует 17 символам, которые приводится к wide-character строке с помощью строкового модификатора L. Отладчик также покажет двухбайтовый символ-ограничитель (0x0000) в конце строки.

Если передать простую Unicode-строку в качестве аргумента функции COM, которая ожидает BSTR-строку, произойдёт сбой в работе этой функции.

Примечание. Анализатор не может точно предсказать, есть в коде настоящая ошибка или нет. Если неправильная BSTR-строка передаётся куда-то вовне, то произойдёт сбой. Если же BSTR-строка превращается обратно в wchar_t *, то всё хорошо.

Речь идет о подобном коде:

wchar_t *wstr = Foo();
BSTR tmp = wstr;
wchar_t *wstr2 = tmp;

Здесь нет настоящей ошибки, но это "код с запахом", который следует поправить. Так он вызовет меньше недоумения у программиста, сопровождающего код, и анализатор не будет выдавать предупреждение. Следует использовать правильные типы данных:

wchar_t *wstr = Foo();
wchar_t *tmp = wstr;
wchar_t *wstr2 = tmp;

Рекомендуем также ознакомиться со ссылками, приведёнными в конце статьи. Они помогут разобраться с BSTR-строками и тем, как их можно конвертировать в строки других типов.

Рассмотрим ещё один пример:

wchar_t *wcharStr = L"123";
wchar_t *foo = L"12345";
int n = SysReAllocString(&wcharStr, foo);

Описание функции SysReAllocString:

INT SysReAllocString(BSTR *pbstr, const OLECHAR *psz);

Она выделяет новую BSTR и копирует в неё заданную строку, затем освобождает BSTR, на которую указывает pbstr, и помещает по этому адресу указатель на новую BSTR.

В качестве первого аргумента функция ожидает указатель на переменную, содержащую адрес строки в формате BSTR. Но вместо этого ей передают указатель на обыкновенную строку. Так как тип wchar_t ** с точки зрения компилятора — то же самое, что и BSTR *, то этот код успешно компилируется. Но на практике он не имеет смысла и приведёт к ошибке на этапе исполнения.

Правильный вариант кода:

BSTR wcharStr = SysAllocString(L"123");
wchar_t *foo = L"12345";
int n = SysReAllocString(&wcharStr, foo);

Дополнительно рассмотрим ситуацию, когда используется ключевое слово auto. Анализатор выдаёт предупреждение на следующий безобидный код:

auto bstr = ::SysAllocStringByteLen(foo, 3);
ATL::CComBSTR value;
value.Attach(bstr);  // Warning: V745

Это ложное срабатывание, но формально анализатор прав, выдавая предупреждение. Переменная bstr имеет тип wchar_t *. Компилятор языка C++ при выведении типа для auto-переменной не учитывает, что функция возвращает значение типа BSTR. При выведении auto, тип BSTR — это просто синоним whar_t *. Получается, что написанный код эквивалентен:

wchar_t *bstr = ::SysAllocStringByteLen(foo, 3);
ATL::CComBSTR value;
value.Attach(bstr);

Поэтому анализатор PVS-Studio и выдаёт предупреждение, так как не рекомендуется хранить указатель на BSTR строку в обыкновенном wchar_t * указателе. Чтобы устранить предупреждение, следует отказаться в данном месте от auto и написать тип явно:

BSTR *bstr = ::SysAllocStringByteLen(foo, 3);
ATL::CComBSTR value;
value.Attach(bstr);

Это интересный случай, когда оператор auto не помогает, а наоборот — теряет информацию о типе и ухудшает ситуацию.

Другой вариант устранить предупреждение — использовать один из механизмов подавления ложных срабатываний, описанных в документации.

Дополнительные ссылки:

Данная диагностика классифицируется как:

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V745.

close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Я хочу принять участие в тестировании
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам