diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 54bcad825a501..0ccb4ec68f594 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3856,6 +3856,7 @@ ZEND_API bool zend_is_callable_at_frame( fcc->called_scope = NULL; fcc->function_handler = NULL; fcc->object = NULL; + fcc->closure = NULL; again: switch (Z_TYPE_P(callable)) { @@ -3929,6 +3930,7 @@ ZEND_API bool zend_is_callable_at_frame( case IS_OBJECT: if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == SUCCESS) { fcc->called_scope = fcc->calling_scope; + fcc->closure = Z_OBJ_P(callable); if (fcc == &fcc_local) { zend_release_fcall_info_cache(fcc); } @@ -4143,6 +4145,24 @@ ZEND_API zend_result zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_ } /* }}} */ +ZEND_API void zend_get_callable_zval_from_fcc(const zend_fcall_info_cache *fcc, zval *callable) +{ + if (fcc->closure) { + ZVAL_OBJ_COPY(callable, fcc->closure); + } else if (fcc->function_handler->common.scope) { + array_init(callable); + if (fcc->object) { + GC_ADDREF(fcc->object); + add_next_index_object(callable, fcc->object); + } else { + add_next_index_str(callable, zend_string_copy(fcc->calling_scope->name)); + } + add_next_index_str(callable, zend_string_copy(fcc->function_handler->common.function_name)); + } else { + ZVAL_STR_COPY(callable, fcc->function_handler->common.function_name); + } +} + ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */ { zend_string *lname; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 3dcb07cfc1314..1f9f1f1201984 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -58,7 +58,8 @@ typedef struct _zend_fcall_info_cache { zend_function *function_handler; zend_class_entry *calling_scope; zend_class_entry *called_scope; - zend_object *object; + zend_object *object; /* Instance of object for method calls */ + zend_object *closure; /* Closure reference, only if the callable *is* the object */ } zend_fcall_info_cache; #define ZEND_NS_NAME(ns, name) ns "\\" name @@ -327,6 +328,7 @@ typedef struct _zend_fcall_info_cache { zend_class_backed_enum_table(ce) #define ZEND_FCI_INITIALIZED(fci) ((fci).size != 0) +#define ZEND_FCC_INITIALIZED(fcc) ((fcc).function_handler != NULL) ZEND_API int zend_next_free_module(void); @@ -728,6 +730,57 @@ ZEND_API void zend_fcall_info_argn(zend_fcall_info *fci, uint32_t argc, ...); */ ZEND_API zend_result zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval, zval *args); +/* Zend FCC API to store and handle PHP userland functions */ +static zend_always_inline bool zend_fcc_equals(const zend_fcall_info_cache* a, const zend_fcall_info_cache* b) +{ + return a->function_handler == b->function_handler + && a->object == b->object + && a->calling_scope == b->calling_scope + && a->closure == b->closure + ; +} + +static zend_always_inline void zend_fcc_addref(zend_fcall_info_cache *fcc) +{ + if (fcc->object) { + GC_ADDREF(fcc->object); + } + if (fcc->closure) { + GC_ADDREF(fcc->closure); + } +} + +static zend_always_inline void zend_fcc_dup(/* restrict */ zend_fcall_info_cache *dest, const zend_fcall_info_cache *src) +{ + memcpy(dest, src, sizeof(zend_fcall_info_cache)); + zend_fcc_addref(dest); +} + +static zend_always_inline void zend_fcc_dtor(zend_fcall_info_cache *fcc) +{ + if (fcc->object) { + OBJ_RELEASE(fcc->object); + } + if (fcc->closure) { + OBJ_RELEASE(fcc->closure); + } + memcpy(fcc, &empty_fcall_info_cache, sizeof(zend_fcall_info_cache)); +} + +ZEND_API void zend_get_callable_zval_from_fcc(const zend_fcall_info_cache *fcc, zval *callable); + +/* Moved out of zend_gc.h because zend_fcall_info_cache is an unknown type in that header */ +static zend_always_inline void zend_get_gc_buffer_add_fcc(zend_get_gc_buffer *gc_buffer, zend_fcall_info_cache *fcc) +{ + ZEND_ASSERT(ZEND_FCC_INITIALIZED(*fcc)); + if (fcc->object) { + zend_get_gc_buffer_add_obj(gc_buffer, fcc->object); + } + if (fcc->closure) { + zend_get_gc_buffer_add_obj(gc_buffer, fcc->closure); + } +} + /* Can only return FAILURE if EG(active) is false during late engine shutdown. * If the call or call setup throws, EG(exception) will be set and the retval * will be UNDEF. Otherwise, the retval will be a non-UNDEF value. */ @@ -750,6 +803,12 @@ ZEND_API void zend_call_known_function( zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params); +static zend_always_inline void zend_call_known_fcc( + zend_fcall_info_cache *fcc, zval *retval_ptr, uint32_t param_count, zval *params, HashTable *named_params) +{ + zend_call_known_function(fcc->function_handler, fcc->object, fcc->called_scope, retval_ptr, param_count, params, named_params); +} + /* Call the provided zend_function instance method on an object. */ static zend_always_inline void zend_call_known_instance_method( zend_function *fn, zend_object *object, zval *retval_ptr, diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 2baad89539251..9043e70bcc154 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -50,7 +50,7 @@ ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_n /* true globals */ ZEND_API const zend_fcall_info empty_fcall_info = {0}; -ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { NULL, NULL, NULL, NULL }; +ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = {0}; #ifdef ZEND_WIN32 ZEND_TLS HANDLE tq_timer = NULL; diff --git a/ext/libxml/libxml.c b/ext/libxml/libxml.c index 270a0367481bf..7cb5c61a87db8 100644 --- a/ext/libxml/libxml.c +++ b/ext/libxml/libxml.c @@ -228,9 +228,7 @@ static PHP_GINIT_FUNCTION(libxml) ZVAL_UNDEF(&libxml_globals->stream_context); libxml_globals->error_buffer.s = NULL; libxml_globals->error_list = NULL; - ZVAL_NULL(&libxml_globals->entity_loader.callback); - libxml_globals->entity_loader.fci.size = 0; - libxml_globals->entity_loader_disabled = 0; + libxml_globals->entity_loader_callback = empty_fcall_info_cache; } /* Channel libxml file io layer through the PHP streams subsystem. @@ -573,13 +571,9 @@ static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, const char *resource = NULL; zval *ctxzv, retval; zval params[3]; - int status; - zend_fcall_info *fci; - fci = &LIBXML(entity_loader).fci; - - if (fci->size == 0) { - /* no custom user-land callback set up; delegate to original loader */ + /* no custom user-land callback set up; delegate to original loader */ + if (!ZEND_FCC_INITIALIZED(LIBXML(entity_loader_callback))) { return _php_libxml_default_entity_loader(URL, ID, context); } @@ -611,24 +605,14 @@ static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, #undef ADD_NULL_OR_STRING_KEY - fci->retval = &retval; - fci->params = params; - fci->param_count = sizeof(params)/sizeof(*params); + zend_call_known_fcc(&LIBXML(entity_loader_callback), &retval, 3, params, /* named_params */ NULL); - status = zend_call_function(fci, &LIBXML(entity_loader).fcc); - if (status != SUCCESS || Z_ISUNDEF(retval)) { + if (Z_ISUNDEF(retval)) { php_libxml_ctx_error(context, "Call to user entity loader callback '%s' has failed", - Z_STRVAL(fci->function_name)); + ZSTR_VAL(LIBXML(entity_loader_callback).function_handler->common.function_name)); } else { - /* - retval_ptr = *fci->retval_ptr_ptr; - if (retval_ptr == NULL) { - php_libxml_ctx_error(context, - "Call to user entity loader callback '%s' has failed; " - "probably it has thrown an exception", - fci->function_name); - } else */ if (Z_TYPE(retval) == IS_STRING) { + if (Z_TYPE(retval) == IS_STRING) { is_string: resource = Z_STRVAL(retval); } else if (Z_TYPE(retval) == IS_RESOURCE) { @@ -638,7 +622,7 @@ static xmlParserInputPtr _php_libxml_external_entity_loader(const char *URL, php_libxml_ctx_error(context, "The user entity loader callback '%s' has returned a " "resource, but it is not a stream", - Z_STRVAL(fci->function_name)); + ZSTR_VAL(LIBXML(entity_loader_callback).function_handler->common.function_name)); } else { /* TODO: allow storing the encoding in the stream context? */ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; @@ -839,9 +823,9 @@ static PHP_RINIT_FUNCTION(libxml) static PHP_RSHUTDOWN_FUNCTION(libxml) { - LIBXML(entity_loader).fci.size = 0; - zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback); - ZVAL_NULL(&LIBXML(entity_loader).callback); + if (ZEND_FCC_INITIALIZED(LIBXML(entity_loader_callback))) { + zend_fcc_dtor(&LIBXML(entity_loader_callback)); + } return SUCCESS; } @@ -1061,24 +1045,20 @@ PHP_FUNCTION(libxml_disable_entity_loader) /* {{{ Changes the default external entity loader */ PHP_FUNCTION(libxml_set_external_entity_loader) { - zval *callback; zend_fcall_info fci; zend_fcall_info_cache fcc; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_FUNC_OR_NULL_WITH_ZVAL(fci, fcc, callback) + Z_PARAM_FUNC_OR_NULL(fci, fcc) ZEND_PARSE_PARAMETERS_END(); - if (ZEND_FCI_INITIALIZED(fci)) { /* argument not null */ - LIBXML(entity_loader).fci = fci; - LIBXML(entity_loader).fcc = fcc; - } else { - LIBXML(entity_loader).fci.size = 0; + /* Unset old callback if it's defined */ + if (ZEND_FCC_INITIALIZED(LIBXML(entity_loader_callback))) { + zend_fcc_dtor(&LIBXML(entity_loader_callback)); } - if (!Z_ISNULL(LIBXML(entity_loader).callback)) { - zval_ptr_dtor_nogc(&LIBXML(entity_loader).callback); + if (ZEND_FCI_INITIALIZED(fci)) { /* argument not null */ + zend_fcc_dup(&LIBXML(entity_loader_callback), &fcc); } - ZVAL_COPY(&LIBXML(entity_loader).callback, callback); RETURN_TRUE; } /* }}} */ @@ -1087,7 +1067,15 @@ PHP_FUNCTION(libxml_set_external_entity_loader) PHP_FUNCTION(libxml_get_external_entity_loader) { ZEND_PARSE_PARAMETERS_NONE(); - RETURN_COPY(&LIBXML(entity_loader).callback); + + if (ZEND_FCC_INITIALIZED(LIBXML(entity_loader_callback))) { + zval tmp; + zend_get_callable_zval_from_fcc(&LIBXML(entity_loader_callback), &tmp); + RETVAL_COPY(&tmp); + zval_ptr_dtor(&tmp); + return; + } + RETURN_NULL(); } /* }}} */ diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h index 96217fd778627..ff8a634e0cf9b 100644 --- a/ext/libxml/php_libxml.h +++ b/ext/libxml/php_libxml.h @@ -42,11 +42,7 @@ ZEND_BEGIN_MODULE_GLOBALS(libxml) zval stream_context; smart_str error_buffer; zend_llist *error_list; - struct _php_libxml_entity_resolver { - zval callback; - zend_fcall_info fci; - zend_fcall_info_cache fcc; - } entity_loader; + zend_fcall_info_cache entity_loader_callback; bool entity_loader_disabled; ZEND_END_MODULE_GLOBALS(libxml) diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 2aebc23384858..f70a07b777f06 100644 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -101,12 +101,6 @@ typedef struct _spl_recursive_it_iterator { zend_object_iterator intern; } spl_recursive_it_iterator; -typedef struct _spl_cbfilter_it_intern { - zend_fcall_info fci; - zend_fcall_info_cache fcc; - zend_object *object; -} _spl_cbfilter_it_intern; - typedef struct _spl_dual_it_object { struct { zval zobject; @@ -143,7 +137,7 @@ typedef struct _spl_dual_it_object { regex_mode mode; int use_flags; } regex; - _spl_cbfilter_it_intern *cbfilter; + zend_fcall_info_cache callback_filter; } u; zend_object std; } spl_dual_it_object; @@ -1441,16 +1435,11 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z } case DIT_CallbackFilterIterator: case DIT_RecursiveCallbackFilterIterator: { - _spl_cbfilter_it_intern *cfi = emalloc(sizeof(*cfi)); - cfi->fci.object = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of", &zobject, ce_inner, &cfi->fci, &cfi->fcc) == FAILURE) { - efree(cfi); + zend_fcall_info fci; + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of", &zobject, ce_inner, &fci, &intern->u.callback_filter) == FAILURE) { return NULL; } - Z_TRY_ADDREF(cfi->fci.function_name); - cfi->object = cfi->fcc.object; - if (cfi->object) GC_ADDREF(cfi->object); - intern->u.cbfilter = cfi; + zend_fcc_addref(&intern->u.callback_filter); break; } default: @@ -1783,7 +1772,10 @@ PHP_METHOD(RecursiveCallbackFilterIterator, getChildren) zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "getchildren", &retval); if (!EG(exception) && Z_TYPE(retval) != IS_UNDEF) { - spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, &retval, &intern->u.cbfilter->fci.function_name); + zval callable; + zend_get_callable_zval_from_fcc(&intern->u.callback_filter, &callable); + spl_instantiate_arg_ex2(Z_OBJCE_P(ZEND_THIS), return_value, &retval, &callable); + zval_ptr_dtor(&callable); } zval_ptr_dtor(&retval); } /* }}} */ @@ -1819,13 +1811,10 @@ PHP_METHOD(CallbackFilterIterator, accept) ZVAL_COPY_VALUE(¶ms[1], &intern->current.key); ZVAL_COPY_VALUE(¶ms[2], &intern->inner.zobject); - zend_fcall_info *fci = &intern->u.cbfilter->fci; - zend_fcall_info_cache *fcc = &intern->u.cbfilter->fcc; - fci->retval = return_value; - fci->param_count = 3; - fci->params = params; + zend_fcall_info_cache *fcc = &intern->u.callback_filter; - if (zend_call_function(fci, fcc) != SUCCESS || Z_ISUNDEF_P(return_value)) { + zend_call_known_fcc(fcc, return_value, 3, params, NULL); + if (Z_ISUNDEF_P(return_value)) { RETURN_FALSE; } } @@ -2129,14 +2118,8 @@ static void spl_dual_it_free_storage(zend_object *_object) } if (object->dit_type == DIT_CallbackFilterIterator || object->dit_type == DIT_RecursiveCallbackFilterIterator) { - if (object->u.cbfilter) { - _spl_cbfilter_it_intern *cbfilter = object->u.cbfilter; - object->u.cbfilter = NULL; - zval_ptr_dtor(&cbfilter->fci.function_name); - if (cbfilter->fci.object) { - OBJ_RELEASE(cbfilter->fci.object); - } - efree(cbfilter); + if (ZEND_FCC_INITIALIZED(object->u.callback_filter)) { + zend_fcc_dtor(&object->u.callback_filter); } } @@ -2181,11 +2164,8 @@ static HashTable *spl_dual_it_get_gc(zend_object *obj, zval **table, int *n) break; case DIT_CallbackFilterIterator: case DIT_RecursiveCallbackFilterIterator: - if (object->u.cbfilter) { - zend_get_gc_buffer_add_zval(gc_buffer, &object->u.cbfilter->fci.function_name); - if (object->u.cbfilter->fci.object) { - zend_get_gc_buffer_add_obj(gc_buffer, object->u.cbfilter->fci.object); - } + if (ZEND_FCC_INITIALIZED(object->u.callback_filter)) { + zend_get_gc_buffer_add_fcc(gc_buffer, &object->u.callback_filter); } break; } diff --git a/ext/sqlite3/php_sqlite3_structs.h b/ext/sqlite3/php_sqlite3_structs.h index 15cb8a8cb303d..6d445d6642dbf 100644 --- a/ext/sqlite3/php_sqlite3_structs.h +++ b/ext/sqlite3/php_sqlite3_structs.h @@ -40,11 +40,6 @@ struct php_sqlite3_bound_param { zval parameter; }; -struct php_sqlite3_fci { - zend_fcall_info fci; - zend_fcall_info_cache fcc; -}; - /* Structure for SQLite function. */ typedef struct _php_sqlite3_func { struct _php_sqlite3_func *next; @@ -52,8 +47,9 @@ typedef struct _php_sqlite3_func { const char *func_name; int argc; - zval func, step, fini; - struct php_sqlite3_fci afunc, astep, afini; + zend_fcall_info_cache func; + zend_fcall_info_cache step; + zend_fcall_info_cache fini; } php_sqlite3_func; /* Structure for SQLite collation function */ @@ -61,8 +57,7 @@ typedef struct _php_sqlite3_collation { struct _php_sqlite3_collation *next; const char *collation_name; - zval cmp_func; - struct php_sqlite3_fci fci; + zend_fcall_info_cache cmp_func; } php_sqlite3_collation; /* Structure for SQLite Database object. */ @@ -71,7 +66,6 @@ typedef struct _php_sqlite3_db_object { sqlite3 *db; php_sqlite3_func *funcs; php_sqlite3_collation *collations; - zend_fcall_info authorizer_fci; zend_fcall_info_cache authorizer_fcc; bool exception; diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 1d00bc758ff0e..9ea9af2e2c445 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -155,7 +155,6 @@ PHP_METHOD(SQLite3, open) #endif db_obj->initialised = 1; - db_obj->authorizer_fci = empty_fcall_info; db_obj->authorizer_fcc = empty_fcall_info_cache; sqlite3_set_authorizer(db_obj->db, php_sqlite3_authorizer, db_obj); @@ -727,13 +726,13 @@ PHP_METHOD(SQLite3, querySingle) } /* }}} */ -static int sqlite3_do_callback(struct php_sqlite3_fci *fc, zval *cb, int argc, sqlite3_value **argv, sqlite3_context *context, int is_agg) /* {{{ */ +static int sqlite3_do_callback(zend_fcall_info_cache *fcc, uint32_t argc, sqlite3_value **argv, sqlite3_context *context, int is_agg) /* {{{ */ { zval *zargs = NULL; zval retval; - int i; - int ret; - int fake_argc; + uint32_t i; + uint32_t fake_argc; + zend_result ret = SUCCESS; php_sqlite3_agg_context *agg_context = NULL; if (is_agg) { @@ -742,14 +741,7 @@ static int sqlite3_do_callback(struct php_sqlite3_fci *fc, zval *cb, int argc, s fake_argc = argc + is_agg; - fc->fci.size = sizeof(fc->fci); - ZVAL_COPY_VALUE(&fc->fci.function_name, cb); - fc->fci.object = NULL; - fc->fci.retval = &retval; - fc->fci.param_count = fake_argc; - /* build up the params */ - if (fake_argc) { zargs = (zval *)safe_emalloc(fake_argc, sizeof(zval), 0); } @@ -791,24 +783,17 @@ static int sqlite3_do_callback(struct php_sqlite3_fci *fc, zval *cb, int argc, s } } - fc->fci.params = zargs; - - if ((ret = zend_call_function(&fc->fci, &fc->fcc)) == FAILURE) { - php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback"); - } + zend_call_known_fcc(fcc, &retval, fake_argc, zargs, /* named_params */ NULL); + /* clean up the params */ if (is_agg) { zval_ptr_dtor(&zargs[0]); + zval_ptr_dtor(&zargs[1]); } - - /* clean up the params */ if (fake_argc) { for (i = is_agg; i < argc + is_agg; i++) { zval_ptr_dtor(&zargs[i]); } - if (is_agg) { - zval_ptr_dtor(&zargs[1]); - } efree(zargs); } @@ -872,7 +857,7 @@ static void php_sqlite3_callback_func(sqlite3_context *context, int argc, sqlite { php_sqlite3_func *func = (php_sqlite3_func *)sqlite3_user_data(context); - sqlite3_do_callback(&func->afunc, &func->func, argc, argv, context, 0); + sqlite3_do_callback(&func->func, argc, argv, context, 0); } /* }}}*/ @@ -883,7 +868,7 @@ static void php_sqlite3_callback_step(sqlite3_context *context, int argc, sqlite agg_context->row_count++; - sqlite3_do_callback(&func->astep, &func->step, argc, argv, context, 1); + sqlite3_do_callback(&func->step, argc, argv, context, 1); } /* }}} */ @@ -894,7 +879,7 @@ static void php_sqlite3_callback_final(sqlite3_context *context) /* {{{ */ agg_context->row_count = 0; - sqlite3_do_callback(&func->afini, &func->fini, 0, NULL, context, 1); + sqlite3_do_callback(&func->fini, 0, NULL, context, 1); } /* }}} */ @@ -903,27 +888,17 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in php_sqlite3_collation *collation = (php_sqlite3_collation*)coll; zval zargs[2]; zval retval; - int ret; + int ret = 0; // Exception occurred on previous callback. Don't attempt to call function. if (EG(exception)) { return 0; } - collation->fci.fci.size = (sizeof(collation->fci.fci)); - ZVAL_COPY_VALUE(&collation->fci.fci.function_name, &collation->cmp_func); - collation->fci.fci.object = NULL; - collation->fci.fci.retval = &retval; - collation->fci.fci.param_count = 2; - ZVAL_STRINGL(&zargs[0], a, a_len); ZVAL_STRINGL(&zargs[1], b, b_len); - collation->fci.fci.params = zargs; - - if ((ret = zend_call_function(&collation->fci.fci, &collation->fci.fcc)) == FAILURE) { - php_error_docref(NULL, E_WARNING, "An error occurred while invoking the compare callback"); - } + zend_call_known_fcc(&collation->cmp_func, &retval, /* argc */ 2, zargs, /* named_params */ NULL); zval_ptr_dtor(&zargs[0]); zval_ptr_dtor(&zargs[1]); @@ -974,7 +949,7 @@ PHP_METHOD(SQLite3, createFunction) if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, flags | SQLITE_UTF8, func, php_sqlite3_callback_func, NULL, NULL) == SQLITE_OK) { func->func_name = estrdup(sql_func); - ZVAL_COPY(&func->func, &fci.function_name); + zend_fcc_dup(&func->func, &fcc); func->argc = sql_func_num_args; func->next = db_obj->funcs; @@ -1016,8 +991,8 @@ PHP_METHOD(SQLite3, createAggregate) if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, SQLITE_UTF8, func, NULL, php_sqlite3_callback_step, php_sqlite3_callback_final) == SQLITE_OK) { func->func_name = estrdup(sql_func); - ZVAL_COPY(&func->step, &step_fci.function_name); - ZVAL_COPY(&func->fini, &fini_fci.function_name); + zend_fcc_dup(&func->step, &step_fcc); + zend_fcc_dup(&func->fini, &fini_fcc); func->argc = sql_func_num_args; func->next = db_obj->funcs; @@ -1057,7 +1032,7 @@ PHP_METHOD(SQLite3, createCollation) if (sqlite3_create_collation(db_obj->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_callback_compare) == SQLITE_OK) { collation->collation_name = estrdup(collation_name); - ZVAL_COPY(&collation->cmp_func, &fci.function_name); + zend_fcc_dup(&collation->cmp_func, &fcc); collation->next = db_obj->collations; db_obj->collations = collation; @@ -1312,16 +1287,14 @@ PHP_METHOD(SQLite3, setAuthorizer) SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3) /* Clear previously set callback */ - if (ZEND_FCI_INITIALIZED(db_obj->authorizer_fci)) { - zval_ptr_dtor(&db_obj->authorizer_fci.function_name); - db_obj->authorizer_fci.size = 0; + if (ZEND_FCC_INITIALIZED(db_obj->authorizer_fcc)) { + zend_fcc_dtor(&db_obj->authorizer_fcc); } /* Only enable userland authorizer if argument is not NULL */ if (ZEND_FCI_INITIALIZED(fci)) { - db_obj->authorizer_fci = fci; - Z_ADDREF(db_obj->authorizer_fci.function_name); db_obj->authorizer_fcc = fcc; + zend_fcc_addref(&db_obj->authorizer_fcc); } RETURN_TRUE; @@ -2088,10 +2061,9 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c } php_sqlite3_db_object *db_obj = (php_sqlite3_db_object *)autharg; - zend_fcall_info *fci = &db_obj->authorizer_fci; /* fallback to access allowed if authorizer callback is not defined */ - if (fci->size == 0) { + if (!ZEND_FCC_INITIALIZED(db_obj->authorizer_fcc)) { return SQLITE_OK; } @@ -2125,13 +2097,10 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c ZVAL_STRING(&argv[4], arg4); } - fci->retval = &retval; - fci->param_count = 5; - fci->params = argv; - int authreturn = SQLITE_DENY; - if (zend_call_function(fci, &db_obj->authorizer_fcc) != SUCCESS || Z_ISUNDEF(retval)) { + zend_call_known_fcc(&db_obj->authorizer_fcc, &retval, /* argc */ 5, argv, /* named_params */ NULL); + if (Z_ISUNDEF(retval)) { php_sqlite3_error(db_obj, "An error occurred while invoking the authorizer callback"); } else { if (Z_TYPE(retval) != IS_LONG) { @@ -2146,8 +2115,13 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c } } - zend_fcall_info_args_clear(fci, 0); + /* Free local return and argument values */ zval_ptr_dtor(&retval); + zval_ptr_dtor(&argv[0]); + zval_ptr_dtor(&argv[1]); + zval_ptr_dtor(&argv[2]); + zval_ptr_dtor(&argv[3]); + zval_ptr_dtor(&argv[4]); return authreturn; } @@ -2189,8 +2163,8 @@ static void php_sqlite3_object_free_storage(zend_object *object) /* {{{ */ } /* Release function_name from authorizer */ - if (intern->authorizer_fci.size > 0) { - zval_ptr_dtor(&intern->authorizer_fci.function_name); + if (ZEND_FCC_INITIALIZED(intern->authorizer_fcc)) { + zend_fcc_dtor(&intern->authorizer_fcc); } while (intern->funcs) { @@ -2202,14 +2176,14 @@ static void php_sqlite3_object_free_storage(zend_object *object) /* {{{ */ efree((char*)func->func_name); - if (!Z_ISUNDEF(func->func)) { - zval_ptr_dtor(&func->func); + if (ZEND_FCC_INITIALIZED(func->func)) { + zend_fcc_dtor(&func->func); } - if (!Z_ISUNDEF(func->step)) { - zval_ptr_dtor(&func->step); + if (ZEND_FCC_INITIALIZED(func->step)) { + zend_fcc_dtor(&func->step); } - if (!Z_ISUNDEF(func->fini)) { - zval_ptr_dtor(&func->fini); + if (ZEND_FCC_INITIALIZED(func->fini)) { + zend_fcc_dtor(&func->fini); } efree(func); } @@ -2221,8 +2195,8 @@ static void php_sqlite3_object_free_storage(zend_object *object) /* {{{ */ sqlite3_create_collation(intern->db, collation->collation_name, SQLITE_UTF8, NULL, NULL); } efree((char*)collation->collation_name); - if (!Z_ISUNDEF(collation->cmp_func)) { - zval_ptr_dtor(&collation->cmp_func); + if (ZEND_FCC_INITIALIZED(collation->cmp_func)) { + zend_fcc_dtor(&collation->cmp_func); } efree(collation); }