Skip to content

array_unique assertion failure with RC1 array causing an exception on sort #20043

Closed

Description

@YuanchengJiang

Description

The following code:

<?php
$cls = new ArrayIterator();
$unset_var = 10;
try {array_unique($GLOBALS,$unset_var);} catch (Exception $e) { echo($e); }

Resulted in this output:

php: /home/phpfuzz/WorkSpace/flowfusion/php-src/Zend/zend_hash.c:1549: zend_result zend_hash_del(HashTable *, zend_string *): Assertion `(zend_gc_refcount(&(ht)->gc) == 1) || ((ht)->u.flags & (1<<6))' failed.
Aborted (core dumped)

To reproduce:

./php-src/sapi/cli/php  ./test.php

Commit:

3ac43296aad7942f6602840f0d42a43a4f3f5ebf

Configurations:

CC="clang-12" CXX="clang++-12" CFLAGS="-DZEND_VERIFY_TYPE_INFERENCE" CXXFLAGS="-DZEND_VERIFY_TYPE_INFERENCE" ./configure --enable-debug --enable-address-sanitizer --enable-undefined-sanitizer --enable-re2c-cgoto --enable-fpm --enable-litespeed --enable-phpdbg-debug --enable-zts --enable-bcmath --enable-calendar --enable-dba --enable-dl-test --enable-exif --enable-ftp --enable-gd --enable-gd-jis-conv --enable-mbstring --enable-pcntl --enable-shmop --enable-soap --enable-sockets --enable-sysvmsg --enable-zend-test --with-zlib --with-bz2 --with-curl --with-enchant --with-gettext --with-gmp --with-mhash --with-ldap --with-libedit --with-readline --with-snmp --with-sodium --with-xsl --with-zip --with-mysqli --with-pdo-mysql --with-pdo-pgsql --with-pgsql --with-sqlite3 --with-pdo-sqlite --with-webp --with-jpeg --with-freetype --enable-sigchild --with-readline --with-pcre-jit --with-iconv

Operating System:

Ubuntu 20.04 Host, Docker 0599jiangyc/flowfusion:latest

This report is automatically generated by FlowFusion

PHP Version

nightly

Operating System

No response

Activity

  1. ndossche commented on Oct 3, 2025

    @ndossche
    Member

    Interesting. The reason this happens is because the array_unique operation happens in-place because the input array is RC1. At one point during comparison an exception is thrown which will capture the arguments in the backtrace, which will increment the refcount of the RC1 array to 2. Then a modification happens after the throw on the RC2 array causing the assertion failure. Arguably we shouldn't try continue work after an exception happened during the sort:

    diff --git a/ext/standard/array.c b/ext/standard/array.c
    index d708a339c6b..b6d81193ed6 100644
    --- a/ext/standard/array.c
    +++ b/ext/standard/array.c
    @@ -5044,6 +5044,9 @@ PHP_FUNCTION(array_unique)
     	ZVAL_UNDEF(&arTmp[i].b.val);
     	zend_sort((void *) arTmp, i, sizeof(struct bucketindex),
     			(compare_func_t) cmp, (swap_func_t) array_bucketindex_swap);
    +	if (UNEXPECTED(EG(exception))) {
    +		goto out;
    +	}
     	/* go through the sorted array and delete duplicates from the copy */
     	lastkept = arTmp;
     	for (cmpdata = arTmp + 1; Z_TYPE(cmpdata->b.val) != IS_UNDEF; cmpdata++) {
    @@ -5063,6 +5066,7 @@ PHP_FUNCTION(array_unique)
     			}
     		}
     	}
    +out:
     	pefree(arTmp, GC_FLAGS(Z_ARRVAL_P(array)) & IS_ARRAY_PERSISTENT);
     
     	if (in_place) {
    

    This patch fixes it but it's a bit ugly (and an extra check :-().

  2. changed the title [-]assertion failure zend_hash_del[/-] [+]array_unique assertion failure with RC1 array causing an exception on sort[/+] on Oct 4, 2025
  3. added a commit that references this issue on Oct 4, 2025
    c9ba722
  4. added 2 commits that reference this issue on Oct 5, 2025
    4fed57e
    f2f84e3
  5. added 2 commits that reference this issue on Oct 5, 2025
    1f809a5
    6cde784
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