From 9a9d98e02fe19c0f0df5aca9da50da5f74446515 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Wed, 4 Jun 2025 12:09:37 +0200 Subject: [PATCH 1/3] Do not delete main chunk in zend_gc Closes GH-18756. Co-authored-by: Arnaud Le Blanc --- NEWS | 1 + Zend/tests/gh18756.phpt | 13 +++++++++++++ Zend/zend_alloc.c | 2 +- ext/zend_test/test.c | 10 ++++++++++ ext/zend_test/test.stub.php | 2 ++ ext/zend_test/test_arginfo.h | 6 +++++- 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 Zend/tests/gh18756.phpt diff --git a/NEWS b/NEWS index 5eb1694b5e8..4db7d93ff98 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ PHP NEWS - Core: . Fixed GH-18695 (zend_ast_export() - float number is not preserved). (Oleg Efimov) + . Do not delete main chunk in zend_gc. (danog, Arnaud) - Curl: . Fix memory leak when setting a list via curl_setopt fails. (nielsdos) diff --git a/Zend/tests/gh18756.phpt b/Zend/tests/gh18756.phpt new file mode 100644 index 00000000000..6e112d90604 --- /dev/null +++ b/Zend/tests/gh18756.phpt @@ -0,0 +1,13 @@ +--TEST-- +Bug GH-18756: Zend MM may delete the main chunk +--EXTENSIONS-- +zend_test +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 573fd5fa26b..2f80bdae3cf 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2047,7 +2047,7 @@ ZEND_API size_t zend_mm_gc(zend_mm_heap *heap) i++; } } - if (chunk->free_pages == ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE) { + if (chunk->free_pages == ZEND_MM_PAGES - ZEND_MM_FIRST_PAGE && chunk != heap->main_chunk) { zend_mm_chunk *next_chunk = chunk->next; zend_mm_delete_chunk(heap, chunk); diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index a7dd604d89e..04ece8bd253 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1516,3 +1516,13 @@ static PHP_FUNCTION(zend_test_create_throwing_resource) zend_resource *res = zend_register_resource(NULL, le_throwing_resource); ZVAL_RES(return_value, res); } + +static PHP_FUNCTION(zend_test_gh18756) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_mm_heap *heap = zend_mm_startup(); + zend_mm_gc(heap); + zend_mm_gc(heap); + zend_mm_shutdown(heap, true, false); +} diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index c9477eef527..f9cb93b5a1c 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -262,6 +262,8 @@ function zend_test_override_libxml_global_state(): void {} function zend_test_is_zend_ptr(int $addr): bool {} function zend_test_log_err_debug(string $str): void {} + + function zend_test_gh18756(): void {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 5947a6587bb..c7e3df5c58d 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 9ddaf4d659226c55d49221c71702fa373d42695e */ + * Stub hash: 2f161861ab09b6b5b594dc2db7c2c9df49d76aa7 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -162,6 +162,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_log_err_debug, 0, 1, I ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) ZEND_END_ARG_INFO() +#define arginfo_zend_test_gh18756 arginfo_zend_test_void_return + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return @@ -292,6 +294,7 @@ static ZEND_FUNCTION(zend_test_set_fmode); static ZEND_FUNCTION(zend_test_cast_fread); static ZEND_FUNCTION(zend_test_is_zend_ptr); static ZEND_FUNCTION(zend_test_log_err_debug); +static ZEND_FUNCTION(zend_test_gh18756); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -372,6 +375,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_cast_fread, arginfo_zend_test_cast_fread) ZEND_FE(zend_test_is_zend_ptr, arginfo_zend_test_is_zend_ptr) ZEND_FE(zend_test_log_err_debug, arginfo_zend_test_log_err_debug) + ZEND_FE(zend_test_gh18756, arginfo_zend_test_gh18756) ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func) From ef92e06de19b51f5655b80ab41e5abd849ca6ffa Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 7 Jun 2025 00:33:34 +0200 Subject: [PATCH 2/3] Fix memory leak on php_odbc_fetch_hash() failure The array is initialized but not freed. Closes GH-18787. --- NEWS | 3 +++ ext/odbc/php_odbc.c | 1 + 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 4db7d93ff98..2956cb8c6af 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,9 @@ PHP NEWS . Fix memory leak in intl_datetime_decompose() on failure. (nielsdos) . Fix memory leak in locale lookup on failure. (nielsdos) +- ODBC: + . Fix memory leak on php_odbc_fetch_hash() failure. (nielsdos) + - OpenSSL: . Fix memory leak of X509_STORE in php_openssl_setup_verify() on failure. (nielsdos) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 579b5e989bd..77ba85fe12a 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -1370,6 +1370,7 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) if (rc == SQL_ERROR) { odbc_sql_error(result->conn_ptr, result->stmt, "SQLGetData"); efree(buf); + zval_ptr_dtor(return_value); RETURN_FALSE; } From 786090b35d2c339912c76588dacf32698f2e2d31 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sat, 7 Jun 2025 00:36:08 +0200 Subject: [PATCH 3/3] pdo_odbc: Fix memory leak if WideCharToMultiByte() fails Closes GH-18788. --- NEWS | 3 +++ ext/pdo_odbc/odbc_stmt.c | 1 + 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 2956cb8c6af..2208cd6e59a 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,9 @@ PHP NEWS . Add missing filter cleanups on phar failure. (nielsdos) . Fixed bug GH-18642 (Signed integer overflow in ext/phar fseek). (nielsdos) +- PDO ODBC: + . Fix memory leak if WideCharToMultiByte() fails. (nielsdos) + - PGSQL: . Fix warning not being emitted when failure to cancel a query with pg_cancel_query(). (Girgias) diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index 4bf7162ea06..9f7ab24f8fa 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -104,6 +104,7 @@ static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, zval *result) zend_string *str = zend_string_alloc(ret, 0); ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) Z_STRVAL_P(result), Z_STRLEN_P(result)/sizeof(WCHAR), ZSTR_VAL(str), ZSTR_LEN(str), NULL, NULL); if (ret == 0) { + zend_string_efree(str); return PDO_ODBC_CONV_FAIL; }