From ce83d373f9cba3608414724a88561fb364c45fc6 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 3 Jul 2025 15:19:42 +0100 Subject: [PATCH 1/2] ext/spl: Add tests for disabled sort functions --- ext/spl/tests/ArrayObject/asort_disabled.phpt | 18 ++++++++++++++++++ ext/spl/tests/ArrayObject/ksort_disabled.phpt | 18 ++++++++++++++++++ .../ArrayObject/natcasesort_disabled.phpt | 18 ++++++++++++++++++ .../tests/ArrayObject/natsort_disabled.phpt | 18 ++++++++++++++++++ ext/spl/tests/ArrayObject/uasort_disabled.phpt | 18 ++++++++++++++++++ ext/spl/tests/ArrayObject/uksort_disabled.phpt | 18 ++++++++++++++++++ 6 files changed, 108 insertions(+) create mode 100644 ext/spl/tests/ArrayObject/asort_disabled.phpt create mode 100644 ext/spl/tests/ArrayObject/ksort_disabled.phpt create mode 100644 ext/spl/tests/ArrayObject/natcasesort_disabled.phpt create mode 100644 ext/spl/tests/ArrayObject/natsort_disabled.phpt create mode 100644 ext/spl/tests/ArrayObject/uasort_disabled.phpt create mode 100644 ext/spl/tests/ArrayObject/uksort_disabled.phpt diff --git a/ext/spl/tests/ArrayObject/asort_disabled.phpt b/ext/spl/tests/ArrayObject/asort_disabled.phpt new file mode 100644 index 0000000000000..57fb742acbddb --- /dev/null +++ b/ext/spl/tests/ArrayObject/asort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function asort() is disabled +--INI-- +disable_functions=asort +--FILE-- +asort(); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback asort, function "asort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->asort() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/ArrayObject/ksort_disabled.phpt b/ext/spl/tests/ArrayObject/ksort_disabled.phpt new file mode 100644 index 0000000000000..4299c282189f1 --- /dev/null +++ b/ext/spl/tests/ArrayObject/ksort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function ksort() is disabled +--INI-- +disable_functions=ksort +--FILE-- +ksort(); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback ksort, function "ksort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->ksort() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt b/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt new file mode 100644 index 0000000000000..def9af50e3561 --- /dev/null +++ b/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function natcasesort() is disabled +--INI-- +disable_functions=natcasesort +--FILE-- +natcasesort(); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback natcasesort, function "natcasesort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->natcasesort() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/ArrayObject/natsort_disabled.phpt b/ext/spl/tests/ArrayObject/natsort_disabled.phpt new file mode 100644 index 0000000000000..994088b7950ec --- /dev/null +++ b/ext/spl/tests/ArrayObject/natsort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function natsort() is disabled +--INI-- +disable_functions=natsort +--FILE-- +natsort(); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback natsort, function "natsort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->natsort() +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/ArrayObject/uasort_disabled.phpt b/ext/spl/tests/ArrayObject/uasort_disabled.phpt new file mode 100644 index 0000000000000..298eadc7303c6 --- /dev/null +++ b/ext/spl/tests/ArrayObject/uasort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function uasort() is disabled +--INI-- +disable_functions=uasort +--FILE-- +uasort(fn ($l, $r) => $l <=> $r); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback uasort, function "uasort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->uasort(Object(Closure)) +#1 {main} + thrown in %s on line %d diff --git a/ext/spl/tests/ArrayObject/uksort_disabled.phpt b/ext/spl/tests/ArrayObject/uksort_disabled.phpt new file mode 100644 index 0000000000000..2abb020659c03 --- /dev/null +++ b/ext/spl/tests/ArrayObject/uksort_disabled.phpt @@ -0,0 +1,18 @@ +--TEST-- +ArrayObject when function uksort() is disabled +--INI-- +disable_functions=uksort +--FILE-- +uksort(fn ($l, $r) => $l <=> $r); +var_dump($ao); + +?> +--EXPECTF-- +Fatal error: Uncaught Error: Invalid callback uksort, function "uksort" not found or invalid function name in %s:%d +Stack trace: +#0 %s(%d): ArrayObject->uksort(Object(Closure)) +#1 {main} + thrown in %s on line %d From 0c3ee427d7f05dfe695a83aa62bbe07a9f6c5c85 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 3 Jul 2025 15:20:35 +0100 Subject: [PATCH 2/2] ext/spl: Refactor ArrayObject sort methods --- ext/spl/spl_array.c | 52 +++++++++++-------- ext/spl/spl_array.h | 4 -- ext/spl/tests/ArrayObject/asort_disabled.phpt | 2 +- ext/spl/tests/ArrayObject/ksort_disabled.phpt | 2 +- .../ArrayObject/natcasesort_disabled.phpt | 2 +- .../tests/ArrayObject/natsort_disabled.phpt | 2 +- .../tests/ArrayObject/uasort_disabled.phpt | 2 +- .../tests/ArrayObject/uksort_disabled.phpt | 2 +- 8 files changed, 37 insertions(+), 31 deletions(-) diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index b950330061920..5cb3e27bbb861 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1203,43 +1203,54 @@ PHP_METHOD(ArrayObject, count) RETURN_LONG(spl_array_object_count_elements_helper(intern)); } /* }}} */ -static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, size_t fname_len, int use_arg) /* {{{ */ +enum spl_array_object_sort_methods { + SPL_NAT_SORT, + SPL_CALLBACK_SORT, + SPL_OPTIONAL_FLAG_SORT +}; + +static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, const char *fname, size_t fname_len, enum spl_array_object_sort_methods use_arg) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(ZEND_THIS); HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern); HashTable *aht = *ht_ptr; - zval function_name, params[2], *arg = NULL; + zval params[2], *arg = NULL; - ZVAL_STRINGL(&function_name, fname, fname_len); + zend_function *fn = zend_hash_str_find_ptr(EG(function_table), fname, fname_len); + if (UNEXPECTED(fn == NULL)) { + zend_throw_error(NULL, "Cannot call method %s when function %s is disabled", fname, fname); + RETURN_THROWS(); + } ZVAL_NEW_EMPTY_REF(¶ms[0]); ZVAL_ARR(Z_REFVAL(params[0]), aht); GC_ADDREF(aht); - if (!use_arg) { + if (use_arg == SPL_NAT_SORT) { if (zend_parse_parameters_none() == FAILURE) { goto exit; } intern->nApplyCount++; - call_user_function(EG(function_table), NULL, &function_name, return_value, 1, params); + zend_call_known_function(fn, NULL, NULL, return_value, 1, params, NULL); intern->nApplyCount--; - } else if (use_arg == SPL_ARRAY_METHOD_SORT_FLAGS_ARG) { + } else if (use_arg == SPL_OPTIONAL_FLAG_SORT) { zend_long sort_flags = 0; if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) { goto exit; } ZVAL_LONG(¶ms[1], sort_flags); intern->nApplyCount++; - call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params); + zend_call_known_function(fn, NULL, NULL, return_value, 2, params, NULL); intern->nApplyCount--; } else { + ZEND_ASSERT(use_arg == SPL_CALLBACK_SORT); if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) { goto exit; } ZVAL_COPY_VALUE(¶ms[1], arg); intern->nApplyCount++; - call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params); + zend_call_known_function(fn, NULL, NULL, return_value, 2, params, NULL); intern->nApplyCount--; } @@ -1251,7 +1262,6 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, size_t f *ht_ptr = Z_ARRVAL_P(ht_zv); ZVAL_NULL(ht_zv); zval_ptr_dtor(¶ms[0]); - zend_string_free(Z_STR(function_name)); } } /* }}} */ @@ -1261,23 +1271,23 @@ PHP_METHOD(cname, fname) \ spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \ } -/* {{{ Sort the entries by values. */ -SPL_ARRAY_METHOD(ArrayObject, asort, SPL_ARRAY_METHOD_SORT_FLAGS_ARG) /* }}} */ +/* Sort the entries by values. */ +SPL_ARRAY_METHOD(ArrayObject, asort, SPL_OPTIONAL_FLAG_SORT) -/* {{{ Sort the entries by key. */ -SPL_ARRAY_METHOD(ArrayObject, ksort, SPL_ARRAY_METHOD_SORT_FLAGS_ARG) /* }}} */ +/* Sort the entries by key. */ +SPL_ARRAY_METHOD(ArrayObject, ksort, SPL_OPTIONAL_FLAG_SORT) -/* {{{ Sort the entries by values user defined function. */ -SPL_ARRAY_METHOD(ArrayObject, uasort, SPL_ARRAY_METHOD_CALLBACK_ARG) /* }}} */ +/* Sort the entries by values user defined function. */ +SPL_ARRAY_METHOD(ArrayObject, uasort, SPL_CALLBACK_SORT) -/* {{{ Sort the entries by key using user defined function. */ -SPL_ARRAY_METHOD(ArrayObject, uksort, SPL_ARRAY_METHOD_CALLBACK_ARG) /* }}} */ +/* Sort the entries by key using user defined function. */ +SPL_ARRAY_METHOD(ArrayObject, uksort, SPL_CALLBACK_SORT) -/* {{{ Sort the entries by values using "natural order" algorithm. */ -SPL_ARRAY_METHOD(ArrayObject, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */ +/* Sort the entries by values using "natural order" algorithm. */ +SPL_ARRAY_METHOD(ArrayObject, natsort, SPL_NAT_SORT) -/* {{{ Sort the entries by key using case insensitive "natural order" algorithm. */ -SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */ +/* {{{ Sort the entries by key using case-insensitive "natural order" algorithm. */ +SPL_ARRAY_METHOD(ArrayObject, natcasesort, SPL_NAT_SORT) /* {{{ Serialize the object */ PHP_METHOD(ArrayObject, serialize) diff --git a/ext/spl/spl_array.h b/ext/spl/spl_array.h index f3577f4beeaad..86de7a955c5b2 100644 --- a/ext/spl/spl_array.h +++ b/ext/spl/spl_array.h @@ -27,10 +27,6 @@ #define SPL_ARRAY_INT_MASK 0xFFFF0000 #define SPL_ARRAY_CLONE_MASK 0x0100FFFF -#define SPL_ARRAY_METHOD_NO_ARG 0 -#define SPL_ARRAY_METHOD_CALLBACK_ARG 1 -#define SPL_ARRAY_METHOD_SORT_FLAGS_ARG 2 - extern PHPAPI zend_class_entry *spl_ce_ArrayObject; extern PHPAPI zend_class_entry *spl_ce_ArrayIterator; extern PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator; diff --git a/ext/spl/tests/ArrayObject/asort_disabled.phpt b/ext/spl/tests/ArrayObject/asort_disabled.phpt index 57fb742acbddb..8f2241332f72e 100644 --- a/ext/spl/tests/ArrayObject/asort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/asort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback asort, function "asort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method asort when function asort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->asort() #1 {main} diff --git a/ext/spl/tests/ArrayObject/ksort_disabled.phpt b/ext/spl/tests/ArrayObject/ksort_disabled.phpt index 4299c282189f1..258057ad64d31 100644 --- a/ext/spl/tests/ArrayObject/ksort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/ksort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback ksort, function "ksort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method ksort when function ksort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->ksort() #1 {main} diff --git a/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt b/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt index def9af50e3561..336e1245dabc5 100644 --- a/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/natcasesort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback natcasesort, function "natcasesort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method natcasesort when function natcasesort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->natcasesort() #1 {main} diff --git a/ext/spl/tests/ArrayObject/natsort_disabled.phpt b/ext/spl/tests/ArrayObject/natsort_disabled.phpt index 994088b7950ec..b674235627adb 100644 --- a/ext/spl/tests/ArrayObject/natsort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/natsort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback natsort, function "natsort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method natsort when function natsort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->natsort() #1 {main} diff --git a/ext/spl/tests/ArrayObject/uasort_disabled.phpt b/ext/spl/tests/ArrayObject/uasort_disabled.phpt index 298eadc7303c6..5a5e9aa57b21a 100644 --- a/ext/spl/tests/ArrayObject/uasort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/uasort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback uasort, function "uasort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method uasort when function uasort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->uasort(Object(Closure)) #1 {main} diff --git a/ext/spl/tests/ArrayObject/uksort_disabled.phpt b/ext/spl/tests/ArrayObject/uksort_disabled.phpt index 2abb020659c03..af703883a3f55 100644 --- a/ext/spl/tests/ArrayObject/uksort_disabled.phpt +++ b/ext/spl/tests/ArrayObject/uksort_disabled.phpt @@ -11,7 +11,7 @@ var_dump($ao); ?> --EXPECTF-- -Fatal error: Uncaught Error: Invalid callback uksort, function "uksort" not found or invalid function name in %s:%d +Fatal error: Uncaught Error: Cannot call method uksort when function uksort is disabled in %s:%d Stack trace: #0 %s(%d): ArrayObject->uksort(Object(Closure)) #1 {main}