From e24746188198e47260e803fcac31566ee0d80005 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:24:20 +0100 Subject: [PATCH] Fix GH-17201: Dom\TokenList issues with interned string replace If a bucket previously had a non-interned string, and is now replaced with an interned string, then the type flags still incorrectly state it's a non-interned string. This leads to the refcount being edited for interned strings, which in turn can lead to a crash when protect_memory is set. Closes GH-17207. --- NEWS | 2 ++ ext/dom/tests/gh17201.phpt | 20 ++++++++++++++++++++ ext/dom/token_list.c | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 ext/dom/tests/gh17201.phpt diff --git a/NEWS b/NEWS index acd439d9bbf5e..70dc8504ea66d 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,8 @@ PHP NEWS - DOM: . Fixed bug GH-17145 (DOM memory leak). (nielsdos) + . Fixed bug GH-17201 (Dom\TokenList issues with interned string replace). + (nielsdos) - FFI: . Fixed bug #79075 (FFI header parser chokes on comments). (nielsdos) diff --git a/ext/dom/tests/gh17201.phpt b/ext/dom/tests/gh17201.phpt new file mode 100644 index 0000000000000..a7d8ecd827db5 --- /dev/null +++ b/ext/dom/tests/gh17201.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-17201 (Dom\TokenList issues with interned string replace) +--EXTENSIONS-- +dom +--INI-- +opcache.protect_memory=1 +--FILE-- +'); +$element = $dom->documentElement; +$list = $element->classList; +$list->replace('AA', 'AB'); // Use interned string +foreach ($list as $entry) { + var_dump($entry); +} +?> +--EXPECT-- +string(2) "AB" +string(1) "B" +string(1) "C" diff --git a/ext/dom/token_list.c b/ext/dom/token_list.c index 15eaeb402017d..fe768e17b2e9c 100644 --- a/ext/dom/token_list.c +++ b/ext/dom/token_list.c @@ -583,7 +583,8 @@ PHP_METHOD(Dom_TokenList, replace) /* It already exists, remove token instead. */ zend_hash_del_bucket(token_set, bucket); } else { - Z_STR(bucket->val) = new_token; + /* Need to use ZVAL_STR instead of Z_STR to reset the type flags. */ + ZVAL_STR(&bucket->val, new_token); } /* 5. Run the update steps. */