Analyzers
Talk to fellow users of Intel Analyzer tools (Intel VTune™ Profiler, Intel Advisor)
4995 Discussions

False Positive Kernel and Memory Leakage with COM and OleDB SQL 2008 Native Client?

driekus77
Beginner
511 Views

Dear all,

We are busy checking for Memory leaks in our Application with a trail of Intel Parallel C/C++ Studio with Inspector 2011 XE.

It looks we are getting lots of false Positives in our COM/OleDB SQL Provider.

I even wrote a small test program (See code beneath) witch causes lots of kernel and memory leaks originating in the Microsoft SQL OleDB Native Client 2008 dll.

The code:

[cpp]// compile with: ole32.lib
//#define UNICODE
//#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID
#define OLEDBVER 0x0250 // to include correct interfaces

#include
#include
#include
#include
#include
#include

#include

#define NUMROWS_CHUNK 5

// AdjustLen supports binding on four-byte boundaries.
_inline DBLENGTH AdjustLen(DBLENGTH cb) {
return ( (cb + 3) & ~3 );
}


// Get the characteristics of the rowset (the IColumnsInfo interface).
HRESULT GetColumnInfo ( IRowset* pIRowset,
DBORDINAL* pnCols,
DBCOLUMNINFO** ppColumnsInfo,
OLECHAR** ppColumnStrings ) {
usoft::CCountedPtr pIColumnsInfo;
HRESULT hr;

*pnCols = 0;
if (FAILED(pIRowset->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo.PtrNullified())))
return (E_FAIL);

hr = pIColumnsInfo->GetColumnInfo(pnCols, ppColumnsInfo, ppColumnStrings);

if (FAILED(hr)) {} /* Process error */

//pIColumnsInfo->Release();
return (hr);
}

// Create binding structures from column information. Binding structures
// will be used to create an accessor that allows row value retrieval.
void CreateDBBindings ( DBORDINAL nCols,
DBCOLUMNINFO* pColumnsInfo,
DBBINDING** ppDBBindings,
BYTE** ppRowValues ) {
ULONG nCol;
DBLENGTH cbRow = 0;
DBLENGTH cbCol;
DBBINDING* pDBBindings;
BYTE* pRowValues;

pDBBindings = new DBBINDING[nCols];
if (!(pDBBindings /* = new DBBINDING[nCols] */ ))
return;

for ( nCol = 0 ; nCol < nCols ; nCol++ ) {
pDBBindings[nCol].iOrdinal = nCol + 1;
pDBBindings[nCol].pTypeInfo = NULL;
pDBBindings[nCol].pObject = NULL;
pDBBindings[nCol].pBindExt = NULL;
pDBBindings[nCol].dwPart = DBPART_VALUE;
pDBBindings[nCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
pDBBindings[nCol].eParamIO = DBPARAMIO_NOTPARAM;
pDBBindings[nCol].dwFlags = 0;
pDBBindings[nCol].wType = pColumnsInfo[nCol].wType;
pDBBindings[nCol].bPrecision = pColumnsInfo[nCol].bPrecision;
pDBBindings[nCol].bScale = pColumnsInfo[nCol].bScale;

cbCol = pColumnsInfo[nCol].ulColumnSize;

switch (pColumnsInfo[nCol].wType) {
case DBTYPE_STR: {
cbCol += 1;
break;
}

case DBTYPE_WSTR: {
cbCol = (cbCol + 1) * sizeof(WCHAR);
break;
}

default:
break;
}

pDBBindings[nCol].obValue = cbRow;
pDBBindings[nCol].cbMaxLen = cbCol;
cbRow += AdjustLen(cbCol);
}

pRowValues = new BYTE[cbRow];
*ppDBBindings = pDBBindings;
*ppRowValues = pRowValues;
}

int main() {
usoft::CCountedPtr pIMalloc;
usoft::CCountedPtr pISourceRowset;
usoft::CCountedPtr pIRowset;
usoft::CCountedPtr pIAccessor;
DBBINDING* pDBBindings = NULL;

HROW* pRows = new HROW[500];
HACCESSOR hAccessorRetrieve = NULL;
ULONG DSSeqNumber = 0;

HRESULT hr;
DBORDINAL nCols;
DBCOLUMNINFO* pColumnsInfo = NULL;
OLECHAR* pColumnStrings = NULL;
DBBINDSTATUS* pDBBindStatus = NULL;

BYTE* pRowValues = NULL;
DBCOUNTITEM cRowsObtained;
ULONG iRow;
char* pMultiByte = NULL;
short* psSourceType = NULL;
BYTE* pDatasource = NULL;

if (!pRows)
return (0);

// Initialize COM library.
CoInitialize(NULL);

// Retrieve the task memory allocator
CoGetMalloc( MEMCTX_TASK, &pIMalloc.PtrNullified() );


// Initialize the enumerator.
if (FAILED(CoCreateInstance(CLSID_SQLNCLI10_ENUMERATOR,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISourcesRowset,
(void**)&pISourceRowset.PtrNullified()))) {
// Process error.
return TRUE;
}

// Retrieve the source rowset.
hr = pISourceRowset->GetSourcesRowset(NULL, IID_IRowset, 0, NULL, (IUnknown**)&pIRowset.PtrNullified());

//pISourceRowset->Release();
if (FAILED(hr)) {
// Process error.
return TRUE;
}

// Get the description of the enumerator's rowset.
if (FAILED(hr = GetColumnInfo(pIRowset, &nCols, &pColumnsInfo, &pColumnStrings))) {
// Process error.
goto SAFE_EXIT;
}

// Create the binding structures.
CreateDBBindings(nCols, pColumnsInfo, &pDBBindings, &pRowValues);
pDBBindStatus = new DBBINDSTATUS[nCols];

if (sizeof(TCHAR) != sizeof(WCHAR))
pMultiByte = new char[pDBBindings[0].cbMaxLen];

if (FAILED(pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor.PtrNullified()))) {
// Process error.
goto SAFE_EXIT;
}

// Create the rowset accessor.
if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
nCols,
pDBBindings,
0,
&hAccessorRetrieve,
pDBBindStatus))) {
// Process error.
goto SAFE_EXIT;
}

