Article ID: 191738
Article Last Modified on 3/2/2005
APPLIES TO
- Microsoft OLE DB 2.7, when used with:
- Microsoft Visual C++ 6.0 Enterprise Edition
- Microsoft Visual C++ 6.0 Professional Edition
- Microsoft Visual C++ 6.0 Standard Edition
This article was previously published under Q191738
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:
- A bug in CVirtualBuffer, which CArrayRowset is derived from, causes the code to go into a loop when it fetches over one page of data (4K).
- If you try to obtain a record that doesn't exist (i.e. prod[51].name when there are only 50 records), the code deliberately causes an access violation as intended. Unfortunately, the code catches the access violation before it gets to the user's code, and it goes into an endless loop.
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 that this is a bug in the Microsoft products that are 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:
Keywords: kbbug kbfix kbconsumer kbdatabase kbtemplate kbdtl kbmdacnosweep kbvs600sp3fix KB191738