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
210 changes: 105 additions & 105 deletions Zend/zend_autoload.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,139 +28,139 @@ ZEND_TLS HashTable *zend_class_autoload_functions;

static void zend_autoload_callback_zval_destroy(zval *element)
{
zend_fcall_info_cache *fcc = Z_PTR_P(element);
zend_fcc_dtor(fcc);
efree(fcc);
zend_fcall_info_cache *fcc = Z_PTR_P(element);
zend_fcc_dtor(fcc);
efree(fcc);
}

static Bucket *autoload_find_registered_function(const HashTable *autoloader_table, const zend_fcall_info_cache *function_entry)
{
zend_fcall_info_cache *current_function_entry;
ZEND_HASH_MAP_FOREACH_PTR(autoloader_table, current_function_entry) {
if (zend_fcc_equals(current_function_entry, function_entry)) {
return _p;
}
} ZEND_HASH_FOREACH_END();
return NULL;
zend_fcall_info_cache *current_function_entry;
ZEND_HASH_MAP_FOREACH_PTR(autoloader_table, current_function_entry) {
if (zend_fcc_equals(current_function_entry, function_entry)) {
return _p;
}
} ZEND_HASH_FOREACH_END();
return NULL;
}

ZEND_API zend_class_entry *zend_perform_class_autoload(zend_string *class_name, zend_string *lc_name)
{
if (!zend_class_autoload_functions) {
return NULL;
}

zval zname;
ZVAL_STR(&zname, class_name);

const HashTable *class_autoload_functions = zend_class_autoload_functions;

/* Cannot use ZEND_HASH_MAP_FOREACH_PTR here as autoloaders may be
* added/removed during autoloading. */
HashPosition pos;
zend_hash_internal_pointer_reset_ex(class_autoload_functions, &pos);
while (true) {
zend_fcall_info_cache *func_info = zend_hash_get_current_data_ptr_ex(class_autoload_functions, &pos);
if (!func_info) {
break;
}
zend_call_known_fcc(func_info, /* retval */ NULL, /* param_count */ 1, /* params */ &zname, /* named_params */ NULL);

if (EG(exception)) {
return NULL;
}
if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name);
}

zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
return ce;
}

zend_hash_move_forward_ex(class_autoload_functions, &pos);
}
return NULL;
if (!zend_class_autoload_functions) {
return NULL;
}

zval zname;
ZVAL_STR(&zname, class_name);

const HashTable *class_autoload_functions = zend_class_autoload_functions;

/* Cannot use ZEND_HASH_MAP_FOREACH_PTR here as autoloaders may be
* added/removed during autoloading. */
HashPosition pos;
zend_hash_internal_pointer_reset_ex(class_autoload_functions, &pos);
while (true) {
zend_fcall_info_cache *func_info = zend_hash_get_current_data_ptr_ex(class_autoload_functions, &pos);
if (!func_info) {
break;
}
zend_call_known_fcc(func_info, /* retval */ NULL, /* param_count */ 1, /* params */ &zname, /* named_params */ NULL);

if (EG(exception)) {
return NULL;
}
if (ZSTR_HAS_CE_CACHE(class_name) && ZSTR_GET_CE_CACHE(class_name)) {
return (zend_class_entry*)ZSTR_GET_CE_CACHE(class_name);
}

zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lc_name);
if (ce) {
return ce;
}

zend_hash_move_forward_ex(class_autoload_functions, &pos);
}
return NULL;
}

/* Needed for compatibility with spl_register_autoload() */
ZEND_API void zend_autoload_register_class_loader(zend_fcall_info_cache *fcc, bool prepend)
{
ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc));

if (!zend_class_autoload_functions) {
ALLOC_HASHTABLE(zend_class_autoload_functions);
zend_hash_init(zend_class_autoload_functions, 1, NULL, zend_autoload_callback_zval_destroy, false);
/* Initialize as non-packed hash table for prepend functionality. */
zend_hash_real_init_mixed(zend_class_autoload_functions);
}

ZEND_ASSERT(
fcc->function_handler->type != ZEND_INTERNAL_FUNCTION
|| !zend_string_equals_literal(fcc->function_handler->common.function_name, "spl_autoload_call")
);

/* If function is already registered, don't do anything */
if (autoload_find_registered_function(zend_class_autoload_functions, fcc)) {
/* Release potential call trampoline */
zend_release_fcall_info_cache(fcc);
return;
}

