BUG: Access Violation in Application That Calls CManualAccessor::AddParameterEntry
ID: Q240364
|
The information in this article applies to:
-
Microsoft Visual C++, 32-bit Editions, version 6.0
SYMPTOMS
When the CCommand::Open function is called, an access violation may occur when this function calls ICommand::Execute. This problem occurs when CManualAccessor is used for the accessor class and AddParameterEntry is called with the fifth argument (the pLength argument) set to something other than NULL.
CAUSE
There is a bug in the CManualAccesor::AddParameterEntry method. In this function, the nLengthOffset value is incorrectly calculated. Here is the code:
void AddParameterEntry(ULONG nOrdinal, DBTYPE wType, ULONG nColumnSize,
void* pData, void* pLength = NULL, void* pStatus = NULL,
DBPARAMIO eParamIO = DBPARAMIO_INPUT)
{
ATLASSERT(m_nCurrentParameter < m_nParameters);
ULONG nLengthOffset, nStatusOffset;
if (pStatus != NULL)
nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
else
nStatusOffset = 0;
if (pLength != NULL)
nLengthOffset = (BYTE*)pLength - m_pBuffer;
else
nLengthOffset = 0;
Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
m_nCurrentParameter++;
}
RESOLUTION
The code in the "Cause" section should be changed to the following:
void AddParameterEntry(ULONG nOrdinal, DBTYPE wType, ULONG nColumnSize,
void* pData, void* pLength = NULL, void* pStatus = NULL,
DBPARAMIO eParamIO = DBPARAMIO_INPUT)
{
ATLASSERT(m_nCurrentParameter < m_nParameters);
ULONG nLengthOffset, nStatusOffset;
if (pStatus != NULL)
nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
else
nStatusOffset = 0;
if (pLength != NULL)
nLengthOffset = (BYTE*)pLength - m_pParameterBuffer;/*m_pBuffer;*/
else
nLengthOffset = 0;
Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
m_nCurrentParameter++;
}
Note that the m_pBuffer variable is replaced with m_pParameterBuffer.
To make the correction, you can either modify the Atldbcli.h file or create a new AddParameterEntry function that has the modification. For example, you might have a CCommand-derived class that resembles the following:
class CMyCmd: public CCommand< CManualAccessor, CNoRowset >
{
public:
void AddParameterEntry(ULONG nOrdinal, DBTYPE wType, ULONG nColumnSize,
void* pData, void* pLength = NULL, void* pStatus = NULL,
DBPARAMIO eParamIO = DBPARAMIO_INPUT)
{
ATLASSERT(m_nCurrentParameter < m_nParameters);
ULONG nLengthOffset, nStatusOffset;
if (pStatus != NULL)
nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
else
nStatusOffset = 0;
if (pLength != NULL)
nLengthOffset = (BYTE*)pLength - m_pParameterBuffer;/*m_pBuffer*/
else
nLengthOffset = 0;
CManualAccessor::Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
m_nCurrentParameter++;
}
};
STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed
at the beginning of this article.
MORE INFORMATION
Steps to Reproduce Behavior
The following code demonstrates how to reproduce the problem:
...
CSession session ;
hr = session.Open( ds ) ;
CCommand< CManualAccessor, CNoRowset > cmd ;<BR/>
cmd.Create( session, NULL);
cmd.CreateParameterAccessor( 2, &buf, sizeof(buf) );
cmd.AddParameterEntry( 1, DBTYPE_I4,0, &buf, NULL, NULL, DBPARAMIO_INPUT );
cmd.AddParameterEntry( 2, DBTYPE_STR, 32, (PBYTE)&buf + 4, (PBYTE)&buf + 36 , NULL, DBPARAMIO_OUTPUT );
if( SUCCEEDED( hr = cmd.Open(session, "{call sp_myproc(?,?)}", NULL, &lRows, DBGUID_DEFAULT, false) ) )
{
...
Additional query words:
AV first chance exception
Keywords : kbtemplate kbDatabase kbDTL kbOLEDB kbVC kbVC600bug kbGrpVCDB kbDSupport
Version : winnt:6.0
Platform : winnt
Issue type : kbbug