Fix crash in shutdown when using a named pipe with a persistent mysqli connection

The code originally posted in GH-10599 triggers the bug for
non-persistent connections, but changing the host to `p:.` reveals that
there is also a crash bug for persistent connections.
This commit is contained in:
Niels Dossche 2024-03-21 23:59:34 +01:00
parent a20d9d72b1
commit 0b69c3aea4
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5

View file

@ -145,6 +145,33 @@ MYSQLND_METHOD(mysqlnd_vio, open_pipe)(MYSQLND_VIO * const vio, const MYSQLND_CS
SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown error while connecting"); SET_CLIENT_ERROR(error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Unknown error while connecting");
DBG_RETURN(NULL); DBG_RETURN(NULL);
} }
if (persistent) {
/* This is a similar hack as for mysqlnd_vio::open_tcp_or_unix.
* The main difference here is that we have no access to the hashed key.
* We can however perform a loop over the persistent resource list to find
* which one corresponds to our newly allocated stream.
* This loop is pretty cheap because it will normally either be the last entry or second to last entry
* in the list, depending on whether the socket connection itself is persistent or not.
* That's why we use a reverse loop. */
Bucket *bucket;
/* Use a bucket loop to make deletion cheap. */
ZEND_HASH_MAP_REVERSE_FOREACH_BUCKET(&EG(persistent_list), bucket) {
zend_resource *current_res = Z_RES(bucket->val);
if (current_res->ptr == net_stream) {
dtor_func_t origin_dtor = EG(persistent_list).pDestructor;
EG(persistent_list).pDestructor = NULL;
zend_hash_del_bucket(&EG(persistent_list), bucket);
EG(persistent_list).pDestructor = origin_dtor;
pefree(current_res, 1);
break;
}
} ZEND_HASH_FOREACH_END();
#if ZEND_DEBUG
php_stream_auto_cleanup(net_stream);
#endif
}
mysqlnd_fixup_regular_list(net_stream); mysqlnd_fixup_regular_list(net_stream);
DBG_RETURN(net_stream); DBG_RETURN(net_stream);