FIX: Access Violation in Application That Calls CManualAccessor::AddParameterEntry (240364)



The information in this article applies to:

  • Microsoft OLE DB, when used with:
    • Microsoft Visual C++, 32-bit Enterprise Edition 6.0
    • Microsoft Visual C++, 32-bit Professional Edition 6.0
    • Microsoft Visual C++, 32-bit Learning Edition 6.0

This article was previously published under Q240364

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 that this is a bug in the Microsoft products that are listed at the beginning of this article.

This problem was corrected in Microsoft Visual C++ .NET.

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)  ) )
			{
...
				

Modification Type:MajorLast Reviewed:10/15/2002
Keywords:kbBug kbConsumer kbDatabase kbDSupport kbDTL kbMDACNoSweep kbNoUpdate kbtemplate KB240364