FIX: Hanging Occurs When Using CArrayRowset
ID: Q191738
|
The information in this article applies to:
-
Microsoft Visual C++, 32-bit Editions, version 6.0
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 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