diff --git a/src/core/api.c b/src/core/api.c index ce9f2ab5fa..8bf71553b0 100644 --- a/src/core/api.c +++ b/src/core/api.c @@ -444,7 +444,7 @@ MsQuicConnectionStart( goto Error; } - QuicConfigurationAddRef(Configuration); + QuicConfigurationAddRef(Configuration, QUIC_CONF_REF_CONN_START_OP); Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_START; Oper->API_CALL.Context->CONN_START.Configuration = Configuration; Oper->API_CALL.Context->CONN_START.ServerName = ServerNameCopy; @@ -543,7 +543,7 @@ MsQuicConnectionSetConfiguration( goto Error; } - QuicConfigurationAddRef(Configuration); + QuicConfigurationAddRef(Configuration, QUIC_CONF_REF_CONN_SET_OP); Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_SET_CONFIGURATION; Oper->API_CALL.Context->CONN_SET_CONFIGURATION.Configuration = Configuration; diff --git a/src/core/configuration.c b/src/core/configuration.c index 96653ecf10..0033f0ff60 100644 --- a/src/core/configuration.c +++ b/src/core/configuration.c @@ -84,6 +84,10 @@ MsQuicConfigurationOpen( Configuration->ClientContext = Context; Configuration->Registration = Registration; CxPlatRefInitialize(&Configuration->RefCount); +#if DEBUG + CxPlatRefInitializeMultiple(Configuration->RefTypeBiasedCount, QUIC_CONF_REF_COUNT); + CxPlatRefIncrement(&Configuration->RefTypeBiasedCount[QUIC_CONF_REF_HANDLE]); +#endif Configuration->AlpnListLength = (uint16_t)AlpnListLength; AlpnList = Configuration->AlpnList; @@ -208,6 +212,9 @@ MsQuicConfigurationOpen( Error: if (QUIC_FAILED(Status) && Configuration != NULL) { +#if DEBUG + CXPLAT_DBG_ASSERT(!CxPlatRefDecrement(&Configuration->RefTypeBiasedCount[QUIC_CONF_REF_HANDLE])); +#endif CxPlatStorageClose(Configuration->AppSpecificStorage); #ifdef QUIC_SILO CxPlatStorageClose(Configuration->Storage); @@ -259,6 +266,12 @@ QuicConfigurationUninitialize( QuicRegistrationRundownRelease(Configuration->Registration, QUIC_REG_REF_CONFIGURATION); +#if DEBUG + for (uint32_t i = 0; i < QUIC_CONF_REF_COUNT; i++) { + CXPLAT_DBG_ASSERT(QuicReadLongPtrNoFence(&Configuration->RefTypeBiasedCount[i]) == 1); + } +#endif + QuicTraceEvent( ConfigurationDestroyed, "[cnfg][%p] Destroyed", @@ -282,7 +295,7 @@ MsQuicConfigurationClose( if (Handle != NULL && Handle->Type == QUIC_HANDLE_TYPE_CONFIGURATION) { #pragma prefast(suppress: __WARNING_25024, "Pointer cast already validated.") - QuicConfigurationRelease((QUIC_CONFIGURATION*)Handle); + QuicConfigurationRelease((QUIC_CONFIGURATION*)Handle, QUIC_CONF_REF_HANDLE); } QuicTraceEvent( @@ -319,7 +332,7 @@ MsQuicConfigurationLoadCredentialComplete( (HQUIC)Configuration, Configuration->ClientContext, Status); - QuicConfigurationRelease(Configuration); + QuicConfigurationRelease(Configuration, QUIC_CONF_REF_LOAD_CRED); } } @@ -351,7 +364,7 @@ MsQuicConfigurationLoadCredential( TlsCredFlags |= CXPLAT_TLS_CREDENTIAL_FLAG_DISABLE_RESUMPTION; } - QuicConfigurationAddRef(Configuration); + QuicConfigurationAddRef(Configuration, QUIC_CONF_REF_LOAD_CRED); Status = CxPlatTlsSecConfigCreate( @@ -365,7 +378,7 @@ MsQuicConfigurationLoadCredential( // // Release ref for synchronous calls or asynchronous failures. // - QuicConfigurationRelease(Configuration); + QuicConfigurationRelease(Configuration, QUIC_CONF_REF_LOAD_CRED); } } diff --git a/src/core/configuration.h b/src/core/configuration.h index c8fec06e39..dd1a2bc31c 100644 --- a/src/core/configuration.h +++ b/src/core/configuration.h @@ -5,6 +5,20 @@ --*/ +// +// The different kinds of references on a Configuration. +// +typedef enum QUIC_CONFIGURATION_REF { + + QUIC_CONF_REF_HANDLE, + QUIC_CONF_REF_CONNECTION, + QUIC_CONF_REF_LOAD_CRED, + QUIC_CONF_REF_CONN_START_OP, + QUIC_CONF_REF_CONN_SET_OP, + + QUIC_CONF_REF_COUNT +} QUIC_CONFIGURATION_REF; + // // Represents a set of TLS and QUIC configurations and settings. // @@ -31,6 +45,15 @@ typedef struct QUIC_CONFIGURATION { // CXPLAT_REF_COUNT RefCount; +#if DEBUG + // + // Detailed ref counts. + // Note: These ref counts are biased by 1, so lowest they go is 1. It is an + // error for them to ever be zero. + // + CXPLAT_REF_COUNT RefTypeBiasedCount[QUIC_CONF_REF_COUNT]; +#endif + // // The TLS security configurations. // @@ -106,10 +129,16 @@ QuicConfigurationUninitialize( QUIC_INLINE void QuicConfigurationAddRef( - _In_ QUIC_CONFIGURATION* Configuration + _In_ QUIC_CONFIGURATION* Configuration, + _In_ QUIC_CONFIGURATION_REF Ref ) { CxPlatRefIncrement(&Configuration->RefCount); +#if DEBUG + CxPlatRefIncrement(&Configuration->RefTypeBiasedCount[Ref]); +#else + UNREFERENCED_PARAMETER(Ref); +#endif } // @@ -118,9 +147,15 @@ QuicConfigurationAddRef( QUIC_INLINE void QuicConfigurationRelease( - _In_ QUIC_CONFIGURATION* Configuration + _In_ QUIC_CONFIGURATION* Configuration, + _In_ QUIC_CONFIGURATION_REF Ref ) { +#if DEBUG + CXPLAT_DBG_ASSERT(!CxPlatRefDecrement(&Configuration->RefTypeBiasedCount[Ref])); +#else + UNREFERENCED_PARAMETER(Ref); +#endif if (CxPlatRefDecrement(&Configuration->RefCount)) { QuicConfigurationUninitialize(Configuration); } diff --git a/src/core/connection.c b/src/core/connection.c index 1bae770724..41b01449ab 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -383,7 +383,7 @@ QuicConnFree( Silo = Connection->Configuration->Silo; QuicSiloAddRef(Silo); #endif - QuicConfigurationRelease(Connection->Configuration); + QuicConfigurationRelease(Connection->Configuration, QUIC_CONF_REF_CONNECTION); Connection->Configuration = NULL; } if (Connection->RemoteServerName != NULL) { @@ -2480,7 +2480,7 @@ QuicConnSetConfiguration( "Configuration set, %p", Configuration); - QuicConfigurationAddRef(Configuration); + QuicConfigurationAddRef(Configuration, QUIC_CONF_REF_CONNECTION); QuicConfigurationAttachSilo(Configuration); Connection->Configuration = Configuration; diff --git a/src/core/operation.c b/src/core/operation.c index 0270f9ea71..c0541a0d36 100644 --- a/src/core/operation.c +++ b/src/core/operation.c @@ -95,12 +95,12 @@ QuicOperationFree( if (Oper->Type == QUIC_OPER_TYPE_API_CALL) { QUIC_API_CONTEXT* ApiCtx = Oper->API_CALL.Context; if (ApiCtx->Type == QUIC_API_TYPE_CONN_START) { - QuicConfigurationRelease(ApiCtx->CONN_START.Configuration); + QuicConfigurationRelease(ApiCtx->CONN_START.Configuration, QUIC_CONF_REF_CONN_START_OP); if (ApiCtx->CONN_START.ServerName != NULL) { CXPLAT_FREE(ApiCtx->CONN_START.ServerName, QUIC_POOL_SERVERNAME); } } else if (ApiCtx->Type == QUIC_API_TYPE_CONN_SET_CONFIGURATION) { - QuicConfigurationRelease(ApiCtx->CONN_SET_CONFIGURATION.Configuration); + QuicConfigurationRelease(ApiCtx->CONN_SET_CONFIGURATION.Configuration, QUIC_CONF_REF_CONN_SET_OP); } else if (ApiCtx->Type == QUIC_API_TYPE_CONN_SEND_RESUMPTION_TICKET) { if (ApiCtx->CONN_SEND_RESUMPTION_TICKET.ResumptionAppData != NULL) { CXPLAT_DBG_ASSERT(ApiCtx->CONN_SEND_RESUMPTION_TICKET.AppDataLength != 0);