zend_fcc_addref(fcc);
zend_hash_next_index_insert_mem(zend_class_autoload_functions, fcc, sizeof(zend_fcall_info_cache));
if (prepend && zend_hash_num_elements(zend_class_autoload_functions) > 1) {
/* Move the newly created element to the head of the hashtable */
ZEND_ASSERT(!HT_IS_PACKED(zend_class_autoload_functions));
Bucket tmp = zend_class_autoload_functions->arData[zend_class_autoload_functions->nNumUsed-1];
memmove(zend_class_autoload_functions->arData + 1, zend_class_autoload_functions->arData, sizeof(Bucket) * (zend_class_autoload_functions->nNumUsed - 1));
zend_class_autoload_functions->arData[0] = tmp;
zend_hash_rehash(zend_class_autoload_functions);
}
ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc));

if (!zend_class_autoload_functions) {
ALLOC_HASHTABLE(zend_class_autoload_functions);
zend_hash_init(zend_class_autoload_functions, 1, NULL, zend_autoload_callback_zval_destroy, false);
/* Initialize as non-packed hash table for prepend functionality. */
zend_hash_real_init_mixed(zend_class_autoload_functions);
}

ZEND_ASSERT(
fcc->function_handler->type != ZEND_INTERNAL_FUNCTION
|| !zend_string_equals_literal(fcc->function_handler->common.function_name, "spl_autoload_call")
);

/* If function is already registered, don't do anything */
if (autoload_find_registered_function(zend_class_autoload_functions, fcc)) {
/* Release potential call trampoline */
zend_release_fcall_info_cache(fcc);
return;
}

zend_fcc_addref(fcc);
zend_hash_next_index_insert_mem(zend_class_autoload_functions, fcc, sizeof(zend_fcall_info_cache));
if (prepend && zend_hash_num_elements(zend_class_autoload_functions) > 1) {
/* Move the newly created element to the head of the hashtable */
ZEND_ASSERT(!HT_IS_PACKED(zend_class_autoload_functions));
Bucket tmp = zend_class_autoload_functions->arData[zend_class_autoload_functions->nNumUsed-1];
memmove(zend_class_autoload_functions->arData + 1, zend_class_autoload_functions->arData, sizeof(Bucket) * (zend_class_autoload_functions->nNumUsed - 1));
zend_class_autoload_functions->arData[0] = tmp;
zend_hash_rehash(zend_class_autoload_functions);
}
}

ZEND_API bool zend_autoload_unregister_class_loader(const zend_fcall_info_cache *fcc) {
if (zend_class_autoload_functions) {
Bucket *p = autoload_find_registered_function(zend_class_autoload_functions, fcc);
if (p) {
zend_hash_del_bucket(zend_class_autoload_functions, p);
return true;
}
}
return false;
if (zend_class_autoload_functions) {
Bucket *p = autoload_find_registered_function(zend_class_autoload_functions, fcc);
if (p) {
zend_hash_del_bucket(zend_class_autoload_functions, p);
return true;
}
}
return false;
}

/* We do not return a HashTable* because zend_empty_array is not collectable,
* therefore the zval holding this value must do so. Something that ZVAL_EMPTY_ARRAY(); does. */
ZEND_API void zend_autoload_fcc_map_to_callable_zval_map(zval *return_value) {
if (zend_class_autoload_functions) {
zend_fcall_info_cache *fcc;

zend_array *map = zend_new_array(zend_hash_num_elements(zend_class_autoload_functions));
ZEND_HASH_MAP_FOREACH_PTR(zend_class_autoload_functions, fcc) {
zval tmp;
zend_get_callable_zval_from_fcc(fcc, &tmp);
zend_hash_next_index_insert(map, &tmp);
} ZEND_HASH_FOREACH_END();
RETURN_ARR(map);
}
RETURN_EMPTY_ARRAY();
if (zend_class_autoload_functions) {
zend_fcall_info_cache *fcc;

zend_array *map = zend_new_array(zend_hash_num_elements(zend_class_autoload_functions));
ZEND_HASH_MAP_FOREACH_PTR(zend_class_autoload_functions, fcc) {
zval tmp;
zend_get_callable_zval_from_fcc(fcc, &tmp);
zend_hash_next_index_insert(map, &tmp);
} ZEND_HASH_FOREACH_END();
RETURN_ARR(map);
}
RETURN_EMPTY_ARRAY();
}

/* Only for deprecated strange behaviour of spl_autoload_unregister() */
ZEND_API void zend_autoload_clean_class_loaders(void)
{
if (zend_class_autoload_functions) {
/* Don't destroy the hash table, as we might be iterating over it right now. */
zend_hash_clean(zend_class_autoload_functions);
}
if (zend_class_autoload_functions) {
/* Don't destroy the hash table, as we might be iterating over it right now. */
zend_hash_clean(zend_class_autoload_functions);
}
}

