Alex Rivera | Logout

Connection Pool returns Same Exception Instance to Two Threads Using the Same Bad Connection String?

Asked 2009-12-29T23:37:18.607
13

Ok this looks like a major fundamental bug in .NET:

Consider the following simple program, which purposely tries to connect to a non-existent database:

class Program
{
    static void Main(string[] args)
    {            

        Thread threadOne = new Thread(GetConnectionOne);
        Thread threadTwo = new Thread(GetConnectionTwo);            
        threadOne.Start();
        threadTwo.Start();

    }



    static void GetConnectionOne()
    {
        try
        {
            using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;"))
            {
                conn.Open();
            }    
        } catch (Exception e)
        {
            File.AppendAllText("ConnectionOneError.txt", e.Message + "\n" + e.StackTrace + "\n");
        }

    }


    static void GetConnectionTwo()
    {
        try
        {
            using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;"))
            {
                conn.Open();
            }
        }
        catch (Exception e)
        {
            File.AppendAllText("ConnectionTwoError.txt", e.Message + "\n" + e.StackTrace + "\n");
        }

    }
}

Run this program and set breakpoints on the catch blocks. The DBConnection object will attempt to connect for 15 seconds (on both threads), then it will throw an error. Inspect the exception's stack trace, and the stack trace will have TWO call stacks intermingled, as follows:

at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbCo
Edit
Report

1 Answer

3

This is not a bug in the VM. Here is your offending line:

private static readonly DbConnectionFactory _connectionFactory;

Internal to this we have the connection pool. Which stores a reference to the exception that occurred. This opens up a race condition when performing multi-threading.

How do we prove this?

Logically if you use different connection pools then we will not have this race condition. So I reran the same test with a different data source specified in the connection string for each thread. The exceptions are now showing up correctly.

This is really a case of the connection pool not being thread safe.

answered 2009-12-30T01:14:58.257

Your Answer