Access Violation Exception in SqlCeConnection disp

2019-06-20 09:08发布

问题:

Application/Code description:

My application is based on c# and uses SQL Server CE and iv'e got this exception only twice at the same code location. the crash with this exception was not introduced till this version. the only change in this version was changing the .net framework to 4.5.2.

I'm getting access violation exception on the dispose of an SqlCeConnection with the following error:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

This exception is not intercepted by the try catch clause of .net- it causes a crash.

In my code I use the following to run

try
{
    var connectionString = string.Format("{0}{1}{2}", "Data Source=", _localDB, ";File Mode=Read Write;Max Database Size=4000;Persist Security Info=False;");
    using (var sqlCeConnection = new SqlCeConnection(connectionString))
    {
        using (var sqlCeCommand = new SqlCeCommand())
        {
            sqlCeCommand.Connection = sqlCeConnection;
            sqlCeCommand.CommandText = "SELECT * FROM Application";
            sqlCeConnection.Open();
            var result = (string)sqlCeCommand.ExecuteScalar();
            isValid = !IsValid(result);
        }
    }
}
catch (Exception ex)
{
    _log.Error("exception", ex);
}

call stack for the first crash:

ntdll!ZwWaitForMultipleObjects+a 
KERNELBASE!WaitForMultipleObjectsEx+e8 
kernel32!WaitForMultipleObjectsExImplementation+b3 
kernel32!WerpReportFaultInternal+215 
kernel32!WerpReportFault+77 
kernel32!BasepReportFault+1f 
kernel32!UnhandledExceptionFilter+1fc 
ntdll! ?? ::FNODOBFM::`string'+2365 
ntdll!_C_specific_handler+8c 
ntdll!RtlpExecuteHandlerForException+d 
ntdll!RtlDispatchException+45a 
ntdll!KiUserExceptionDispatcher+2e 
sqlcese35!__SafeRelease+c 
sqlcese35!Column::`vector deleting destructor'+5c 
sqlcese35!Object::DeleteObjects+39 
sqlcese35!Table::`vector deleting destructor'+45 
sqlcese35!Table::Release+27 
sqlcese35!HashTable::~HashTable+2a 
sqlcese35!Store::~Store+12b 
sqlcese35!Store::Release+2a 
sqlceme35!ME_SafeRelease+17 
DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr ByRef)+78 
[[InlinedCallFrame] (System.Data.SqlServerCe.NativeMethods.SafeRelease)] System.Data.SqlServerCe.NativeMethods.SafeRelease(IntPtrByRef) 
System.Data.SqlServerCe.SqlCeConnection.ReleaseNativeInterfaces()+147 
System.Data.SqlServerCe.SqlCeConnection.Dispose(Boolean)+f1 
System_ni!System.ComponentModel.Component.Dispose()+18 

call stack for the second crash:

ntdll!NtWaitForMultipleObjects+a 
KERNELBASE!WaitForMultipleObjectsEx+e8 
kernel32!WaitForMultipleObjectsExImplementation+b3 
kernel32!WerpReportFaultInternal+215 
kernel32!WerpReportFault+77 
kernel32!BasepReportFault+1f 
kernel32!UnhandledExceptionFilter+1fc 
ntdll! ?? ::FNODOBFM::`string'+2335 
ntdll!_C_specific_handler+8c 
ntdll!RtlpExecuteHandlerForException+d 
ntdll!RtlDispatchException+45a 
ntdll!KiUserExceptionDispatcher+2e 
<Unloaded_sqlcese35.dll>+7c88c 
<Unloaded_sqlceqp35.dll>+102790 
0x06ccc898 
0x06f9efc8 
0x1eca8018 
0x1f207400 
<Unloaded_sqlcese35.dll>+228dc 
0x00000004 
0x2edff008 
0x00000002 
0x00000003 
0x00000004 
<Unloaded_sqlcese35.dll>+3fbd9 
0x06ccc898 
DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr ByRef)+78 
[[InlinedCallFrame] (System.Data.SqlServerCe.NativeMethods.SafeRelease)] System.Data.SqlServerCe.NativeMethods.SafeRelease(IntPtrByRef) 
System.Data.SqlServerCe.SqlCeConnection.ReleaseNativeInterfaces()+147 
System.Data.SqlServerCe.SqlCeConnection.Dispose(Boolean)+f1 
System_ni!System.ComponentModel.Component.Dispose()+1b 

I found some references on the internet that suggests some solutions:

  1. Probable solution: check multithreading issue on the same connection (attempted to read write protected memory. this is often an indication that other memory is corrupt)

    Rejection:
    a. the connection is created in the using brackets and doesn't get reused.
    b. the calling method is called every 5 minutes and verified via the dump file that it was not called simultaneously.

  2. Probable solution: sql ce version mismatch (http://blogs.msdn.com/b/sqlservercompact/archive/2009/05/06/troubleshooting-access-violation-exception-while-using-sql-server-compact-database-with-ado-net-provider.aspx)

    Probable Rejection: I can see in the version installed is 3.5 SP2 (3.5.8080.0) and from the modules located in the dump I can see the sqlceme35.dll, System.Data.SqlServerCe.dll DLL's are with version 3.05.8080.0

  3. Probable solution which is in question is the following: https://stackoverflow.com/a/20492181/1447518

    Probable Rejection: it doesn't sound right from a statistical perspective- the code crashed twice in the same place although there another place in the application code which writes and read to a different DB and the application didn't crash there.

  4. The last thing I was thinking about, may suggest a unload problem of DLLs (take a look at the second call stack). My guess is that the dll's are unloaded from the application while the application needed them in order to do a dispose, but it seams a bit blurry and a 'long shot'

My question is: what may cause the problem, and what is a probable solution?

回答1:

Although this solution is not yet verified, the solution is as follows:

From the second call stack i can see there is unload of native DLL's, my guess was that the dispose method of the SQL connection was using one of the methods it currently disposed. I verified thorough the Process dump that all the SqlCeConnection types were in the process of dispose.

Seeing ErikEj comment made me realize it's will be better if i will take a look in the code differences that was made between SQL-CE 3.5 to 4.0 (System.Data.SqlServerCe.dll).

after viewing the code, i could see that the method of the release was moved to a later position inside the dispose method.

In addition i could see that before calling SafeRelease there was another check that checks if the native DLLs that were needed for safe release was released already- and throw an exception.

bottom line, SQL-CE 4.0 has 2 solutions for the same issue.

my guess is that this issue was caused because of this.

the solution for now was to keep a connection during all the application life-cycle (which has no connection string), this cause the pointer pool to keep the native Dlls in the memory for all the application life-cycle.

the better solution is to move to SQL-CE 4.0 .