Merge branch 'PHP-8.2' into PHP-8.3

* PHP-8.2:
  Partially backport GH-13782 to stable branches
This commit is contained in:
Niels Dossche 2024-05-30 21:02:03 +02:00
commit 7c947b57b7
No known key found for this signature in database
GPG key ID: B8A8AD166DF0E2E5
2 changed files with 50 additions and 23 deletions

5
NEWS
View file

@ -16,6 +16,11 @@ PHP NEWS
- DOM: - DOM:
. Fixed bug GH-14343 (Memory leak in xml and dom). (nielsdos) . Fixed bug GH-14343 (Memory leak in xml and dom). (nielsdos)
- MySQLnd:
. Partially fix bug GH-10599 (Apache crash on Windows when using a
self-referencing anonymous function inside a class with an active
mysqli connection). (nielsdos)
- Opcache: - Opcache:
. Fixed bug GH-14267 (opcache.jit=off does not allow enabling JIT at runtime). . Fixed bug GH-14267 (opcache.jit=off does not allow enabling JIT at runtime).
(ilutov) (ilutov)

View file

@ -112,6 +112,20 @@ MYSQLND_METHOD(mysqlnd_vio, network_write)(MYSQLND_VIO * const vio, const zend_u
} }
/* }}} */ /* }}} */
static void mysqlnd_fixup_regular_list(php_stream *net_stream)
{
/*
Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
be registered as resource (in EG(regular_list). So far, so good. However, it won't be
unregistered until the script ends. So, we need to take care of that.
*/
dtor_func_t origin_dtor = EG(regular_list).pDestructor;
EG(regular_list).pDestructor = NULL;
zend_hash_index_del(&EG(regular_list), net_stream->res->handle);
EG(regular_list).pDestructor = origin_dtor;
efree(net_stream->res);
net_stream->res = NULL;
}
/* {{{ mysqlnd_vio::open_pipe */ /* {{{ mysqlnd_vio::open_pipe */
static php_stream * static php_stream *
@ -119,7 +133,6 @@ MYSQLND_METHOD(mysqlnd_vio, open_pipe)(MYSQLND_VIO * const vio, const MYSQLND_CS
MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info) MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
{ {
unsigned int streams_options = 0; unsigned int streams_options = 0;
dtor_func_t origin_dtor;
php_stream * net_stream = NULL; php_stream * net_stream = NULL;
DBG_ENTER("mysqlnd_vio::open_pipe"); DBG_ENTER("mysqlnd_vio::open_pipe");
@ -132,16 +145,34 @@ 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);
} }
/*
Streams are not meant for C extensions! Thus we need a hack. Every connected stream will if (persistent) {
be registered as resource (in EG(regular_list). So far, so good. However, it won't be /* This is a similar hack as for mysqlnd_vio::open_tcp_or_unix.
unregistered until the script ends. So, we need to take care of that. * 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
origin_dtor = EG(regular_list).pDestructor; * which one corresponds to our newly allocated stream.
EG(regular_list).pDestructor = NULL; * This loop is pretty cheap because it will normally either be the last entry or second to last entry
zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/ * in the list, depending on whether the socket connection itself is persistent or not.
EG(regular_list).pDestructor = origin_dtor; * That's why we use a reverse loop. */
net_stream->res = NULL; 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);
DBG_RETURN(net_stream); DBG_RETURN(net_stream);
} }
@ -205,6 +236,7 @@ MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYS
zend_resource *le; zend_resource *le;
if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) { if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len))) {
ZEND_ASSERT(le->ptr == net_stream);
origin_dtor = EG(persistent_list).pDestructor; origin_dtor = EG(persistent_list).pDestructor;
/* /*
in_free will let streams code skip destructing - big HACK, in_free will let streams code skip destructing - big HACK,
@ -218,22 +250,12 @@ MYSQLND_METHOD(mysqlnd_vio, open_tcp_or_unix)(MYSQLND_VIO * const vio, const MYS
} }
#if ZEND_DEBUG #if ZEND_DEBUG
/* Shut-up the streams, they don't know what they are doing */ /* Shut-up the streams, they don't know what they are doing */
net_stream->__exposed = 1; php_stream_auto_cleanup(net_stream);
#endif #endif
mnd_sprintf_free(hashed_details); mnd_sprintf_free(hashed_details);
} }
/* mysqlnd_fixup_regular_list(net_stream);
Streams are not meant for C extensions! Thus we need a hack. Every connected stream will
be registered as resource (in EG(regular_list). So far, so good. However, it won't be
unregistered until the script ends. So, we need to take care of that.
*/
origin_dtor = EG(regular_list).pDestructor;
EG(regular_list).pDestructor = NULL;
zend_hash_index_del(&EG(regular_list), net_stream->res->handle); /* ToDO: should it be res->handle, do streams register with addref ?*/
efree(net_stream->res);
net_stream->res = NULL;
EG(regular_list).pDestructor = origin_dtor;
DBG_RETURN(net_stream); DBG_RETURN(net_stream);
} }
/* }}} */ /* }}} */