diff --git a/.cirrus.yml b/.cirrus.yml index d29ed7e103a26..b3cc9d61f1d68 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -4,7 +4,7 @@ env: freebsd_task: name: FREEBSD_DEBUG_NTS freebsd_instance: - image_family: freebsd-13-0 + image_family: freebsd-13-2 env: ARCH: amd64 install_script: diff --git a/.github/actions/apt-x64/action.yml b/.github/actions/apt-x64/action.yml index 621b18532e05f..4e1a03dd58cc5 100644 --- a/.github/actions/apt-x64/action.yml +++ b/.github/actions/apt-x64/action.yml @@ -59,15 +59,3 @@ runs: libjpeg-dev \ libpng-dev \ libfreetype6-dev - - mkdir /opt/oracle - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip - unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip - wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip - unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip - mv instantclient_*_* /opt/oracle/instantclient - # interferes with libldap2 headers - rm /opt/oracle/instantclient/sdk/include/ldap.h - # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup - echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora - sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' diff --git a/.github/actions/install-linux-x32/action.yml b/.github/actions/install-linux-x32/action.yml index bf5f09cd779d4..4ef87ee03fd3f 100644 --- a/.github/actions/install-linux-x32/action.yml +++ b/.github/actions/install-linux-x32/action.yml @@ -6,7 +6,7 @@ runs: run: | set -x make install - mkdir /etc/php.d + mkdir -p /etc/php.d chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini diff --git a/.github/actions/install-linux/action.yml b/.github/actions/install-linux/action.yml index 7ac2ae4c4fcb1..576357b94f1c5 100644 --- a/.github/actions/install-linux/action.yml +++ b/.github/actions/install-linux/action.yml @@ -6,9 +6,7 @@ runs: run: | set -x sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini - echo extension=oci8.so > /etc/php.d/oci8.ini - echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini diff --git a/.github/actions/setup-oracle/action.yml b/.github/actions/setup-oracle/action.yml index 11c16fe93d525..1208e93a24893 100644 --- a/.github/actions/setup-oracle/action.yml +++ b/.github/actions/setup-oracle/action.yml @@ -11,3 +11,20 @@ runs: --name oracle \ -h oracle \ -d gvenzl/oracle-xe:slim + + mkdir /opt/oracle + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip + unzip instantclient-basiclite-linuxx64.zip && rm instantclient-basiclite-linuxx64.zip + wget -nv https://download.oracle.com/otn_software/linux/instantclient/instantclient-sdk-linuxx64.zip + unzip instantclient-sdk-linuxx64.zip && rm instantclient-sdk-linuxx64.zip + mv instantclient_*_* /opt/oracle/instantclient + # interferes with libldap2 headers + rm /opt/oracle/instantclient/sdk/include/ldap.h + # fix debug build warning: zend_signal: handler was replaced for signal (2) after startup + echo DISABLE_INTERRUPT=on > /opt/oracle/instantclient/network/admin/sqlnet.ora + sudo sh -c 'echo /opt/oracle/instantclient >/etc/ld.so.conf.d/oracle-instantclient.conf && ldconfig' + + sudo mkdir -p /etc/php.d + sudo chmod 777 /etc/php.d + echo extension=oci8.so > /etc/php.d/oci8.ini + echo extension=pdo_oci.so > /etc/php.d/pdo_oci.ini diff --git a/.github/nightly_matrix.php b/.github/nightly_matrix.php index fdd5860f53923..868ecb41375c5 100644 --- a/.github/nightly_matrix.php +++ b/.github/nightly_matrix.php @@ -78,6 +78,25 @@ function get_matrix_include(array $branches) { return $jobs; } +function get_windows_matrix_include(array $branches) { + $jobs = []; + foreach ($branches as $branch) { + $jobs[] = [ + 'branch' => $branch, + 'x64' => true, + 'zts' => true, + 'opcache' => true, + ]; + $jobs[] = [ + 'branch' => $branch, + 'x64' => false, + 'zts' => false, + 'opcache' => false, + ]; + } + return $jobs; +} + $trigger = $argv[1] ?? 'schedule'; $attempt = (int) ($argv[2] ?? 1); $discard_cache = ($trigger === 'schedule' && $attempt !== 1) || $trigger === 'workflow_dispatch'; @@ -87,6 +106,8 @@ function get_matrix_include(array $branches) { $branches = get_branches(); $matrix_include = get_matrix_include($branches); +$windows_matrix_include = get_windows_matrix_include($branches); echo '::set-output name=branches::' . json_encode($branches, JSON_UNESCAPED_SLASHES) . "\n"; echo '::set-output name=matrix-include::' . json_encode($matrix_include, JSON_UNESCAPED_SLASHES) . "\n"; +echo '::set-output name=windows-matrix-include::' . json_encode($windows_matrix_include, JSON_UNESCAPED_SLASHES) . "\n"; diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e098c904e3d23..1ff8b6847a4a0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -11,6 +11,7 @@ jobs: outputs: branches: ${{ steps.set-matrix.outputs.branches }} matrix-include: ${{ steps.set-matrix.outputs.matrix-include }} + windows-matrix-include: ${{ steps.set-matrix.outputs.windows-matrix-include }} steps: - uses: actions/checkout@v3 with: @@ -554,7 +555,7 @@ jobs: - name: make install run: | sudo make install - sudo mkdir /etc/php.d + sudo mkdir -p /etc/php.d sudo chmod 777 /etc/php.d echo mysqli.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/mysqli.ini echo pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock > /etc/php.d/pdo_mysql.ini @@ -646,17 +647,13 @@ jobs: with: token: ${{ secrets.ACTION_MONITORING_SLACK }} WINDOWS: + needs: GENERATE_MATRIX + if: ${{ needs.GENERATE_MATRIX.outputs.branches != '[]' }} strategy: fail-fast: false matrix: - include: - - x64: true - zts: true - opcache: true - - x64: false - zts: false - opcache: false - name: "WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" + include: ${{ fromJson(needs.GENERATE_MATRIX.outputs.windows-matrix-include) }} + name: "${{ matrix.branch.name }}_WINDOWS_${{ matrix.x64 && 'X64' || 'X86' }}_${{ matrix.zts && 'ZTS' || 'NTS' }}" runs-on: windows-2019 env: PHP_BUILD_CACHE_BASE_DIR: C:\build-cache @@ -674,6 +671,8 @@ jobs: run: git config --global core.autocrlf false && git config --global core.eol lf - name: git checkout uses: actions/checkout@v3 + with: + ref: ${{ matrix.branch.ref }} - name: Setup uses: ./.github/actions/setup-windows - name: Build diff --git a/NEWS b/NEWS index b8bfcace9f65f..a4d3499a58315 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,22 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.1.23 +?? ??? ????, PHP 8.1.24 + +- Core: + . Fixed bug GH-11937 (Constant ASTs containing objects). (ilutov) + +- DOM: + . Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos) + +- Iconv: + . Fixed build for NetBSD which still uses the old iconv signature. + (David Carlier) + +- MySQLnd: + . Fixed bug GH-10270 (Invalid error message when connection via SSL fails: + "trying to connect via (null)"). (Kamil Tekiela) + +31 Aug 2023, PHP 8.1.23 - CLI: . Fixed bug GH-11716 (cli server crashes on SIGINT when compiled with @@ -55,6 +71,10 @@ PHP NEWS . Revert behaviour of receiving SIGCHLD signals back to the behaviour before 8.1.22. (nielsdos) +- SPL: + . Fixed bug #81992 (SplFixedArray::setSize() causes use-after-free). + (nielsdos) + - Standard: . Prevent int overflow on $decimals in number_format. (Marc Bennewitz) . Fixed bug GH-11870 (Fix off-by-one bug when truncating tempnam prefix) diff --git a/Zend/zend.h b/Zend/zend.h index 237adfe01ddad..5b27b725db262 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.1.23-dev" +#define ZEND_VERSION "4.1.24-dev" #define ZEND_ENGINE_3 diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index af9be18d10f5b..75127b8b8d18a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1458,6 +1458,35 @@ ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, con } /* }}} */ +static bool array_is_const_ex(zend_array *array, uint32_t *max_checks) +{ + if (zend_hash_num_elements(array) > *max_checks) { + return false; + } + *max_checks -= zend_hash_num_elements(array); + + zval *element; + ZEND_HASH_FOREACH_VAL(array, element) { + if (Z_TYPE_P(element) < IS_ARRAY) { + continue; + } else if (Z_TYPE_P(element) == IS_ARRAY) { + if (!array_is_const_ex(array, max_checks)) { + return false; + } + } else { + return false; + } + } ZEND_HASH_FOREACH_END(); + + return true; +} + +static bool array_is_const(zend_array *array) +{ + uint32_t max_checks = 50; + return array_is_const_ex(array, &max_checks); +} + static bool can_ct_eval_const(zend_constant *c) { if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) { return 0; @@ -1468,9 +1497,13 @@ static bool can_ct_eval_const(zend_constant *c) { && (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) { return 1; } - if (Z_TYPE(c->value) < IS_OBJECT + if (Z_TYPE(c->value) < IS_ARRAY && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) { return 1; + } else if (Z_TYPE(c->value) == IS_ARRAY + && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) + && array_is_const(Z_ARR(c->value))) { + return 1; } return 0; } @@ -1690,7 +1723,10 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend c = &cc->value; /* Substitute case-sensitive (or lowercase) persistent class constants */ - if (Z_TYPE_P(c) < IS_OBJECT) { + if (Z_TYPE_P(c) < IS_ARRAY) { + ZVAL_COPY_OR_DUP(zv, c); + return 1; + } else if (Z_TYPE_P(c) == IS_ARRAY && array_is_const(Z_ARR_P(c))) { ZVAL_COPY_OR_DUP(zv, c); return 1; } diff --git a/configure.ac b/configure.ac index 6d6d44e0597c4..0c723046adfdc 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.1.23-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.1.24-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/ext/dom/document.c b/ext/dom/document.c index ea6daafeb30fb..64da4f051be2c 100644 --- a/ext/dom/document.c +++ b/ext/dom/document.c @@ -139,7 +139,6 @@ int dom_document_encoding_read(dom_object *obj, zval *retval) zend_result dom_document_encoding_write(dom_object *obj, zval *newval) { xmlDoc *docp = (xmlDocPtr) dom_object_get_node(obj); - zend_string *str; xmlCharEncodingHandlerPtr handler; if (docp == NULL) { @@ -147,11 +146,15 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) return FAILURE; } - str = zval_try_get_string(newval); - if (UNEXPECTED(!str)) { - return FAILURE; + /* Typed property, can only be IS_STRING or IS_NULL. */ + ZEND_ASSERT(Z_TYPE_P(newval) == IS_STRING || Z_TYPE_P(newval) == IS_NULL); + + if (Z_TYPE_P(newval) == IS_NULL) { + goto invalid_encoding; } + zend_string *str = Z_STR_P(newval); + handler = xmlFindCharEncodingHandler(ZSTR_VAL(str)); if (handler != NULL) { @@ -161,12 +164,14 @@ zend_result dom_document_encoding_write(dom_object *obj, zval *newval) } docp->encoding = xmlStrdup((const xmlChar *) ZSTR_VAL(str)); } else { - zend_value_error("Invalid document encoding"); - return FAILURE; + goto invalid_encoding; } - zend_string_release_ex(str, 0); return SUCCESS; + +invalid_encoding: + zend_value_error("Invalid document encoding"); + return FAILURE; } /* }}} */ diff --git a/ext/dom/tests/gh12002.phpt b/ext/dom/tests/gh12002.phpt new file mode 100644 index 0000000000000..7d1ae944646ae --- /dev/null +++ b/ext/dom/tests/gh12002.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-12002 (DOMDocument::encoding memory leak with invalid encoding) +--EXTENSIONS-- +dom +--FILE-- +encoding = make_nonconst('utf-8'); +var_dump($dom->encoding); +try { + $dom->encoding = make_nonconst('foobar'); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); +$dom->encoding = make_nonconst('utf-16le'); +var_dump($dom->encoding); +try { + $dom->encoding = NULL; +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($dom->encoding); + +?> +--EXPECT-- +string(5) "utf-8" +Invalid document encoding +string(5) "utf-8" +string(8) "utf-16le" +Invalid document encoding +string(8) "utf-16le" diff --git a/ext/iconv/iconv.c b/ext/iconv/iconv.c index f05e58aa1d953..83d89a0df4835 100644 --- a/ext/iconv/iconv.c +++ b/ext/iconv/iconv.c @@ -44,6 +44,14 @@ #undef iconv #endif +#if defined(__NetBSD__) +// unfortunately, netbsd has still the old non posix conformant signature +// libiconv tends to match the eventual system's iconv too. +#define ICONV_CONST const +#else +#define ICONV_CONST +#endif + #include "zend_smart_str.h" #include "ext/standard/base64.h" #include "ext/standard/quot_print.h" @@ -360,7 +368,7 @@ static php_iconv_err_t _php_iconv_appendl(smart_str *d, const char *s, size_t l, out_p = ZSTR_VAL((d)->s) + ZSTR_LEN((d)->s); - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: return PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -456,7 +464,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len, out_p = ZSTR_VAL(out_buf); while (in_left > 0) { - result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left); + result = iconv(cd, (ICONV_CONST char **) &in_p, &in_left, (char **) &out_p, &out_left); out_size = bsz - out_left; if (result == (size_t)(-1)) { if (ignore_ilseq && errno == EILSEQ) { @@ -576,7 +584,7 @@ static php_iconv_err_t _php_iconv_strlen(size_t *pretval, const char *str, size_ more = in_left > 0; - iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } else { @@ -683,7 +691,7 @@ static php_iconv_err_t _php_iconv_substr(smart_str *pretval, more = in_left > 0 && len > 0; - iconv(cd1, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv(cd1, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -805,7 +813,7 @@ static php_iconv_err_t _php_iconv_strpos(size_t *pretval, more = in_left > 0; - iconv_ret = iconv(cd, more ? (char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); + iconv_ret = iconv(cd, more ? (ICONV_CONST char **)&in_p : NULL, more ? &in_left : NULL, (char **) &out_p, &out_left); if (out_left == sizeof(buf)) { break; } @@ -1012,7 +1020,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_left = out_size - out_reserved; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -1096,7 +1104,7 @@ static php_iconv_err_t _php_iconv_mime_encode(smart_str *pretval, const char *fn out_p = buf; out_left = out_size; - if (iconv(cd, (char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { + if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) { switch (errno) { case EINVAL: err = PHP_ICONV_ERR_ILLEGAL_CHAR; @@ -2373,7 +2381,7 @@ static int php_iconv_stream_filter_append_bucket( tcnt = self->stub_len; while (tcnt > 0) { - if (iconv(self->cd, &pt, &tcnt, &pd, &ocnt) == (size_t)-1) { + if (iconv(self->cd, (ICONV_CONST char **)&pt, &tcnt, &pd, &ocnt) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); @@ -2439,7 +2447,7 @@ static int php_iconv_stream_filter_append_bucket( while (icnt > 0) { if ((ps == NULL ? iconv(self->cd, NULL, NULL, &pd, &ocnt): - iconv(self->cd, (char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { + iconv(self->cd, (ICONV_CONST char **)&ps, &icnt, &pd, &ocnt)) == (size_t)-1) { switch (errno) { case EILSEQ: php_error_docref(NULL, E_WARNING, "iconv stream filter (\"%s\"=>\"%s\"): invalid multibyte sequence", self->from_charset, self->to_charset); diff --git a/ext/mysqli/tests/gh8978.phpt b/ext/mysqli/tests/gh8978.phpt new file mode 100644 index 0000000000000..92de63b381ca8 --- /dev/null +++ b/ext/mysqli/tests/gh8978.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug GH-8267 (Invalid error message when connection via SSL fails) +--EXTENSIONS-- +mysqli +--SKIPIF-- + +--FILE-- +getMessage()."\n"; +} + +echo 'done!'; +?> +--EXPECTF-- +Warning: failed loading cafile stream: `x509.ca' in %s +Cannot connect to MySQL using SSL +done! diff --git a/ext/mysqlnd/mysqlnd_commands.c b/ext/mysqlnd/mysqlnd_commands.c index 40821bb1efedd..ae64560850531 100644 --- a/ext/mysqlnd/mysqlnd_commands.c +++ b/ext/mysqlnd/mysqlnd_commands.c @@ -571,6 +571,8 @@ MYSQLND_METHOD(mysqlnd_command, enable_ssl)(MYSQLND_CONN_DATA * const conn, cons conn->vio->data->m.set_client_option(conn->vio, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify); if (FAIL == conn->vio->data->m.enable_ssl(conn->vio)) { + SET_CONNECTION_STATE(&conn->state, CONN_QUIT_SENT); + SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, "Cannot connect to MySQL using SSL"); goto end; } } diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 4f720cdb15495..c905e38c8573d 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -289,7 +289,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) mysqlnd_set_persistent_string(&conn->unix_socket, NULL, 0, pers); DBG_INF_FMT("scheme=%s", conn->scheme.s); mysqlnd_set_persistent_string(&conn->scheme, NULL, 0, pers); - + if (conn->server_version) { mnd_pefree(conn->server_version, pers); conn->server_version = NULL; @@ -726,19 +726,20 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, DBG_RETURN(PASS); } err: - if (transport.s) { - mnd_sprintf_free(transport.s); - transport.s = NULL; - } - - DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, conn->scheme.s); + DBG_ERR_FMT("[%u] %.128s (trying to connect via %s)", conn->error_info->error_no, conn->error_info->error, transport.s ? transport.s : conn->scheme.s); if (!conn->error_info->error_no) { + /* There was an unknown error if the connection failed but we have no error number */ char * msg; - mnd_sprintf(&msg, 0, "%s (trying to connect via %s)",conn->error_info->error, conn->scheme.s); + mnd_sprintf(&msg, 0, "Unknown error while trying to connect via %s", transport.s ? transport.s : conn->scheme.s); SET_CLIENT_ERROR(conn->error_info, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, msg); mnd_sprintf_free(msg); } + if (transport.s) { + mnd_sprintf_free(transport.s); + transport.s = NULL; + } + conn->m->free_contents(conn); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_FAILURE); DBG_RETURN(FAIL); diff --git a/ext/mysqlnd/mysqlnd_vio.c b/ext/mysqlnd/mysqlnd_vio.c index 2bd77906a1b9a..cd9c714f23bb9 100644 --- a/ext/mysqlnd/mysqlnd_vio.c +++ b/ext/mysqlnd/mysqlnd_vio.c @@ -569,7 +569,6 @@ MYSQLND_METHOD(mysqlnd_vio, enable_ssl)(MYSQLND_VIO * const net) php_stream_xport_crypto_enable(net_stream, 1) < 0) { DBG_ERR("Cannot connect to MySQL by using SSL"); - php_error_docref(NULL, E_WARNING, "Cannot connect to MySQL by using SSL"); DBG_RETURN(FAIL); } net->data->ssl = TRUE; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index d3d5914866a1e..876338f4ab127 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -639,6 +639,7 @@ static int format_default_value(smart_str *str, zval *value) { } ZEND_HASH_FOREACH_END(); smart_str_appendc(str, ']'); } else if (Z_TYPE_P(value) == IS_OBJECT) { + /* This branch may only be reached for default properties, which don't support arbitrary objects. */ zend_object *obj = Z_OBJ_P(value); zend_class_entry *class = obj->ce; ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM); diff --git a/ext/reflection/tests/gh11937_1.inc b/ext/reflection/tests/gh11937_1.inc new file mode 100644 index 0000000000000..4d55213f2f831 --- /dev/null +++ b/ext/reflection/tests/gh11937_1.inc @@ -0,0 +1,13 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(2) { + [0]=> + enum(TestEnum::One) + [1]=> + enum(TestEnum::Two) +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ new \Foo(TestEnum::CASES) ] + } +} diff --git a/ext/reflection/tests/gh11937_2.inc b/ext/reflection/tests/gh11937_2.inc new file mode 100644 index 0000000000000..d6e21e6ba5c55 --- /dev/null +++ b/ext/reflection/tests/gh11937_2.inc @@ -0,0 +1,4 @@ +getAttributes('Attr')[0]; + +?> +--EXPECT-- +array(1) { + [0]=> + object(Foo)#1 (0) { + } +} +Attribute [ Attr ] { + - Arguments [1] { + Argument #0 [ FOOS ] + } +} diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 2cf5e2360adbf..562806a5c284b 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -46,6 +46,8 @@ typedef struct _spl_fixedarray { zval *elements; /* True if this was modified after the last call to get_properties or the hash table wasn't rebuilt. */ bool should_rebuild_properties; + /* If positive, it's a resize within a resize and the value gives the desired size. If -1, it's not. */ + zend_long cached_resize; } spl_fixedarray; typedef struct _spl_fixedarray_methods { @@ -117,6 +119,7 @@ static void spl_fixedarray_init(spl_fixedarray *array, zend_long size) } else { spl_fixedarray_default_ctor(array); } + array->cached_resize = -1; } /* Copies the range [begin, end) into the fixedarray, beginning at `offset`. @@ -148,6 +151,7 @@ static void spl_fixedarray_copy_ctor(spl_fixedarray *to, spl_fixedarray *from) */ static void spl_fixedarray_dtor_range(spl_fixedarray *array, zend_long from, zend_long to) { + array->size = from; zval *begin = array->elements + from, *end = array->elements + to; while (begin != end) { zval_ptr_dtor(begin++); @@ -184,19 +188,35 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size) return; } + if (UNEXPECTED(array->cached_resize >= 0)) { + /* We're already resizing, so just remember the desired size. + * The resize will happen later. */ + array->cached_resize = size; + return; + } + array->cached_resize = size; + /* clearing the array */ if (size == 0) { spl_fixedarray_dtor(array); array->elements = NULL; + array->size = 0; } else if (size > array->size) { array->elements = safe_erealloc(array->elements, size, sizeof(zval), 0); spl_fixedarray_init_elems(array, array->size, size); + array->size = size; } else { /* size < array->size */ + /* Size set in spl_fixedarray_dtor_range() */ spl_fixedarray_dtor_range(array, size, array->size); array->elements = erealloc(array->elements, sizeof(zval) * size); } - array->size = size; + /* If resized within the destructor, take the last resize command and perform it */ + zend_long cached_resize = array->cached_resize; + array->cached_resize = -1; + if (cached_resize != size) { + spl_fixedarray_resize(array, cached_resize); + } } static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, int *n) diff --git a/ext/spl/tests/bug81992.phpt b/ext/spl/tests/bug81992.phpt new file mode 100644 index 0000000000000..52235218a78f6 --- /dev/null +++ b/ext/spl/tests/bug81992.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #81992 (SplFixedArray::setSize() causes use-after-free) +--FILE-- +getMessage(), "\n"; + } + try { + var_dump($obj[4]); + } catch (Throwable $e) { + echo $e->getMessage(), "\n"; + } + } +} + +$obj = new SplFixedArray(5); +$obj[0] = str_repeat("A", 10); +$obj[2] = str_repeat('B', 10); +$obj[3] = new InvalidDestructor(); +$obj[4] = str_repeat('C', 10); +$obj->setSize(2); +?> +--EXPECT-- +string(10) "AAAAAAAAAA" +Index invalid or out of range +Index invalid or out of range diff --git a/ext/spl/tests/bug81992b.phpt b/ext/spl/tests/bug81992b.phpt new file mode 100644 index 0000000000000..ba4736dfff1f3 --- /dev/null +++ b/ext/spl/tests/bug81992b.phpt @@ -0,0 +1,66 @@ +--TEST-- +Bug #81992 (SplFixedArray::setSize() causes use-after-free) - setSize variation +--FILE-- +obj->setSize($this->desiredSize); + echo "Destroyed, size is now still ", $this->obj->getSize(), "\n"; + } +} + +class DestructorLogger { + public function __construct(private int $id) {} + + public function __destruct() { + echo "Destroyed the logger with id ", $this->id, "\n"; + } +} + +function test(int $desiredSize) { + $obj = new SplFixedArray(5); + $obj[0] = str_repeat("A", 10); + $obj[1] = new DestructorLogger(1); + $obj[2] = str_repeat('B', 10); + $obj[3] = new InvalidDestructor($desiredSize, $obj); + $obj[4] = new DestructorLogger(4); + $obj->setSize(2); + echo "Size is now ", $obj->getSize(), "\n"; + echo "Done\n"; +} + +echo "--- Smaller size test ---\n"; +test(1); +echo "--- Equal size test ---\n"; +test(2); +echo "--- Larger size test ---\n"; +test(10); +?> +--EXPECT-- +--- Smaller size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Destroyed the logger with id 1 +Size is now 1 +Done +--- Equal size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Size is now 2 +Done +Destroyed the logger with id 1 +--- Larger size test --- +In destructor +Destroyed, size is now still 2 +Destroyed the logger with id 4 +Size is now 10 +Done +Destroyed the logger with id 1 diff --git a/main/php_version.h b/main/php_version.h index b1c3d7c65affb..7c1327eb68217 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 1 -#define PHP_RELEASE_VERSION 23 +#define PHP_RELEASE_VERSION 24 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.1.23-dev" -#define PHP_VERSION_ID 80123 +#define PHP_VERSION "8.1.24-dev" +#define PHP_VERSION_ID 80124