Skip to content

Typo in zend_hash_iterator_pos_ex() checks !HT_ITERATORS_OVERFLOW(ht) instead of !HT_ITERATORS_OVERFLOW(iter->ht) #24667

Closed as not planned

Description

@yasu20200121web-prog

Description

In Zend/zend_hash.c (lines 627–654), zend_hash_iterator_pos_ex(uint32_t idx, zval *array) decrements the iterator count on the old HashTable (iter->ht) when iter->ht != ht and !zend_hash_iterator_find_copy_pos(idx, ht):

ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval *array)
{
	HashTable *ht = Z_ARRVAL_P(array);
	HashTableIterator *iter = EG(ht_iterators) + idx;

	ZEND_ASSERT(idx != (uint32_t)-1);
	if (UNEXPECTED(iter->ht != ht) && !zend_hash_iterator_find_copy_pos(idx, ht)) {
		if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
				&& EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
			HT_DEC_ITERATORS_COUNT(iter->ht);
		}

Compare this with zend_hash_iterator_pos() right above it (Zend/zend_hash.c, lines 614–617):

		if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
				&& EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
			HT_DEC_ITERATORS_COUNT(iter->ht);
		}

On line 635, zend_hash_iterator_pos_ex() mistakenly checks !HT_ITERATORS_OVERFLOW(ht) (the new ht) instead of !HT_ITERATORS_OVERFLOW(iter->ht) (the old iter->ht whose nIteratorsCount is about to be decremented by HT_DEC_ITERATORS_COUNT(iter->ht)).

If iter->ht had overflowed its 8-bit nIteratorsCount counter (0xff) while ht has not, HT_DEC_ITERATORS_COUNT(iter->ht) will erroneously decrement iter->ht's saturated counter. Conversely, if ht had overflowed while iter->ht had not, iter->ht's counter will not be decremented.

Suggested Patch

--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@ -632,7 +632,7 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos_ex(uint32_t idx, zval
 	ZEND_ASSERT(idx != (uint32_t)-1);
 	if (UNEXPECTED(iter->ht != ht) && !zend_hash_iterator_find_copy_pos(idx, ht)) {
 		if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
-				&& EXPECTED(!HT_ITERATORS_OVERFLOW(ht))) {
+				&& EXPECTED(!HT_ITERATORS_OVERFLOW(iter->ht))) {
 			HT_DEC_ITERATORS_COUNT(iter->ht);
 		}

PHP Version

PHP 8.4, PHP 8.5, master

Operating System

All

Activity

  1. changed the title [-]zend_hash_iterator_pos_ex() calls zend_hash_iterator_pos() without _ex in fallback path[/-] [+]Typo in zend_hash_iterator_pos_ex() checks !HT_ITERATORS_OVERFLOW(ht) instead of !HT_ITERATORS_OVERFLOW(iter->ht)[/+] on Oct 25, 2026
  2. ndossche commented on Oct 25, 2026

    @ndossche
    Member

    This overlaps exactly with #23401, so closing as a duplicate
    cc @iliaal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions