The CComBSTR constructor does not always allocate sufficient space in ATL (241857)



The information in this article applies to:

  • The Microsoft Active Template Library (ATL) 3.0, when used with:
    • Microsoft Visual C++, 32-bit Enterprise Edition 6.0
    • Microsoft Visual C++, 32-bit Professional Edition 6.0
    • Microsoft Visual C++, 32-bit Learning Edition 6.0

This article was previously published under Q241857

SYMPTOMS

The following fragment of code produces different results with ATL version 2.1 and ATL version 3.0:
char rawStr[128] = "01234567839";
CComBSTR bstr (4, rawStr);
				
In ATL 2.1, the new bstr is L"0123"; however, in ATL 3.0, the new bstr is L"012".

CAUSE

This problem is due to a bug in the A2WBSTR function in the Atlconv.h file:
inline BSTR A2WBSTR(LPCSTR lp, int nLen = -1)
{
 USES_CONVERSION;
 BSTR str = NULL;
 int nConvertedLen= MultiByteToWideChar(_acp, 0, lp, nLen, NULL, NULL)-1;
 str = ::SysAllocStringLen(NULL, nConvertedLen);
 if (str != NULL)
 {
  MultiByteToWideChar(_acp, 0, lp, -1,
   str, nConvertedLen);
 }
 return str;
}
				
If the MultiByteToWideChar function's fourth argument is -1, the string is assumed to be NULL-terminated and the number of bytes returned will include the NULL character. The result of this function should not subtract 1 (one) if nLen does not equal -1; it should only do this if nLen is equal to -1.

RESOLUTION

There are two ways to correct this problem:

Method 1

Use one of the conversion macros to wrap the string passed into the constructor:
CComBSTR bstr(5, T2OLE(buf));

-or-

CComBSTR bstr(5, OLESTR("01234");
This method uses the CComBSTR(int nSize, LPCOLESTR sz) constructor, which calls ::SysAllocStringLen, and then returns a BSTR with the number of characters equal to nSize.

Method 2

Change the incorrect code in Atlconv.h for the A2WBSTR function:
  1. Change the code in Atlconv.h for the A2WBSTR function from the following:
    inline BSTR A2WBSTR(LPCSTR lp, int nLen = -1)
    {
      USES_CONVERSION;
      BSTR str = NULL;
      int nConvertedLen = MultiByteToWideChar(_acp, 0, lp, nLen, NULL, NULL)-1;
      str = ::SysAllocStringLen(NULL, nConvertedLen);
      if (str != NULL)
      {
        MultiByteToWideChar(_acp, 0, lp, -1, str, nConvertedLen);
      }
      return str;
    }
    						
    to the following:
    inline BSTR A2WBSTR(LPCSTR lp, int nLen = -1)
    {
       USES_CONVERSION;
       BSTR str = NULL;
       int nConvertedLen = MultiByteToWideChar(_acp, 0, lp,
         nLen, NULL, NULL);
     
       // BUG FIX #1 (from Q241857): only subtract 1 from 
       // the length if the source data is nul-terminated
       if (nLen == -1)
          nConvertedLen--;
     
       str = ::SysAllocStringLen(NULL, nConvertedLen);
       if (str != NULL)
       {
         MultiByteToWideChar(_acp, 0, lp, nLen, str, nConvertedLen);
       }
       return str;
    }
    						
  2. Save Atlconv.h.
  3. On the Build menu, click Rebuild All. You need to do this on a Debug or ReleaseMinDependency build so that the modified code above is linked into your code.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.

Modification Type:MajorLast Reviewed:6/2/2005
Keywords:kbtshoot kbBug kbString KB241857 kbAudDeveloper