@@ -3722,23 +3722,29 @@ static void php_phongo_pclient_destroy_ptr(zval* ptr)
37223722PHP_RINIT_FUNCTION (mongodb )
37233723{
37243724 /* Initialize HashTable for non-persistent clients, which is initialized to
3725- * NULL in GINIT and destroyed and reset to NULL in RSHUTDOWN. */
3725+ * NULL in GINIT and destroyed and reset to NULL in RSHUTDOWN. Although we
3726+ * specify an element destructor here, all request clients should be freed
3727+ * naturally via garbage collection (i.e. the HashTable should be empty at
3728+ * the time it is destroyed in RSHUTDOWN). */
37263729 if (MONGODB_G (request_clients ) == NULL ) {
37273730 ALLOC_HASHTABLE (MONGODB_G (request_clients ));
37283731 zend_hash_init (MONGODB_G (request_clients ), 0 , NULL , php_phongo_pclient_destroy_ptr , 0 );
37293732 }
37303733
37313734 /* Initialize HashTable for APM subscribers, which is initialized to NULL in
3732- * GINIT and destroyed and reset to NULL in RSHUTDOWN. */
3735+ * GINIT and destroyed and reset to NULL in RSHUTDOWN. Since this HashTable
3736+ * will store subscriber object zvals, we specify ZVAL_PTR_DTOR as its
3737+ * element destructor so that any still-registered subscribers can be freed
3738+ * in RSHUTDOWN. */
37333739 if (MONGODB_G (subscribers ) == NULL ) {
37343740 ALLOC_HASHTABLE (MONGODB_G (subscribers ));
37353741 zend_hash_init (MONGODB_G (subscribers ), 0 , NULL , ZVAL_PTR_DTOR , 0 );
37363742 }
37373743
37383744 /* Initialize HashTable for registering Manager objects. This is initialized
37393745 * to NULL in GINIT and destroyed and reset to NULL in RSHUTDOWN. Since this
3740- * HashTable stores pointers to existing php_phongo_manager_t objects, the
3741- * element destructor is intentionally NULL. */
3746+ * HashTable stores pointers to existing php_phongo_manager_t objects (not
3747+ * counted references), the element destructor is intentionally NULL. */
37423748 if (MONGODB_G (managers ) == NULL ) {
37433749 ALLOC_HASHTABLE (MONGODB_G (managers ));
37443750 zend_hash_init (MONGODB_G (managers ), 0 , NULL , NULL , 0 );
@@ -3761,8 +3767,12 @@ PHP_GINIT_FUNCTION(mongodb)
37613767 /* Clear extension globals */
37623768 memset (mongodb_globals , 0 , sizeof (zend_mongodb_globals ));
37633769
3764- /* Initialize HashTable for persistent clients */
3765- zend_hash_init (& mongodb_globals -> persistent_clients , 0 , NULL , NULL , 1 );
3770+ /* Initialize HashTable for persistent clients, which will be destroyed in
3771+ * GSHUTDOWN. We specify an element destructor so that persistent clients
3772+ * can be destroyed along with the HashTable. The HashTable's struct is
3773+ * nested within globals, so no allocation is needed (unlike the HashTables
3774+ * allocated in RINIT). */
3775+ zend_hash_init (& mongodb_globals -> persistent_clients , 0 , NULL , php_phongo_pclient_destroy_ptr , 1 );
37663776}
37673777/* }}} */
37683778
@@ -3934,9 +3944,11 @@ PHP_RSHUTDOWN_FUNCTION(mongodb)
39343944
39353945 /* Destroy HashTable for non-persistent clients, which was initialized in
39363946 * RINIT. This is intentionally done after the APM subscribers to allow any
3937- * non-persistent clients still referenced by a subscriber (not removed
3938- * prior to RSHUTDOWN) to be naturally freed by the Manager's free_object
3939- * handler rather than the HashTable's element destructor. */
3947+ * non-persistent clients still referenced by a subscriber (not freed prior
3948+ * to RSHUTDOWN) to be naturally garbage collected and freed by the Manager
3949+ * free_object handler rather than the HashTable's element destructor. There
3950+ * is no need to use zend_hash_graceful_reverse_destroy here like we do for
3951+ * persistent clients; moreover, the HashTable should already be empty. */
39403952 if (MONGODB_G (request_clients )) {
39413953 zend_hash_destroy (MONGODB_G (request_clients ));
39423954 FREE_HASHTABLE (MONGODB_G (request_clients ));
@@ -3957,20 +3969,10 @@ PHP_RSHUTDOWN_FUNCTION(mongodb)
39573969/* {{{ PHP_GSHUTDOWN_FUNCTION */
39583970PHP_GSHUTDOWN_FUNCTION (mongodb )
39593971{
3960- php_phongo_pclient_t * pclient ;
3961-
3962- /* Destroy mongoc_client_t objects in reverse order. This is necessary to
3963- * prevent segmentation faults as clients may reference other clients in
3972+ /* Destroy persistent client HashTable in reverse order. This is necessary
3973+ * to prevent segmentation faults as clients may reference other clients in
39643974 * encryption settings. */
3965- ZEND_HASH_REVERSE_FOREACH_PTR (& mongodb_globals -> persistent_clients , pclient )
3966- {
3967- php_phongo_pclient_destroy (pclient );
3968- }
3969- ZEND_HASH_FOREACH_END ();
3970-
3971- /* Destroy HashTable for persistent clients. mongoc_client_t objects have
3972- * already been destroyed. */
3973- zend_hash_destroy (& mongodb_globals -> persistent_clients );
3975+ zend_hash_graceful_reverse_destroy (& mongodb_globals -> persistent_clients );
39743976
39753977 mongodb_globals -> debug = NULL ;
39763978 if (mongodb_globals -> debug_fd ) {
0 commit comments