diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 82f273974cd5..24f6a1b96674 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -29,6 +29,10 @@ PHP 8.7 INTERNALS UPGRADE NOTES and C23, which means that ZEND_NORETURN needs to come first in the modifier list. Consider using noreturn (C11) / [[noreturn]] (C23) directly if header interoperability is not required. +- The signature of zend_is_callable() has been changed to + zend_is_callable(const zval *callable, zend_fcall_info_cache *fcc, char **error) + from zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name). + This new signature covers the most common parameters used with zend_is_callable_ex(). ======================== 2. Build system changes diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 5c4083052202..c94a71cf56b8 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -422,9 +422,9 @@ ZEND_API bool zend_is_callable_at_frame( const zval *callable, zend_object *object, const zend_execute_data *frame, uint32_t check_flags, zend_fcall_info_cache *fcc, char **error); ZEND_API bool zend_is_callable_ex(const zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error); -static zend_always_inline bool zend_is_callable(const zval *callable, uint32_t check_flags, zend_string **callable_name) +static zend_always_inline bool zend_is_callable(const zval *callable, zend_fcall_info_cache *fcc, char **error) { - return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL); + return zend_is_callable_ex(callable, NULL, 0, NULL, fcc, error); } ZEND_API const char *zend_get_module_version(const char *module_name); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index d4c0b5881369..9d5971fac479 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -399,7 +399,7 @@ static zend_result zend_create_closure_from_callable(zval *return_value, zval *c zend_function *mptr; zend_internal_function call; - if (!zend_is_callable_ex(callable, NULL, 0, NULL, &fcc, error)) { + if (!zend_is_callable(callable, &fcc, error)) { return FAILURE; } diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index ff3a5f0b3de9..9c414634a23e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1213,7 +1213,7 @@ static zend_always_inline bool zend_check_type_slow( const uint32_t type_mask = ZEND_TYPE_FULL_MASK(*type); if ((type_mask & MAY_BE_CALLABLE) && - zend_is_callable(arg, is_internal ? IS_CALLABLE_SUPPRESS_DEPRECATIONS : 0, NULL)) { + zend_is_callable_ex(arg, NULL, is_internal ? IS_CALLABLE_SUPPRESS_DEPRECATIONS : 0, NULL, NULL, NULL)) { return 1; } if ((type_mask & MAY_BE_STATIC) && zend_value_instanceof_static(arg)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9c9e262169f8..d1355208c287 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3985,10 +3985,10 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMP|CV, NUM) SAVE_OPLINE(); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 942f18eb7040..fe2df85c23e3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7668,10 +7668,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL SAVE_OPLINE(); function_name = RT_CONSTANT(opline, opline->op2); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ @@ -10444,10 +10444,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL SAVE_OPLINE(); function_name = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ @@ -13108,10 +13108,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL SAVE_OPLINE(); function_name = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ @@ -60529,10 +60529,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE SAVE_OPLINE(); function_name = RT_CONSTANT(opline, opline->op2); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ @@ -63305,10 +63305,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE SAVE_OPLINE(); function_name = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ @@ -65867,10 +65867,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE SAVE_OPLINE(); function_name = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); - if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { + if (zend_is_callable(function_name, &fcc, &error)) { ZEND_ASSERT(!error); - /* Deprecation can be emitted from zend_is_callable_ex(), which can + /* Deprecation can be emitted from zend_is_callable(), which can * invoke a user error handler and throw an exception. * For the CONST and CV case we reuse the same exception block below * to make sure we don't increase VM size too much. */ diff --git a/ext/dom/xpath_callbacks.c b/ext/dom/xpath_callbacks.c index e4ad6c59b3d1..e0f75fbf6a7c 100644 --- a/ext/dom/xpath_callbacks.c +++ b/ext/dom/xpath_callbacks.c @@ -204,7 +204,7 @@ static zend_result php_dom_xpath_callback_ns_update_method_handler( ZEND_HASH_FOREACH_STR_KEY_VAL(callable_ht, key, entry) { zend_fcall_info_cache* fcc = emalloc(sizeof(*fcc)); char *error; - if (!zend_is_callable_ex(entry, NULL, 0, NULL, fcc, &error)) { + if (!zend_is_callable(entry, fcc, &error)) { zend_argument_type_error(1, "must be an array with valid callbacks as values, %s", error); efree(fcc); efree(error); @@ -251,7 +251,7 @@ static zend_result php_dom_xpath_callback_ns_update_method_handler( char *error; zval tmp; ZVAL_STR(&tmp, name); - if (!zend_is_callable_ex(&tmp, NULL, 0, NULL, fcc, &error)) { + if (!zend_is_callable(&tmp, fcc, &error)) { zend_argument_type_error(1, "must be a callable, %s", error); efree(fcc); efree(error); diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 37a0a215262b..0f6e7626d834 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -1006,7 +1006,7 @@ static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value) /* {{{ * return NULL; } - if (!zend_is_callable_ex(value, NULL, 0, NULL, &fcc, &error)) { + if (!zend_is_callable(value, &fcc, &error)) { zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, %s", error); return NULL; } diff --git a/ext/gd/tests/gif-oob.phpt b/ext/gd/tests/gif-oob.phpt new file mode 100644 index 000000000000..73fd0427c8e8 --- /dev/null +++ b/ext/gd/tests/gif-oob.phpt @@ -0,0 +1,63 @@ +--TEST-- +GIF OOB array access when using code size of 12 +--EXTENSIONS-- +gd +--FILE-- + "GIF", + "version" => "89a", +]; +$fileHeader = implode("", $fileHeaderParts); + +$logicalScreenDescriptorParts = [ + // little-endian format + "width" => "\x04\x00", + "height" => "\x04\x00", + // packed data: global color table flag (most significant bit), + // color resolution (3 bits, only meaningful if global color table is enabled + // and we don't enable it here) + // sort flag (one bit, again only meaningful if global color table is enabled) + // size of global color table (3 bits) + "packed_info" => "\x00", + "background_color_index" => "\x00", + "pixel_aspect_ratio" => "\x00", +]; +$logicalScreenDescriptor = implode("", $logicalScreenDescriptorParts); + +$startImage = ","; + +$imgDescParts = [ + // little-ending format + "left" => "\x00\x00", + "top" => "\x00\x00", + "width" => "\x04\x00", + "height" => "\x04\x00", + // more packed data: local color table flag, interlace flag, sort flag, + // 2 bits reserved for future use, then 3 bits for size of local color + // table, which we don't have + "packed_info" => "\x00", +]; +$imgDesc = implode("", $imgDescParts); + +$imgDataParts = [ + "lzw_min_code_size" => "\x0c", // 12 + "sub_block_num_bytes" => "\x05", + // Data in the block: 3 12-bit codes, and then 4 trailing 0 bits + "sub_block_bytes" => "\xff\x5f\x00\x06\x40", + // end of data + "end" => "\x00" +]; +$imgData = implode("", $imgDataParts); + +$trailer = ";"; + +$source = $fileHeader . $logicalScreenDescriptor . $startImage . $imgDesc . $imgData . $trailer; +$img = imagecreatefromstring($source); +var_dump($img); + +?> +--EXPECTF-- +object(GdImage)#%d (0) { +} diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 0466dd4bf653..854227318da0 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2007,7 +2007,7 @@ static zend_result php_openssl_validate_and_allocate_psk_callback( char *is_callable_error = NULL; zend_fcall_info_cache fcc = {0}; - if (!zend_is_callable_ex(callable, NULL, 0, NULL, &fcc, &is_callable_error)) { + if (!zend_is_callable(callable, &fcc, &is_callable_error)) { if (is_callable_error) { zend_type_error("%s must be a valid callback, %s", callback_name, is_callable_error); @@ -2130,7 +2130,7 @@ static zend_result php_openssl_setup_server_early_data(php_stream *stream, char *is_callable_error = NULL; zend_fcall_info_cache fcc = {0}; - if (!zend_is_callable_ex(val, NULL, 0, NULL, &fcc, &is_callable_error)) { + if (!zend_is_callable(val, &fcc, &is_callable_error)) { if (is_callable_error) { zend_type_error("early_data_cb must be a valid callback, %s", is_callable_error); efree(is_callable_error); @@ -2318,7 +2318,7 @@ static zend_result php_openssl_validate_and_allocate_session_callback( /* Validate callable */ zend_fcall_info_cache fcc; - if (!zend_is_callable_ex(callable, NULL, 0, NULL, &fcc, &is_callable_error)) { + if (!zend_is_callable(callable, &fcc, &is_callable_error)) { if (is_callable_error) { zend_type_error("%s must be a valid callback, %s", callback_name, is_callable_error); efree(is_callable_error); diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index c73478fe5835..0a40bd0f2dfe 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -842,7 +842,7 @@ PHP_FUNCTION(pcntl_signal) RETURN_TRUE; } - if (!zend_is_callable_ex(handle, NULL, 0, NULL, NULL, NULL)) { + if (!zend_is_callable(handle, NULL, NULL)) { PCNTL_G(last_error) = EINVAL; zend_argument_type_error(2, "must be of type callable|int, %s given", zend_zval_value_name(handle)); diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 4c63ab0920ae..fce1a21a6c29 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -2459,7 +2459,7 @@ PHP_FUNCTION(preg_replace_callback_array) /* Copy potential trampoline */ ZVAL_COPY_VALUE(&fci.function_name, replace); - if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) { + if (!zend_is_callable(replace, &fcc, NULL)) { zend_argument_type_error(1, "must contain only valid callbacks"); goto error; } diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 9774b197b7d9..4b56dbdbbd59 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -1116,7 +1116,7 @@ static bool pdo_get_fcc_from_zval(zend_fcall_info_cache *fcc, zval *callable) { } char *is_callable_error = NULL; - if (!zend_is_callable_ex(callable, NULL, 0, NULL, fcc, &is_callable_error)) { + if (!zend_is_callable(callable, fcc, &is_callable_error)) { if (is_callable_error) { zend_type_error("%s", is_callable_error); efree(is_callable_error); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 7552b00c1151..b1968d9ff118 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -5142,7 +5142,7 @@ void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS, /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal * with it ourselves. It is important that it is not refetched on every call, * because calls may occur from different scopes. */ - zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL); + zend_is_callable(&fci.function_name, &fcc, NULL); } obj = zend_object_make_lazy(obj, ce, &fci.function_name, &fcc, diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 90341109210f..6502ac279e26 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -967,7 +967,7 @@ static zend_result parse_context_params(php_stream_context *context, const HashT zend_fcall_info_cache *fcc = emalloc(sizeof(*fcc)); char *error; - if (!zend_is_callable_ex(tmp, NULL, 0, NULL, fcc, &error)) { + if (!zend_is_callable(tmp, fcc, &error)) { zend_argument_type_error(1, "must be an array with valid callbacks as values, %s", error); efree(fcc); efree(error); diff --git a/ext/tidy/tests/reparse_node.phpt b/ext/tidy/tests/reparse_node.phpt new file mode 100644 index 000000000000..2ee03d8344e8 --- /dev/null +++ b/ext/tidy/tests/reparse_node.phpt @@ -0,0 +1,57 @@ +--TEST-- +tidyNode objects are invalid after reparsing their document +--EXTENSIONS-- +tidy +--FILE-- +
one
two