void zend_autoload_shutdown(void)
{
if (zend_class_autoload_functions) {
zend_hash_destroy(zend_class_autoload_functions);
FREE_HASHTABLE(zend_class_autoload_functions);
zend_class_autoload_functions = NULL;
}
if (zend_class_autoload_functions) {
zend_hash_destroy(zend_class_autoload_functions);
FREE_HASHTABLE(zend_class_autoload_functions);
zend_class_autoload_functions = NULL;
}
}
6 changes: 3 additions & 3 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7896,7 +7896,7 @@ static bool zend_property_hook_uses_property(const zend_string *property_name, c
return context.uses_property;
}

static bool zend_property_is_virtual(const zend_class_entry *ce, const zend_string *property_name, zend_ast *hooks_ast, uint32_t flags)
static bool zend_property_is_virtual(const zend_class_entry *ce, const zend_string *property_name, zend_ast *hooks_ast)
{
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
return true;
Expand Down Expand Up @@ -8172,7 +8172,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zend_property_info *prop = zend_declare_typed_property(
scope, name, &default_value,
property_flags | (zend_property_is_virtual(scope, name, hooks_ast, property_flags) ? ZEND_ACC_VIRTUAL : 0) | ZEND_ACC_PROMOTED,
property_flags | (zend_property_is_virtual(scope, name, hooks_ast) ? ZEND_ACC_VIRTUAL : 0) | ZEND_ACC_PROMOTED,
doc_comment, type);
if (hooks_ast) {
const zend_ast_list *hooks = zend_ast_get_list(hooks_ast);
Expand Down Expand Up @@ -9074,7 +9074,7 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f
zend_string *doc_comment = NULL;
zval value_zv;
zend_type type = ZEND_TYPE_INIT_NONE(0);
flags |= zend_property_is_virtual(ce, name, hooks_ast, flags) ? ZEND_ACC_VIRTUAL : 0;
flags |= zend_property_is_virtual(ce, name, hooks_ast) ? ZEND_ACC_VIRTUAL : 0;

zend_string *old_active_property_info_name = CG(context).active_property_info_name;
CG(context).active_property_info_name = name;
Expand Down
10 changes: 10 additions & 0 deletions ext/curl/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
zval argv[3];
zval retval;

if (!ZEND_FCC_INITIALIZED(ch->handlers.fnmatch)) {
return rval;
}

GC_ADDREF(&ch->std);
ZVAL_OBJ(&argv[0], &ch->std);
ZVAL_STRING(&argv[1], pattern);
Expand Down Expand Up @@ -606,6 +610,9 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
fprintf(stderr, "curl_progress() called\n");
fprintf(stderr, "clientp = %x, dltotal = %f, dlnow = %f, ultotal = %f, ulnow = %f\n", clientp, dltotal, dlnow, ultotal, ulnow);
#endif
if (!ZEND_FCC_INITIALIZED(ch->handlers.progress)) {
return rval;
}

zval args[5];
zval retval;
Expand Down Expand Up @@ -644,6 +651,9 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
fprintf(stderr, "curl_xferinfo() called\n");
fprintf(stderr, "clientp = %x, dltotal = %ld, dlnow = %ld, ultotal = %ld, ulnow = %ld\n", clientp, dltotal, dlnow, ultotal, ulnow);
#endif
if (!ZEND_FCC_INITIALIZED(ch->handlers.xferinfo)) {
return rval;
}

zval argv[5];
zval retval;
Expand Down
27 changes: 27 additions & 0 deletions ext/curl/tests/gh21023.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
GH-21023 (crash with CURLOPT_XFERINFOFUNCTION set with an invalid callback)
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';
$host = curl_cli_server_start();
$url = "{$host}/get.inc";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION, null);
curl_exec($ch);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, null);
curl_exec($ch);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_WILDCARDMATCH, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FNMATCH_FUNCTION, null);
curl_exec($ch);
echo "OK", PHP_EOL;
?>
--EXPECT--
OK
4 changes: 1 addition & 3 deletions ext/ftp/php_ftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ static zend_class_entry *php_ftp_ce = NULL;
static zend_object_handlers ftp_object_handlers;

zend_module_entry php_ftp_module_entry = {
STANDARD_MODULE_HEADER_EX,
NULL,
NULL,
STANDARD_MODULE_HEADER,
"ftp",
ext_functions,
PHP_MINIT(ftp),
Expand Down
2 changes: 1 addition & 1 deletion ext/opcache/jit/ir/ir_gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ static bool ir_split_partially_dead_node(ir_ctx *ctx, ir_ref ref, uint32_t b)
#endif

/* 1.2. Iteratively check the predecessors of already found TOTALLY_USEFUL blocks and
* add them into TOTALLY_USEFUL set if all of their sucessors are already there.
* add them into TOTALLY_USEFUL set if all of their successors are already there.
*/
IR_SPARSE_SET_FOREACH(&data->totally_useful, i) {
_push_predecessors(ctx, &ctx->cfg_blocks[i], data);
Expand Down