Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_closures.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
24 changes: 12 additions & 12 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ext/dom/xpath_callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion ext/ffi/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
63 changes: 63 additions & 0 deletions ext/gd/tests/gif-oob.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
--TEST--
GIF OOB array access when using code size of 12
--EXTENSIONS--
gd
--FILE--
<?php

$fileHeaderParts = [
"signature" => "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) {
}
6 changes: 3 additions & 3 deletions ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion ext/pcntl/pcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion ext/pcre/php_pcre.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/pdo_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/streamsfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
57 changes: 57 additions & 0 deletions ext/tidy/tests/reparse_node.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--TEST--
tidyNode objects are invalid after reparsing their document
--EXTENSIONS--
tidy
--FILE--
<?php

$tidy = tidy_parse_string('<html><body><p>one</p><p>two</p></body></html>');
$node = $tidy->body()->child[0];
var_dump($node->isHtml());
var_dump($node->hasSiblings());

$tidy->parseString('<html><body><p>three</p></body></html>');

$operations = [
'string cast' => static fn() => (string) $node,
'hasChildren' => static fn() => $node->hasChildren(),
'hasSiblings' => static fn() => $node->hasSiblings(),
'isComment' => static fn() => $node->isComment(),
'isHtml' => static fn() => $node->isHtml(),
'isText' => static fn() => $node->isText(),
'isJste' => static fn() => $node->isJste(),
'isAsp' => static fn() => $node->isAsp(),
'isPhp' => static fn() => $node->isPhp(),
'getParent' => static fn() => $node->getParent(),
'getPreviousSibling' => static fn() => $node->getPreviousSibling(),
'getNextSibling' => static fn() => $node->getNextSibling(),
];

foreach ($operations as $operation => $callback) {
try {
$callback();
echo $operation, ": no error\n";
} catch (Error $e) {
echo $operation, ': ', $e::class, ': ', $e->getMessage(), "\n";
}
}

var_dump($tidy->body()->child[0]->isHtml());

?>
--EXPECT--
bool(true)
bool(true)
string cast: Error: tidyNode object is no longer valid after its document was reparsed
hasChildren: Error: tidyNode object is no longer valid after its document was reparsed
hasSiblings: Error: tidyNode object is no longer valid after its document was reparsed
isComment: Error: tidyNode object is no longer valid after its document was reparsed
isHtml: Error: tidyNode object is no longer valid after its document was reparsed
isText: Error: tidyNode object is no longer valid after its document was reparsed
isJste: Error: tidyNode object is no longer valid after its document was reparsed
isAsp: Error: tidyNode object is no longer valid after its document was reparsed
isPhp: Error: tidyNode object is no longer valid after its document was reparsed
getParent: Error: tidyNode object is no longer valid after its document was reparsed
getPreviousSibling: Error: tidyNode object is no longer valid after its document was reparsed
getNextSibling: Error: tidyNode object is no longer valid after its document was reparsed
bool(true)
Loading