rpcrt4: Fix a race when server grabs a connection from the list of active connections.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2017-06-08 14:16:50 +02:00 committed by Alexandre Julliard
parent ab2760ec33
commit e889b027ef
1 changed files with 34 additions and 24 deletions

View File

@ -3373,39 +3373,49 @@ void rpcrt4_conn_release_and_wait(RpcConnection *connection)
}
}
RpcConnection *RPCRT4_GrabConnection( RpcConnection *conn )
RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection)
{
InterlockedIncrement( &conn->ref );
return conn;
LONG ref = InterlockedIncrement(&connection->ref);
TRACE("%p ref=%u\n", connection, ref);
return connection;
}
RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection* Connection)
RPC_STATUS RPCRT4_ReleaseConnection(RpcConnection *connection)
{
if (InterlockedDecrement( &Connection->ref ) > 0) return RPC_S_OK;
LONG ref = InterlockedDecrement(&connection->ref);
TRACE("destroying connection %p\n", Connection);
if (!ref && connection->protseq)
{
/* protseq stores a list of active connections, but does not own references to them.
* It may need to grab a connection from the list, which could lead to a race if
* connection is being released, but not yet removed from the list. We handle that
* by synchronizing on CS here. */
EnterCriticalSection(&connection->protseq->cs);
ref = connection->ref;
if (!ref)
list_remove(&connection->protseq_entry);
LeaveCriticalSection(&connection->protseq->cs);
}
RPCRT4_CloseConnection(Connection);
RPCRT4_strfree(Connection->Endpoint);
RPCRT4_strfree(Connection->NetworkAddr);
HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
HeapFree(GetProcessHeap(), 0, Connection->CookieAuth);
if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
TRACE("%p ref=%u\n", connection, ref);
if (!ref)
{
RPCRT4_CloseConnection(connection);
RPCRT4_strfree(connection->Endpoint);
RPCRT4_strfree(connection->NetworkAddr);
HeapFree(GetProcessHeap(), 0, connection->NetworkOptions);
HeapFree(GetProcessHeap(), 0, connection->CookieAuth);
if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo);
if (connection->QOS) RpcQualityOfService_Release(connection->QOS);
/* server-only */
if (Connection->server_binding) RPCRT4_ReleaseBinding(Connection->server_binding);
if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding);
if (Connection->protseq)
{
EnterCriticalSection(&Connection->protseq->cs);
list_remove(&Connection->protseq_entry);
LeaveCriticalSection(&Connection->protseq->cs);
if (connection->wait_release) SetEvent(connection->wait_release);
HeapFree(GetProcessHeap(), 0, connection);
}
if (Connection->wait_release) SetEvent(Connection->wait_release);
HeapFree(GetProcessHeap(), 0, Connection);
return RPC_S_OK;
}