views:

236

answers:

3

Hi,

I am getting this exception when disposing an OdbcDataReader just after retrieving data from the database. The reader is actually disposed while leaving a Using block. This should not be causing any errors as far as I know. Any ideas?

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Data.Common.UnsafeNativeMethods.SQLFreeStmt(OdbcStatementHandle StatementHandle, STMT Option)
at System.Data.Odbc.CMDWrapper.FreeStatementHandle(STMT stmt)
at System.Data.Odbc.OdbcDataReader.Close(Boolean disposing)
at System.Data.Odbc.OdbcDataReader.Dispose(Boolean disposing)
at System.Data.Common.DbDataReader.Dispose()
at MyNamespace.MyClass.MyFunction() in C:\myfile.vb:line 100

Thanks!

EDIT: using Sybase ASE 12.5 database

A: 

Is the exception being thrown in Dispose()? Or before then? It is bad practice for Dispose() to throw, but not unheard of. Sometimes (for example, with WCF) it is desirable to swallow these, but in this case the error sounds like something that shouldn't be swallowed.

A quick search for OdbcDataReader + AccessViolationException shows that this isn't uncommon - but there isn't enough info (database? scenario?) in the question to narrow it down. Personally, I'd start by looking at some of the google hits... (perhaps filtered by your rdbms).

Marc Gravell
From the stacktrace: it is in Dispose()
Laurent
A: 

Probably a bug in the ODBC driver you're using.

Joe
A: 

In general managed/unmanged interactions can be troublesome when it comes to lifetime management.

This looks like a race condition between dispose and a finalizer inside the OdbcDataReader that is probably deleting some unmanaged object that dispose also tries to clean up. They probably both call SQLFreeStmt.

Using guarantees to clean an object up - but it does not guarantee to keep that object alive. [A finalizer can kick in during the last call to an instance method on an object. Therefore the finalizer can kick in during the dispose call. If this happens early enough it is as if the finalizer is called before dispose.]

If this is true, and if the OBDC stuff is a blackbox to you, the best you can do is attempt a workaround.

I would try adding a System.GC.KeepAlive(your_DbDataReader_object) on the last line before the end of your using scope.

For a full overview of the headache that is dispose and finalizers see:GC Discussion This is a very detailed discussion.

morechilli
"but it does not guarantee to keep that object alive." - can you qualify that? In order to call Dispose(), the variable must still be considered in scope; there is a read on the variable, so it shouldn't be collected until after that point...?
Marc Gravell
I've updated my post with a good link for more detail and clarified what I meant - I hope this helps.
morechilli