FIX: Hanging Occurs When Using CArrayRowset

ID: Q191738


The information in this article applies to:


SYMPTOMS

The CArrayRowset class included with the Visual C++ 6.0 OLE DB Templates might hang when retrieving data.


CAUSE

There are two bugs that can cause a hang to occur:

The following code in the CVirtualBuffer class reproduces the bug:

   int Except(LPEXCEPTION_POINTERS lpEP)
   {
      EXCEPTION_RECORD* pExcept = lpEP->ExceptionRecord;
      if (pExcept->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
        return EXCEPTION_CONTINUE_SEARCH;
      BYTE* pAddress = (LPBYTE) pExcept->ExceptionInformation[1];
      VirtualAlloc(pAddress, ((BYTE*)m_pTop - (BYTE*)m_pBase), MEM_COMMIT,
                   PAGE_READWRITE);
      return EXCEPTION_CONTINUE_EXECUTION;
   } 


The purpose of the function is to commit the memory so that the access violation doesn't occur. Unfortunately, m_pTop and m_pBase are equal to the same value so no memory gets allocated. This causes the access violation to keep occurring and the code gets stuck in an endless loop.

If you look at the CArrayRowset operator [] code for the second problem, you should add some method to let the programmer know that the array bounds have been exceeded. Or, if you want to handle this at run time, you may want to throw your own exception. In either case, you need to change the code in the operator [] method.


RESOLUTION

To fix both of the problems described above, you should copy the code of the CArrayRowset template into your own .h file and rename the class. You then need to fix the class.

The following sample demonstrates what the resultant class might look like. The code has added C++ exception handling to throw an exception to indicate that the end of rowset has been reached if the index value specified is too big. If you want to avoid C++ exception handling, you may want to revise the code to throw the access violation to the user and let the user catch the exception and handle it.

Sample Code


   #include <oledberr.h>

   class CDBEndOfRowset
   {
   };

   template <class T, class TRowset = CRowset>
   class CArrRowset:

     public CVirtualBuffer<T>,
     public TRowset

   {

     public:
       CArrRowset(int nMax = 100000) : CVirtualBuffer<T>(nMax)
       {
         m_nRowsRead = 0;
       }


       int Except(LPEXCEPTION_POINTERS lpEP)
       {
          EXCEPTION_RECORD* pExcept = lpEP->ExceptionRecord;
          if (pExcept->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
             return EXCEPTION_CONTINUE_SEARCH;
          BYTE* pAddress = (LPBYTE) pExcept->ExceptionInformation[1];
          VirtualAlloc(pAddress, sizeof(T), MEM_COMMIT, PAGE_READWRITE);
          return EXCEPTION_CONTINUE_EXECUTION;
       }


       T& operator[](int nRow)
       {
         ATLASSERT(nRow >= 0);
         HRESULT hr;
         T* m_pCurrent = m_pBase + m_nRowsRead;
         T* pTEndofRowset = NULL;


         // Retrieve the row if you haven't retrieved it already.
         while ((ULONG)nRow >= m_nRowsRead)
         {
           m_pAccessor->SetBuffer((BYTE*)m_pCurrent);
           __try
          {
            // Get the row.
            hr = MoveNext();

            if (hr == DB_S_ENDOFROWSET)
               throw CDBEndOfRowset();

            if (hr != S_OK)
            {
               *((char*)0) = 0; // Force exception.
            }

          }
          __except(Except(GetExceptionInformation()))
          {
          }

          m_nRowsRead++;
          m_pCurrent++;
         }
         return *(m_pBase + nRow);
       }

       HRESULT Snapshot()
       {
         ATLASSERT(m_nRowsRead == 0);
         ATLASSERT(m_spRowset != NULL);
         HRESULT hr = MoveFirst();
         if (FAILED(hr))
           return hr;
         do
         {
            Write(*(T*)m_pAccessor->GetBuffer());
            m_nRowsRead++;
            hr = MoveNext();
         } while (SUCCEEDED(hr) &&  hr != DB_S_ENDOFROWSET);

         return (hr == DB_S_ENDOFROWSET) ? S_OK : hr;
       }

       // Implementation.
       ULONG   m_nRowsRead;
   }; 


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 Studio 6.0 Service Pack 3. For more information about Visual Studio service packs, please see the following articles in the Microsoft Knowledge Base:

Q194022 INFO: Visual Studio 6.0 Service Packs, What, Where, Why

Q194295 HOWTO: Tell That Visual Studio 6.0 Service Packs Are Installed

Additional query words:


Keywords          : kbservicepack kbtemplate kbOLEDB kbVC600bug kbVS600sp2 kbVS600SP1 kbVS600sp3fix 
Version           : winnt:6.0
Platform          : winnt 
Issue type        : kbbug 

Last Reviewed: May 19, 1999