V750. BSTR string becomes invalid. Notice that BSTR strings store their length before start of the text.
The analyzer has detected that invalid operations are performed on a pointer to a BSTR-formatted string. A pointer of the BSTR type must always point to the first character of the string; shifting the pointer by even one character results in an invalid BSTR string.
The following code example is very dangerous:
BSTR str = foo();
str++;
The 'str' string can no longer be used as a BSTR string. If you need to skip one character, use the following code instead:
BSTR str = foo();
BSTR newStr = SysAllocString(str + 1);
If you don't need the BSTR string, rewrite the code in the following way:
BSTR str = foo();
const wchar_t *newStr = str;
newStr++;
Another version:
BSTR str = foo();
const wchar_t *newStr = str + 1;
To see why changing the value of a BSTR pointer is forbidden, let's examine the article form MSDN.
typedef wchar_t OLECHAR;
typedef OLECHAR * BSTR;
A BSTR (Basic string or binary string) is a string data type that is used by COM, Automation, and Interop functions. Use the BSTR data type in all interfaces that will be accessed from script.
- A length prefix. A four-byte integer that contains the number of bytes in the following data string. It appears immediately before the first character of the data string. This value does not include the terminal null character.
- A data string. A string of Unicode characters. May contain multiple nested null characters.
- A terminator. Two null characters.
A BSTR is a pointer that points to the first character of the data string, not to the length prefix.
BSTRs are allocated using COM memory allocation functions, so they can be returned from methods without the need to control memory allocation.
The following code is incorrect:
BSTR MyBstr = L"I am a happy BSTR";
This code builds (compiles and links) correctly, but it will not function properly because the string does not have a length prefix. If you use a debugger to examine the memory location of this variable, you will not see a four-byte length prefix preceding the data string.
Instead, use the following code:
BSTR MyBstr = SysAllocString(L"I am a happy BSTR");
A debugger that examines the memory location of this variable will now reveal a length prefix containing the value 34. This is the expected value for a 17-byte single-character string that is converted to a wide-character string through the inclusion of the "L" string modifier. The debugger will also show a two-byte terminal null character (0x0000
) that appears after the data string.
If you pass a simple Unicode string as an argument to the COM function that is expecting a BSTR, the COM function will fail.
When using code like this...
BSTR str = foo();
str += 3;
...the BSTR string gets breaks. The pointer now points to the middle of the string instead of its first character. So, if we attempt to retrieve the string length using a negative offset, we will read a random value—in fact, the preceding characters will be interpreted as the string length.
References:
- 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.