# V750. BSTR string becomes invalid. Notice that BSTR strings store their length before start of the text.

Анализатор обнаружил, что над указателем на строку в формате BSTR выполняются недопустимые операции. Указатель типа BSTR всегда должен ссылаться на первый символ строки. Если сдвинуть указатель хотя бы на один символ, то получим некорректную BSTR строку.

Такой код крайне опасен:

    BSTR str = foo();
    str++;

Теперь 'str' нельзя использовать как BSTR строку. Если нужно пропустить один символ, следует написать следующий код:

    BSTR str = foo();
    BSTR newStr = SysAllocString(str + 1);

Если вам не нужна BSTR строка, то можно написать следующий код:

    BSTR str = foo();
    const wchar_t *newStr = str;
    newStr++;

Или так:

    BSTR str = foo();
    const wchar_t *newStr = str + 1;

Чтобы понять, почему недопустимо менять значение указателя типа BSTR, процитируем статью с сайта MSDN.

    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 str = foo();
    str += 3;

Мы портим BSTR строку. Указатель ссылается не на начало строки, а куда-то в середину. Соответственно, если мы попытаемся взять длину строки по отрицательному смещению, то мы прочитаем случайное значение. Вернее, предыдущие символы будут интерпретированы как длина строки.

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

- MSDN. BSTR.
- StackOverfow. Static code analysis for detecting passing a wchar_t* to BSTR.
- StackOverfow. BSTR to std::string (std::wstring) and vice versa.
- Robert Pittenger. Guide to BSTR and CString Conversions.