Skip to content

Commit 02f71b6

Browse files
committed
ext/intl: Fix double construction leaks (php#22386)
Calling Collator::__construct() or Spoofchecker::__construct() on an already constructed object replaces the stored ICU handle, which leaves the previous handle unreachable and prevents it from being released during object destruction. Reject repeated construction with an Error for both classes so the existing ICU handle remains owned by the object. Add PHPT coverage for the double construction path. Closes php#22386
1 parent 34a9a43 commit 02f71b6

5 files changed

Lines changed: 46 additions & 2 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ PHP NEWS
5454
and later. (Graham Campbell)
5555
. Fixed Locale::lookup() and locale_lookup() to return NULL instead of the
5656
fallback locale when a language tag cannot be canonicalized. (Weilin Du)
57+
. Fixed memory leaks when calling Collator::__construct() or
58+
Spoofchecker::__construct() twice. (Weilin Du)
5759

5860
- mysqli:
5961
. Fix stmt->query leak in mysqli_execute_query() validation errors.

ext/intl/collator/collator_create.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ static int collator_ctor(INTERNAL_FUNCTION_PARAMETERS, zend_error_handling *erro
4242

4343
INTL_CHECK_LOCALE_LEN_OR_FAILURE(locale_len);
4444
COLLATOR_METHOD_FETCH_OBJECT;
45+
if (co->ucoll) {
46+
zend_throw_error(NULL, "Collator object is already constructed");
47+
return FAILURE;
48+
}
4549

4650
if(locale_len == 0) {
4751
locale = (char *)intl_locale_get_default();

ext/intl/spoofchecker/spoofchecker_create.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ PHP_METHOD(Spoofchecker, __construct)
3131

3232
ZEND_PARSE_PARAMETERS_NONE();
3333

34-
zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling);
35-
3634
SPOOFCHECKER_METHOD_FETCH_OBJECT_NO_CHECK;
35+
if (co->uspoof) {
36+
zend_throw_error(NULL, "Spoofchecker object is already constructed");
37+
RETURN_THROWS();
38+
}
39+
40+
zend_replace_error_handling(EH_THROW, IntlException_ce_ptr, &error_handling);
3741

3842
co->uspoof = uspoof_open(SPOOFCHECKER_ERROR_CODE_P(co));
3943
INTL_METHOD_CHECK_STATUS(co, "spoofchecker: unable to open ICU Spoof Checker");
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Collator double construction should not be allowed
3+
--EXTENSIONS--
4+
intl
5+
--FILE--
6+
<?php
7+
$collator = new Collator('en_US');
8+
9+
try {
10+
$collator->__construct('en_US');
11+
} catch (Error $e) {
12+
echo $e->getMessage(), "\n";
13+
}
14+
?>
15+
--EXPECT--
16+
Collator object is already constructed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Spoofchecker double construction should not be allowed
3+
--EXTENSIONS--
4+
intl
5+
--SKIPIF--
6+
<?php if (!class_exists("Spoofchecker")) print "skip"; ?>
7+
--FILE--
8+
<?php
9+
$checker = new Spoofchecker();
10+
11+
try {
12+
$checker->__construct();
13+
} catch (Error $e) {
14+
echo $e->getMessage(), "\n";
15+
}
16+
?>
17+
--EXPECT--
18+
Spoofchecker object is already constructed

0 commit comments

Comments
 (0)