From 9115f62342cd87a8b33e28cd3ed2c074e0eeca2f Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Mon, 22 Jun 2026 00:50:45 +0800 Subject: [PATCH] ext/Intl: Fix memory leaks when calling `Collator::__construct()` or `Spoofchecker::__construct()` twice. --- NEWS | 2 ++ ext/intl/collator/collator_create.c | 4 ++++ ext/intl/spoofchecker/spoofchecker_create.c | 8 ++++++-- ext/intl/tests/collator_double_ctor.phpt | 16 ++++++++++++++++ ext/intl/tests/spoofchecker_double_ctor.phpt | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 ext/intl/tests/collator_double_ctor.phpt create mode 100644 ext/intl/tests/spoofchecker_double_ctor.phpt diff --git a/NEWS b/NEWS index 9a1b6d35d1f7..ce9688459814 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,8 @@ PHP NEWS and later. (Graham Campbell) . Fixed Locale::lookup() and locale_lookup() to return NULL instead of the fallback locale when a language tag cannot be canonicalized. (Weilin Du) + . Fixed memory leaks when calling Collator::__construct() or + Spoofchecker::__construct() twice. (Weilin Du) - mysqli: . Fix stmt->query leak in mysqli_execute_query() validation errors. diff --git a/ext/intl/collator/collator_create.c b/ext/intl/collator/collator_create.c index 88dacc1c1db4..ca57d5431e01 100644 --- a/ext/intl/collator/collator_create.c +++ b/ext/intl/collator/collator_create.c @@ -42,6 +42,10 @@ static int collator_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_error_handling *erro INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len); COLLATOR_METHOD_FETCH_OBJECT; + if (co->ucoll) { + zend_throw_error(NULL, "Collator object is already constructed"); + return FAILURE; + } if(locale_len == 0) { locale = (char *)intl_locale_get_default(); diff --git a/ext/intl/spoofchecker/spoofchecker_create.c b/ext/intl/spoofchecker/spoofchecker_create.c index c1cecac8412a..4614d44c3174 100644 --- a/ext/intl/spoofchecker/spoofchecker_create.c +++ b/ext/intl/spoofchecker/spoofchecker_create.c @@ -31,9 +31,13 @@ PHP_METHOD(Spoofchecker, __construct) ZEND_PARSE_PARAMETERS_NONE(); - zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling); - SPOOFCHECKER_METHOD_FETCH_OBJECT_NO_CHECK; + if (co->uspoof) { + zend_throw_error(NULL, "Spoofchecker object is already constructed"); + RETURN_THROWS(); + } + + zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling); co->uspoof = uspoof_open(SPOOFCHECKER_ERROR_CODE_P(co)); INTL_METHOD_CHECK_STATUS(co, "spoofchecker: unable to open ICU Spoof Checker"); diff --git a/ext/intl/tests/collator_double_ctor.phpt b/ext/intl/tests/collator_double_ctor.phpt new file mode 100644 index 000000000000..93b72f7392b3 --- /dev/null +++ b/ext/intl/tests/collator_double_ctor.phpt @@ -0,0 +1,16 @@ +--TEST-- +Collator double construction should not be allowed +--EXTENSIONS-- +intl +--FILE-- +__construct('en_US'); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Collator object is already constructed diff --git a/ext/intl/tests/spoofchecker_double_ctor.phpt b/ext/intl/tests/spoofchecker_double_ctor.phpt new file mode 100644 index 000000000000..01dae5ab4bc5 --- /dev/null +++ b/ext/intl/tests/spoofchecker_double_ctor.phpt @@ -0,0 +1,18 @@ +--TEST-- +Spoofchecker double construction should not be allowed +--EXTENSIONS-- +intl +--SKIPIF-- + +--FILE-- +__construct(); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Spoofchecker object is already constructed