// Process all the rows, NUMROWS_CHUNK rows at a time.
while (SUCCEEDED(hr))
{
hr = pIRowset->GetNextRows(NULL, 0, NUMROWS_CHUNK, &cRowsObtained, &pRows);
if( FAILED(hr)) {
// process error
}
if (cRowsObtained == 0 || FAILED(hr))
break;

for (iRow = 0 ; iRow < cRowsObtained ; iRow++) {
// Get the rowset data.
if (SUCCEEDED(hr = pIRowset->GetData(pRows[iRow], hAccessorRetrieve, pRowValues))) {
psSourceType = (short *)(pRowValues + pDBBindings[3].obValue);

if (*psSourceType == DBSOURCETYPE_DATASOURCE) {
DSSeqNumber = DSSeqNumber + 1; // Data source counter.
pDatasource = (pRowValues + pDBBindings[0].obValue);

if ( sizeof(TCHAR) != sizeof(WCHAR) ) {
WideCharToMultiByte(CP_ACP,
0,
(WCHAR*)pDatasource,
-1,
pMultiByte,
static_cast(pDBBindings[0].cbMaxLen),
NULL,
NULL);

printf( "DataSource# %d\tName: %S\n",
DSSeqNumber,
(WCHAR *) pMultiByte );
}
else {
printf( "DataSource# %d\tName: %S\n",
DSSeqNumber,
(WCHAR *) pDatasource );
}
}
}
}
pIRowset->ReleaseRows(cRowsObtained, pRows, NULL, NULL, NULL);
}

SAFE_EXIT:
// Do the clean-up.
if ( pRows )
delete [] pRows;
if ( pRowValues )
delete [] pRowValues;
if ( pDBBindings )
delete [] pDBBindings;
if ( pDBBindStatus )
delete [] pDBBindStatus;

if ( pColumnsInfo )
pIMalloc->Free(pColumnsInfo);
if ( pColumnStrings )
pIMalloc->Free(pColumnStrings);

pISourceRowset = NULL;
pIRowset = NULL;
pIAccessor = NULL;
pIMalloc = NULL;

// Release COM library.
CoUninitialize();

return TRUE;
}
[/cpp]

The results from Intel Inspector 2011 XE:

Results running OleDB SQL Native Client 2008 test program

Can anybody tell me if these COM+ / OleDB (Kernel/Memory)Leakages are false positives or not?

Kind regards,

Henry Roeland

0 Kudos
7 Replies
SergeyKostrov
Valued Contributor II
511 Views
Hi Henry,

Quoting driekus77
...
Can anybody tell me if these COM+ / OleDB (Kernel/Memory) Leakages are false positives or not?


...
IMalloc
ISourcesRowset
IRowset
IAccessor
...

I don'tthink that there areany memory leaks in these fundamental Generic and OLE DB COM interfaces.
You can doverification with a CRTset ofmemory leaks detection functions:

http://software.intel.com/en-us/forums/showthread.php?t=105996&o=a&s=lr Post #8

Howeverit will onlycheck your application.

Best regards,
Sergey

0 Kudos
driekus77
Beginner
511 Views

Hi Sergey,

Thanks for you quick response.

I fixed one of the "Unitialized memory access" but I have another one thats still bordering me:

Results OledbExample application

The code is an example from Microsoft: http://msdn.microsoft.com/en-us/library/ms403324.aspx

I've added CCountedPtr and Boost smart Pointers and thats it.

I don't know who to trust the most Intel or Microsoft? :-)

