FIX: Run Out of Memory or Assertion in GetBufferSetLength() (148787)



The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), when used with:
    • Microsoft Visual C++, 32-bit Editions 4.0
    • Microsoft Visual C++, 32-bit Editions 4.1

This article was previously published under Q148787

SYMPTOMS

An error can occur when mapping a CString to a SQL_LONGVARCHAR, SQL_VARCHAR, or other SQL data type fields if a driver returns a large precision value from SQLDescribeCol() for the column.

A bug in the MFC ODBC Database classes results in MFC trying to allocate a large chunk of memory to store data that might have this large precision.

In some cases, such as using a memo field with the FoxPro Desktop ODBC driver, a memory allocation of 1 gigabyte may be attempted. Or, as is the case with the Visual FoxPro driver, the MFC Database Classes will try to allocate a negative number of bytes because the return value of the driver is 2 gigabytes and then MFC adds 1 which causes the signed variable to wrap into a negative value. In this case, an assertion occurs in GetBufferSetLength() on line 447 of Strcore.cpp:
    ASSERT(nNewLength >= 0);
				
SQL Server text fields produce the same result.

The problem occurs only when mapping CString variables to variable length fields using the RFX_Text() function.

CAUSE

The fourth argument of the RFX_Text() function takes a value for the user-defined maximum length of the CString. The MFC ODBC database classes fail to constrain the CString buffer to this maximum length.

The following code exists at line 527 of Dbrfx.cpp:
   // Determine string pre-allocation size
   if (cbColumn < (UINT)nMaxLength)
      cbColumn = nMaxLength;
				
It should be:
   if (cbColumn > (UINT)nMaxLength)
      cbColumn = nMaxLength;
				

RESOLUTION

Do one of the following:

  • Don't bind to a CString. For example, use a CLongBinary object. -or-

  • Write your own RFX_Text() function that corrects the problem with the existing RFX_Text(). To do this, copy the contents of the RFX_Text() function from Msdev\Mfc\Src\Dbrfx.cpp, change the name, and modify the code from this:
          if (cbColumn < (UINT)nMaxLength)
              cbColumn = nMaxLength;
    						
    to this:
          if (cbColumn > (UINT)nMaxLength)
             cbColumn = nMaxLength;
    							
You'll need to replace the RFX_Text() function call in your CRecordset's DoFieldExchange() function with a call to your new function. You'll want to copy the RFX_Text() function prototype from Afxdb.h as well so that you are sure to use the correct default parameters.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This bug was corrected in Visual C++ 32- bit Edition version 4.2.

It is also fixed in the Visual C++ 4.1a patch. For information on this patch, see the following Microsoft Knowledge Base article:

150937 Visual C++ Version 4.1 Patch


Modification Type:MajorLast Reviewed:10/24/2003
Keywords:kbBug kbcode kbDatabase kbfix kbVC420fix KB148787