Because the rest of the &...PtrNullified() calls look oke its seems to be something with the GetSourcesRowset function???

The API description of this function tells that the 5th parameter is an [in] :http://msdn.microsoft.com/en-us/library/ms711200

My jugement is that the GetSourcesRowset function is reading the Uninitialized memory before it is written???

Or do I have to Initialize the COM+ Object cpIRowset with something ?? (I have no qlue how to do this because its an Interface).

Is my jugement right?

Hope to hear from you.

Best regards,

Henry Roeland

0 Kudos
driekus77
Beginner
511 Views

I've tested also with the newest SQL Server 2012 Native Client (v11).

This one has 2 errors less that the SQLOLEDB driver I used in above print.

This tells me that Microsoft has some errors in this area.

But still memory and kernel leak on "CoInitialize(NULL)" and "CoUninitialize()".

Best regards,

Henry Roeland

0 Kudos
SergeyKostrov
Valued Contributor II
511 Views
Quoting driekus77
...This tells me that Microsoft has some errors in this area.But still memory and kernel leak on
"CoInitialize(NULL)" and "CoUninitialize()".


Hi Henry,

That was discussed a couple of weeks ago on the forumand Intel Inspector XE really reports some "memory leaks"
on these two fundamental ( sorry for mentioning and stressingthis again )COM API functions. Do you see that I used
quotation-marks around memory leaks expression?

A test-case is as follows:
...
_tprintf( _T("Sub-Test Started\n") );

for( int t = 0; t < 65536; t++ ) // 2^16
{
// Sub-Test 1 - No Memory Leaks
::CoInitialize(NULL );
::Sleep( 1 );
::CoUninitialize();

// Sub-Test 2 - Forced Memory Leaks ( should allocate 1GB of memory )
// int *pData = ( int * )malloc(4096 * sizeof( int ) );
}

_tprintf( _T("Sub-Test Completed\n") );
...

and take a look at the Windows Task Manager 'Performance' property page. I tested that test-casemany times and
I have not seen any increase inallocated memory for a test application when a'Sub-Test 2' is commented.
Than, uncomment a line with a forced memory leaks 'Sub-Test 2'and repeat the test.

Best regards,
Sergey

0 Kudos
SergeyKostrov
Valued Contributor II
511 Views
...take a look at the Windows Task Manager 'Performance' property page. I tested that test-casemany times and
I have not seen any increase inallocated memory for a test application when a'Sub-Test 2' is commented.
Than, uncomment a line with a forced memory leaks 'Sub-Test 2'and repeat the test.

Here is a screenshot of how it should look like:

0 Kudos
SergeyKostrov
Valued Contributor II
511 Views
Quoting driekus77
...I don't know who to trust the most Intel or Microsoft? :-) ...


Trust both companies and verify both companies. Intel and Microsoft are spending billions of dollars on R&D
every year and they try todeliver as better as possible, in terms of quality, software. However, "...nobody is perfect..." and
sometimes errors are made. So, do your own verifications. Hereare pseudo-codes on a set oftest-cases:

vodsi main( void )
{
// Test #1
for( 65536 times ) // Monitor 'Performance' property page inWindows Task Manager
{
CoInitialize( NULL )
CoUnitialize()
}

// Test #2
for(32768 times ) // Monitor 'Performance' property page inWindows Task Manager
{
CoInitialize( NULL )
CreateInstance( IID_Interface1, pInterface1)
ReleaseInterface( pInterface1 )
CoUnitialize()
}

// Test #3
for(16384 times ) // Monitor 'Performance' property page inWindows Task Manager
{
CoInitialize( NULL )
CreateInstance( IID_Interface1, pInterface1)
pInterface1->Method1( ... )
ReleaseInterface( pInterface1 )
CoUnitialize()
}

// Test #4
for(8192 times ) // Monitor 'Performance' property page inWindows Task Manager
{
CoInitialize( NULL )
CreateInstance( IID_Interface1, pInterface1)
pInterface1->Method1( ... )
CreateInstance( IID_Interface2, pInterface2)
pInterface2->Method2( ... )
ReleaseInterface( pInterface2 )
ReleaseInterface( pInterface1 )
CoUnitialize()
}

// and so on
}

0 Kudos
SergeyKostrov
Valued Contributor II
511 Views
Quoting driekus77
...Or do I have to Initialize the COM+ Object cpIRowset with something ?? (I have no qlue how to do this because its an Interface)...


I just checkedtopics 'IRowset Interface' and'Fetching Rows' in'SQL Server 2005Books Online' and I haven't found
anything about some additional initialization of IRowset OLE DB interface. A class-wrapper of the interface ( generated
from a tlb-library, for example ) should doinitializations of allmembers. If Microsoft software developers
missed to initialize some member(s) of the class-wrapper than Intel Inspector XE could report it.

Best regards,
Sergey

0 Kudos
Reply