Пример #1
0
static APC_HOTSPOT zend_reference* my_copy_reference(const zend_reference* src, apc_context_t *ctxt) {
	apc_pool* pool = ctxt->pool;
	zend_reference *dst;

	assert(src != NULL);

	if (ctxt->copied.nTableSize) {
		zend_reference *rc = zend_hash_index_find_ptr(&ctxt->copied, (uintptr_t) src);
		if (rc) {
			GC_REFCOUNT(rc)++;
			return rc;
		}
	}

    if (ctxt->copy == APC_COPY_IN) {
        dst = pool->palloc(pool, sizeof(zend_reference));
    } else {
        dst = emalloc(sizeof(zend_reference));
    }

    GC_REFCOUNT(dst) = 1;
    GC_TYPE_INFO(dst) = IS_REFERENCE;
	
    my_copy_zval(&dst->val, &src->val, ctxt);

	if (ctxt->copied.nTableSize) {
		zend_hash_index_update_ptr(&ctxt->copied, (uintptr_t) src, dst);
	}

    return dst;
}
Пример #2
0
/* Store all the possible watches the refcounted may refer to (for displaying & deleting by identifier) [collision] */
static phpdbg_watchpoint_t *phpdbg_create_refcounted_watchpoint(phpdbg_watchpoint_t *parent, zend_refcounted *ref) {
	phpdbg_watchpoint_t *watch = emalloc(sizeof(phpdbg_watchpoint_t));
	watch->flags = parent->flags;
	watch->parent = parent;
	watch->str = parent->str;
	++GC_REFCOUNT(parent->str);
	phpdbg_create_addr_watchpoint(&GC_REFCOUNT(ref), sizeof(uint32_t), watch);
	watch->type = WATCH_ON_REFCOUNTED;

	return watch;
}
Пример #3
0
static int phpdbg_create_recursive_ht_watch(phpdbg_watchpoint_t *watch) {
	zval *zv;
	zend_string *key;
	zend_long h;

	ZEND_ASSERT(watch->type == WATCH_ON_HASHTABLE);

	ZEND_HASH_FOREACH_KEY_VAL(HT_WATCH_HT(watch), h, key, zv) {
		phpdbg_watchpoint_t *new_watch = emalloc(sizeof(phpdbg_watchpoint_t));

		new_watch->flags = PHPDBG_WATCH_RECURSIVE;
		new_watch->parent = watch;
		new_watch->parent_container = HT_WATCH_HT(watch);

		if (key) {
			new_watch->name_in_parent = key;
			++GC_REFCOUNT(key);
		} else {
			new_watch->name_in_parent = strpprintf(0, ZEND_LONG_FMT, h);
		}

		new_watch->str = strpprintf(0, "%.*s%s%s%s", (int) ZSTR_LEN(watch->str) - 2, ZSTR_VAL(watch->str), (watch->flags & PHPDBG_WATCH_ARRAY) ? "[" : "->", phpdbg_get_property_key(ZSTR_VAL(new_watch->name_in_parent)), (watch->flags & PHPDBG_WATCH_ARRAY) ? "]" : "");

		while (Z_TYPE_P(zv) == IS_INDIRECT) {
			zv = Z_INDIRECT_P(zv);
		}

		phpdbg_create_zval_watchpoint(zv, new_watch);
		new_watch = phpdbg_create_watchpoint(new_watch);
		phpdbg_create_recursive_zval_watch(new_watch);
	} ZEND_HASH_FOREACH_END();
Пример #4
0
void zend_exception_set_previous(zend_object *exception, zend_object *add_previous) /* {{{ */
{
    zval *previous, *ancestor, *ex;
	zval  pv, zv, rv;
	zend_class_entry *base_ce;

	if (exception == add_previous || !add_previous || !exception) {
		return;
	}
	ZVAL_OBJ(&pv, add_previous);
	if (!instanceof_function(Z_OBJCE(pv), zend_ce_throwable)) {
		zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");
		return;
	}
	ZVAL_OBJ(&zv, exception);
	ex = &zv;
	do {
		ancestor = zend_read_property(i_get_exception_base(&pv), &pv, "previous", sizeof("previous")-1, 1, &rv);
		while (Z_TYPE_P(ancestor) == IS_OBJECT) {
			if (Z_OBJ_P(ancestor) == Z_OBJ_P(ex)) {
				OBJ_RELEASE(add_previous);
				return;
			}
			ancestor = zend_read_property(i_get_exception_base(ancestor), ancestor, "previous", sizeof("previous")-1, 1, &rv);
		}
		base_ce = i_get_exception_base(ex);
		previous = zend_read_property(base_ce, ex, "previous", sizeof("previous")-1, 1, &rv);
		if (Z_TYPE_P(previous) == IS_NULL) {
			zend_update_property(base_ce, ex, "previous", sizeof("previous")-1, &pv);
			GC_REFCOUNT(add_previous)--;
			return;
		}
		ex = previous;
	} while (Z_OBJ_P(ex) != add_previous);
}
Пример #5
0
/* {{{ */
zend_string* pthreads_globals_string(zend_string *str) {
	/*
	 This is sourcery of the darkest kind ...
	
	 We don't need all threads to have a copy of every string used as the name for a threaded objects property.
	 
	 In addition, Zend has troubles with persistent strings in non-persistent hashes and vice versa, to avoid these
	 we have a global table of strings that is used when writing to threaded objects properties, this table is detroyed
	 on shutdown of the process, so will show as leaked, but we don't care, we want stable !
	*/
	zend_string* p = NULL;
	if (pthreads_globals_lock()) {
		if (!(p = zend_hash_find_ptr(&PTHREADS_G(gstrings), str)) && 
			(p = (zend_string*) malloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(ZSTR_LEN(str)))))) {
			memset(p, 0, sizeof(zend_string));

			GC_REFCOUNT(p) = 2;
			GC_TYPE_INFO(p) = IS_STR_PERSISTENT;

			memcpy(ZSTR_VAL(p), ZSTR_VAL(str), ZSTR_LEN(str));
			p->len = ZSTR_LEN(str);
			ZSTR_VAL(p)[ZSTR_LEN(p)] = '\0';
			zend_string_forget_hash_val(p);
			zend_hash_update_ptr(
				&PTHREADS_G(gstrings), p, p);
		}

		pthreads_globals_unlock();
	}

	return p;
} /* }}} */
Пример #6
0
ZEND_API void zend_iterator_dtor(zend_object_iterator *iter)
{
	if (--GC_REFCOUNT(&iter->std) > 0) {
		return;
	}

	zend_objects_store_del(&iter->std);
}
static zend_always_inline zend_string *zend_clone_str(zend_string *str)
{
	zend_string *ret;

	if (EXPECTED(IS_INTERNED(str))) {
		ret = str;
	} else if (GC_REFCOUNT(str) <= 1 || (ret = accel_xlat_get(str)) == NULL) {
		ret = zend_string_dup(str, 0);
		GC_FLAGS(ret) = GC_FLAGS(str);
		if (GC_REFCOUNT(str) > 1) {
			accel_xlat_set(str, ret);
		}
	} else {
		GC_REFCOUNT(ret)++;
	}
	return ret;
}
Пример #8
0
static void ZEND_FASTCALL zend_string_destroy(zend_string *str)
{
	CHECK_ZVAL_STRING(str);
	ZEND_ASSERT(!ZSTR_IS_INTERNED(str));
	ZEND_ASSERT(GC_REFCOUNT(str) == 0);
	ZEND_ASSERT(!(GC_FLAGS(str) & IS_STR_PERSISTENT));
	efree(str);
}
Пример #9
0
void init_executor(void) /* {{{ */
{
	zend_init_fpu();

	ZVAL_NULL(&EG(uninitialized_zval));
	/* trick to make uninitialized_zval never be modified, passed by ref, etc. */
	ZVAL_NULL(&EG(error_zval));
/* destroys stack frame, therefore makes core dumps worthless */
#if 0&&ZEND_DEBUG
	original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
#endif

	EG(symtable_cache_ptr) = EG(symtable_cache) - 1;
	EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1;
	EG(no_extensions) = 0;

	EG(function_table) = CG(function_table);
	EG(class_table) = CG(class_table);

	EG(in_autoload) = NULL;
	EG(autoload_func) = NULL;
	EG(error_handling) = EH_NORMAL;

	zend_vm_stack_init();

	zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0);
	GC_REFCOUNT(&EG(symbol_table)) = 1;
	GC_TYPE_INFO(&EG(symbol_table)) = IS_ARRAY;
	EG(valid_symbol_table) = 1;

	zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator);

	zend_hash_init(&EG(included_files), 8, NULL, NULL, 0);

	EG(ticks_count) = 0;

	ZVAL_UNDEF(&EG(user_error_handler));

	EG(current_execute_data) = NULL;

	zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int));
	zend_stack_init(&EG(user_error_handlers), sizeof(zval));
	zend_stack_init(&EG(user_exception_handlers), sizeof(zval));

	zend_objects_store_init(&EG(objects_store), 1024);

	EG(full_tables_cleanup) = 0;
#ifdef ZEND_WIN32
	EG(timed_out) = 0;
#endif

	EG(exception) = NULL;
	EG(prev_exception) = NULL;

	EG(scope) = NULL;

	EG(active) = 1;
}
Пример #10
0
ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ */
{
	/*	Make sure we hold a reference count during the destructor call
		otherwise, when the destructor ends the storage might be freed
		when the refcount reaches 0 a second time
	 */
	if (EG(objects_store).object_buckets &&
	    IS_OBJ_VALID(EG(objects_store).object_buckets[object->handle])) {
		if (GC_REFCOUNT(object) == 0) {
			if (!(GC_FLAGS(object) & IS_OBJ_DESTRUCTOR_CALLED)) {
				GC_FLAGS(object) |= IS_OBJ_DESTRUCTOR_CALLED;

				if (object->handlers->dtor_obj
				 && (object->handlers->dtor_obj != zend_objects_destroy_object
				  || object->ce->destructor)) {
					GC_ADDREF(object);
					object->handlers->dtor_obj(object);
					GC_DELREF(object);
				}
			}

			if (GC_REFCOUNT(object) == 0) {
				uint32_t handle = object->handle;
				void *ptr;

				EG(objects_store).object_buckets[handle] = SET_OBJ_INVALID(object);
				if (!(GC_FLAGS(object) & IS_OBJ_FREE_CALLED)) {
					GC_FLAGS(object) |= IS_OBJ_FREE_CALLED;
					if (object->handlers->free_obj) {
						GC_ADDREF(object);
						object->handlers->free_obj(object);
						GC_DELREF(object);
					}
				}
				ptr = ((char*)object) - object->handlers->offset;
				GC_REMOVE_FROM_BUFFER(object);
				efree(ptr);
				ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle);
			}
		} else {
			GC_DELREF(object);
		}
	}
}
Пример #11
0
ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ */
{
	ZEND_ASSERT(GC_REFCOUNT(object) == 0);

	/* GC might have released this object already. */
	if (UNEXPECTED(GC_TYPE(object) == IS_NULL)) {
		return;
	}

	/*	Make sure we hold a reference count during the destructor call
		otherwise, when the destructor ends the storage might be freed
		when the refcount reaches 0 a second time
	 */
	if (!(OBJ_FLAGS(object) & IS_OBJ_DESTRUCTOR_CALLED)) {
		GC_ADD_FLAGS(object, IS_OBJ_DESTRUCTOR_CALLED);

		if (object->handlers->dtor_obj != zend_objects_destroy_object
				|| object->ce->destructor) {
			GC_SET_REFCOUNT(object, 1);
			object->handlers->dtor_obj(object);
			GC_DELREF(object);
		}
	}

	if (GC_REFCOUNT(object) == 0) {
		uint32_t handle = object->handle;
		void *ptr;

		ZEND_ASSERT(EG(objects_store).object_buckets != NULL);
		ZEND_ASSERT(IS_OBJ_VALID(EG(objects_store).object_buckets[handle]));
		EG(objects_store).object_buckets[handle] = SET_OBJ_INVALID(object);
		if (!(OBJ_FLAGS(object) & IS_OBJ_FREE_CALLED)) {
			GC_ADD_FLAGS(object, IS_OBJ_FREE_CALLED);
			GC_SET_REFCOUNT(object, 1);
			object->handlers->free_obj(object);
		}
		ptr = ((char*)object) - object->handlers->offset;
		GC_REMOVE_FROM_BUFFER(object);
		efree(ptr);
		ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle);
	}
}
Пример #12
0
static void gc_trace_ref(zend_refcounted *ref) {
	if (GC_TYPE(ref) == IS_OBJECT) {
		zend_object *obj = (zend_object *) ref;
		fprintf(stderr, "[%p] rc=%d addr=%d %s object(%s)#%d ",
			ref, GC_REFCOUNT(ref), GC_REF_ADDRESS(ref),
			gc_color_name(GC_REF_COLOR(ref)),
			obj->ce->name->val, obj->handle);
	} else if (GC_TYPE(ref) == IS_ARRAY) {
		zend_array *arr = (zend_array *) ref;
		fprintf(stderr, "[%p] rc=%d addr=%d %s array(%d) ",
			ref, GC_REFCOUNT(ref), GC_REF_ADDRESS(ref),
			gc_color_name(GC_REF_COLOR(ref)),
			zend_hash_num_elements(arr));
	} else {
		fprintf(stderr, "[%p] rc=%d addr=%d %s %s ",
			ref, GC_REFCOUNT(ref), GC_REF_ADDRESS(ref),
			gc_color_name(GC_REF_COLOR(ref)),
			zend_get_type_by_const(GC_TYPE(ref)));
	}
}
Пример #13
0
static void zend_persist_zval_const(zval *z)
{
	zend_uchar flags;
	void *new_ptr;

	switch (Z_TYPE_P(z)) {
		case IS_STRING:
		case IS_CONSTANT:
			flags = Z_GC_FLAGS_P(z) & ~ (IS_STR_PERSISTENT | IS_STR_INTERNED | IS_STR_PERMANENT);
			zend_accel_memdup_interned_string(Z_STR_P(z));
			Z_GC_FLAGS_P(z) |= flags;
			Z_TYPE_FLAGS_P(z) &= ~(IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
			break;
		case IS_ARRAY:
			new_ptr = zend_shared_alloc_get_xlat_entry(Z_ARR_P(z));
			if (new_ptr) {
				Z_ARR_P(z) = new_ptr;
				Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
			} else {
				if (Z_IMMUTABLE_P(z)) {
					Z_ARR_P(z) = zend_accel_memdup(Z_ARR_P(z), sizeof(zend_array));
					zend_hash_persist_immutable(Z_ARRVAL_P(z));
				} else {
					GC_REMOVE_FROM_BUFFER(Z_ARR_P(z));
					zend_accel_store(Z_ARR_P(z), sizeof(zend_array));
					zend_hash_persist(Z_ARRVAL_P(z), zend_persist_zval);
					/* make immutable array */
					Z_TYPE_FLAGS_P(z) = IS_TYPE_IMMUTABLE;
					GC_REFCOUNT(Z_COUNTED_P(z)) = 2;
					Z_ARRVAL_P(z)->u.flags &= ~HASH_FLAG_APPLY_PROTECTION;
				}
			}
			break;
		case IS_REFERENCE:
			new_ptr = zend_shared_alloc_get_xlat_entry(Z_REF_P(z));
			if (new_ptr) {
				Z_REF_P(z) = new_ptr;
			} else {
				zend_accel_store(Z_REF_P(z), sizeof(zend_reference));
				zend_persist_zval(Z_REFVAL_P(z));
			}
			break;
		case IS_CONSTANT_AST:
			new_ptr = zend_shared_alloc_get_xlat_entry(Z_AST_P(z));
			if (new_ptr) {
				Z_AST_P(z) = new_ptr;
			} else {
				zend_accel_store(Z_AST_P(z), sizeof(zend_ast_ref));
				Z_ASTVAL_P(z) = zend_persist_ast(Z_ASTVAL_P(z));
			}
			break;
	}
}
Пример #14
0
SKYRAY_METHOD(ProcessWatcher, getProcess)
{
    if (zend_parse_parameters_none() == FAILURE) {
        return;
    }

    skyray_process_watcher_t *intern = skyray_process_watcher_from_obj(Z_OBJ_P(getThis()));

    GC_REFCOUNT(&intern->process->std) ++;

    RETURN_OBJ(&intern->process->std)
}
Пример #15
0
static void php_set_default_dir(zend_resource *res)
{
	if (DIRG(default_dir)) {
		zend_list_delete(DIRG(default_dir));
	}

	if (res) {
		GC_REFCOUNT(res)++;
	}

	DIRG(default_dir) = res;
}
Пример #16
0
static promise_resolve_context_t * promise_resolve_context_create(skyray_promise_t *self, zval *callback, skyray_promise_t *late)
{
    promise_resolve_context_t *context = emalloc(sizeof(promise_resolve_context_t));

    GC_REFCOUNT((zend_refcounted *)context) = 1;

    // if context->self is NULL, this context is created for done()
    context->self = self;
    if (self) {
        GC_REFCOUNT((zend_refcounted *)&self->std) ++;
    }

    ZVAL_NULL(&context->callback);

    context->late = late;

    if (callback) {
        ZVAL_COPY(&context->callback, callback);
    }

    return context;
}
Пример #17
0
SKYRAY_METHOD(deferred, promise)
{
    if (zend_parse_parameters_none() == FAILURE) {
        return;
    }

    skyray_deferred_t *intern = skyray_deferred_from_obj(Z_OBJ_P(getThis()));
    if (!intern->promise) {
        intern->promise = skyray_deferred_create_promise();
    }

    GC_REFCOUNT(intern->promise) ++;
    RETURN_OBJ(intern->promise);
}
Пример #18
0
static phpdbg_watchpoint_t *phpdbg_create_reference_watch(phpdbg_watchpoint_t *watch) {
	phpdbg_watchpoint_t *ref = emalloc(sizeof(phpdbg_watchpoint_t));
	watch->reference = ref;
	ref->flags = watch->flags;
	ref->str = watch->str;
	++GC_REFCOUNT(ref->str);
	ref->parent = watch;
	ref->parent_container = NULL;
	phpdbg_create_zval_watchpoint(Z_REFVAL_P(watch->addr.zv), ref);

	phpdbg_create_watchpoint(ref);

	return ref;
}
Пример #19
0
static void promise_resolve_context_free(zval *value)
{
    promise_resolve_context_t *context = Z_PTR_P(value);

    if (--GC_REFCOUNT(context) != 0) {
        return;
    }

    if (context->self) {
        zend_object_release(&context->self->std);
    }

    zval_ptr_dtor(&context->callback);
    efree(context);
}
Пример #20
0
static void zend_accel_destroy_zend_function(zval *zv)
{
	zend_function *function = Z_PTR_P(zv);

	if (function->type == ZEND_USER_FUNCTION) {
		if (function->op_array.static_variables) {
			if (!(GC_FLAGS(function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
				if (--GC_REFCOUNT(function->op_array.static_variables) == 0) {
					FREE_HASHTABLE(function->op_array.static_variables);
				}
			}
			function->op_array.static_variables = NULL;
		}
	}

	destroy_zend_function(function);
}
Пример #21
0
PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
{
	php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
	zval *tmp;

	if (stm == NULL)
		return NULL;

	memset(stm, 0, sizeof(*stm));
	stm->engine_thread = GetCurrentThreadId();
	stm->lpVtbl = &php_istream_vtbl;
	stm->refcount = 1;
	stm->stream = stream;

	GC_REFCOUNT(stream->res)++;
	tmp = zend_list_insert(stm, le_istream);
	stm->res = Z_RES_P(tmp);

	return (IStream*)stm;
}
Пример #22
0
void stream_client_do_connect_blocking(
        skyray_stream_client_t *self, zend_object *protocol_obj,
        zend_string *host, zend_long port, zval *return_value)
{
    int fd = stream_client_do_connect(host->val, port);

    if (fd < 0) {
        return;
    }

    zval zstream;

    object_init_ex(&zstream, skyray_ce_Stream);
    zend_object *stream = Z_OBJ_P(&zstream);

    skyray_stream_t * stream_intern = skyray_stream_from_obj(stream);
    skyray_stream_init_blocking(stream_intern, SR_TCP, fd, protocol_obj);

    skyray_stream_on_opened(stream_intern, SR_READABLE | SR_WRITABLE);

    if (!self->protocol_creator) {
        ZVAL_COPY(return_value, &zstream);
        return;
    }

    zend_string *buffer;

    ++GC_REFCOUNT(protocol_obj); //preventing protocol instance be free'd after connection closed.
    while((buffer = skyray_stream_read(stream_intern, 0))) {
        if (buffer->len == 0) {
            zend_string_free(buffer);
            break;
        }
        skyray_stream_on_data(stream_intern, buffer);
        zend_string_free(buffer);
    }

    RETURN_OBJ(protocol_obj);
}
Пример #23
0
int zephir_call_func_aparams_fast(zval *return_value_ptr, zephir_fcall_cache_entry **cache_entry, zend_uint param_count, zval *params[])
{
	uint32_t i;
	zend_class_entry *calling_scope = NULL;
	zend_execute_data *call, dummy_execute_data;
	zval retval_local;
	zval *retval_ptr = return_value_ptr ? return_value_ptr : &retval_local;
	zend_class_entry *orig_scope;
	zend_function *func;

	if (return_value_ptr) {
		zval_ptr_dtor(return_value_ptr);
		ZVAL_UNDEF(return_value_ptr);
	} else {
		ZVAL_UNDEF(&retval_local);
	}

	if (!EG(active)) {
		return FAILURE; /* executor is already inactive */
	}

	if (EG(exception)) {
		return FAILURE; /* we would result in an instable executor otherwise */
	}

	orig_scope = EG(scope);

	/* Initialize execute_data */
	if (!EG(current_execute_data)) {
		/* This only happens when we're called outside any execute()'s
		 * It shouldn't be strictly necessary to NULL execute_data out,
		 * but it may make bugs easier to spot
		 */
		memset(&dummy_execute_data, 0, sizeof(zend_execute_data));
		EG(current_execute_data) = &dummy_execute_data;
	} else if (EG(current_execute_data)->func &&
	           ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
	           EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL &&
	           EG(current_execute_data)->opline->opcode != ZEND_DO_ICALL &&
	           EG(current_execute_data)->opline->opcode != ZEND_DO_UCALL &&
	           EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL_BY_NAME) {
		/* Insert fake frame in case of include or magic calls */
		dummy_execute_data = *EG(current_execute_data);
		dummy_execute_data.prev_execute_data = EG(current_execute_data);
		dummy_execute_data.call = NULL;
		dummy_execute_data.opline = NULL;
		dummy_execute_data.func = NULL;
		EG(current_execute_data) = &dummy_execute_data;
	}

#ifndef ZEPHIR_RELEASE
	func = (*cache_entry)->f;
	++(*cache_entry)->times;
#else
	func = *cache_entry;
#endif

	calling_scope = NULL;
	call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION, func, param_count, NULL, NULL);

	for (i = 0; i < param_count; i++) {
		zval *param;
		zval *arg = params[i];

		if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
			if (!Z_ISREF_P(arg)) {
				/*if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
					if (i) {
						// hack to clean up the stack
						ZEND_CALL_NUM_ARGS(call) = i;
						zend_vm_stack_free_args(call);
					}
					zend_vm_stack_free_call_frame(call);

					zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
						i+1,
						func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
						func->common.scope ? "::" : "",
						ZSTR_VAL(func->common.function_name));
					if (EG(current_execute_data) == &dummy_execute_data) {
						EG(current_execute_data) = dummy_execute_data.prev_execute_data;
					}
					return FAILURE;
				}*/

				ZVAL_NEW_REF(arg, arg);
			}
			Z_ADDREF_P(arg);
		} else {
			if (Z_ISREF_P(arg) &&
			    !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
				/* don't separate references for __call */
				arg = Z_REFVAL_P(arg);
			}
			if (Z_OPT_REFCOUNTED_P(arg)) {
				Z_ADDREF_P(arg);
			}
		}
		param = ZEND_CALL_ARG(call, i+1);
		ZVAL_COPY_VALUE(param, arg);
	}

	EG(scope) = calling_scope;
	Z_OBJ(call->This) = NULL;

	if (func->type == ZEND_USER_FUNCTION) {
		int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
		EG(scope) = func->common.scope;
		call->symbol_table = NULL;
		if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
			ZEND_ASSERT(GC_TYPE((zend_object*)func->op_array.prototype) == IS_OBJECT);
			GC_REFCOUNT((zend_object*)func->op_array.prototype)++;
			ZEND_ADD_CALL_FLAG(call, ZEND_CALL_CLOSURE);
		}
		if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) {
			zend_init_execute_data(call, &func->op_array, retval_ptr);
			zend_execute_ex(call);
		} else {
			zend_generator_create_zval(call, &func->op_array, retval_ptr);
		}
		if (call_via_handler) {
			/* We must re-initialize function again */
			*cache_entry = NULL;
		}
	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
		int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
		if (func->common.scope) {
			EG(scope) = func->common.scope;
		}
		call->prev_execute_data = EG(current_execute_data);
		call->return_value = NULL; /* this is not a constructor call */
		EG(current_execute_data) = call;
		if (EXPECTED(zend_execute_internal == NULL)) {
			/* saves one function call if zend_execute_internal is not used */
			func->internal_function.handler(call, retval_ptr);
		} else {
			zend_execute_internal(call, retval_ptr);
		}
		EG(current_execute_data) = call->prev_execute_data;
		zend_vm_stack_free_args(call);

		/*  We shouldn't fix bad extensions here,
			because it can break proper ones (Bug #34045)
		if (!EX(function_state).function->common.return_reference)
		{
			INIT_PZVAL(f->retval);
		}*/
		if (EG(exception)) {
			zval_ptr_dtor(retval_ptr);
			ZVAL_UNDEF(retval_ptr);
		}

		if (call_via_handler) {
			/* We must re-initialize function again */
			*cache_entry = NULL;
		}
	} else { /* ZEND_OVERLOADED_FUNCTION */
		ZVAL_NULL(retval_ptr);

		zend_throw_error(NULL, "Cannot call overloaded function for non-object");
		zend_vm_stack_free_args(call);

		if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
			zend_string_release(func->common.function_name);
		}
		efree(func);

		if (EG(exception)) {
			zval_ptr_dtor(retval_ptr);
			ZVAL_UNDEF(retval_ptr);
		}
	}

	EG(scope) = orig_scope;
	zend_vm_stack_free_call_frame(call);

	if (EG(current_execute_data) == &dummy_execute_data) {
		EG(current_execute_data) = dummy_execute_data.prev_execute_data;
	}

	if (EG(exception)) {
		zend_throw_exception_internal(NULL);
	}
	return SUCCESS;
}
Пример #24
0
/* {{{ php_oci_lob_create()
 Create LOB descriptor and allocate all the resources needed */
php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, zend_long type)
{
	php_oci_descriptor *descriptor;
	sword errstatus;

	switch (type) {
		case OCI_DTYPE_FILE:
		case OCI_DTYPE_LOB:
		case OCI_DTYPE_ROWID:
			/* these three are allowed */
			break;
		default:
			php_error_docref(NULL, E_WARNING, "Unknown descriptor type %pd", type);
			return NULL;
			break;
	}

	descriptor = ecalloc(1, sizeof(php_oci_descriptor));
	descriptor->type = (ub4) type;
	descriptor->connection = connection;
	++GC_REFCOUNT(descriptor->connection->id);

	PHP_OCI_CALL_RETURN(errstatus, OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));

	if (errstatus != OCI_SUCCESS) {
		OCI_G(errcode) = php_oci_error(OCI_G(err), errstatus);
		PHP_OCI_HANDLE_ERROR(connection, OCI_G(errcode));
		efree(descriptor);
		return NULL;
	} else {
		OCI_G(errcode) = 0; /* retain backwards compat with OCI8 1.4 */
	}

	PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
	
	descriptor->lob_current_position = 0;
	descriptor->lob_size = -1;				/* we should set it to -1 to know, that it's just not initialized */
	descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED;				/* buffering is off by default */
	descriptor->charset_form = SQLCS_IMPLICIT;	/* default value */
	descriptor->charset_id = connection->charset;
	descriptor->is_open = 0;
	descriptor->chunk_size = 0;

	if (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE) {
		/* add Lobs & Files to hash. we'll flush them at the end */
		if (!connection->descriptors) {
			ALLOC_HASHTABLE(connection->descriptors);
			zend_hash_init(connection->descriptors, 0, NULL, php_oci_descriptor_flush_hash_dtor, 0);
			connection->descriptor_count = 0;
		}
		
		descriptor->index = (connection->descriptor_count)++;
		if (connection->descriptor_count == LONG_MAX) {
			php_error_docref(NULL, E_WARNING, "Internal descriptor counter has reached limit");
			php_oci_connection_descriptors_free(connection);
			return NULL;
		}

		zend_hash_index_update_ptr(connection->descriptors, descriptor->index, &descriptor);
	}
	return descriptor;

}
Пример #25
0
static void context_copy_func(void *pElement)
{
    promise_resolve_context_t *context = Z_PTR_P((zval *)pElement);
    GC_REFCOUNT((zend_refcounted *)context) ++;
}
Пример #26
0
/* {{{ php_dba_open
 */
static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
	zval *args = NULL;
	int ac = ZEND_NUM_ARGS();
	dba_mode_t modenr;
	dba_info *info, *other;
	dba_handler *hptr;
	char *key = NULL, *error = NULL;
	int keylen = 0;
	int i;
	int lock_mode, lock_flag, lock_dbf = 0;
	char *file_mode;
	char mode[4], *pmode, *lock_file_mode = NULL;
	int persistent_flag = persistent ? STREAM_OPEN_PERSISTENT : 0;
	zend_string *opened_path = NULL;
	char *lock_name;

	if (ac < 2) {
		WRONG_PARAM_COUNT;
	}

	/* we pass additional args to the respective handler */
	args = safe_emalloc(ac, sizeof(zval), 0);
	if (zend_get_parameters_array_ex(ac, args) != SUCCESS) {
		efree(args);
		WRONG_PARAM_COUNT;
	}

	/* we only take string arguments */
	for (i = 0; i < ac; i++) {
		if (Z_TYPE(args[i]) != IS_STRING) {
			convert_to_string_ex(&args[i]);
		} else if (Z_REFCOUNTED(args[i])) {
			Z_ADDREF(args[i]);
		}
		keylen += Z_STRLEN(args[i]);
	}

	if (persistent) {
		zend_resource *le;

		/* calculate hash */
		key = safe_emalloc(keylen, 1, 1);
		key[keylen] = '\0';
		keylen = 0;

		for(i = 0; i < ac; i++) {
			memcpy(key+keylen, Z_STRVAL(args[i]), Z_STRLEN(args[i]));
			keylen += Z_STRLEN(args[i]);
		}

		/* try to find if we already have this link in our persistent list */
		if ((le = zend_hash_str_find_ptr(&EG(persistent_list), key, keylen)) != NULL) {
			FREENOW;

			if (le->type != le_pdb) {
				RETURN_FALSE;
			}

			info = (dba_info *)le->ptr;

			GC_REFCOUNT(le)++;
			RETURN_RES(le);
			return;
		}
	}

	if (ac==2) {
		hptr = DBA_G(default_hptr);
		if (!hptr) {
			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No default handler selected");
			FREENOW;
			RETURN_FALSE;
		}
	} else {
		for (hptr = handler; hptr->name && strcasecmp(hptr->name, Z_STRVAL(args[2])); hptr++);
	}

	if (!hptr->name) {
		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "No such handler: %s", Z_STRVAL(args[2]));
		FREENOW;
		RETURN_FALSE;
	}

	/* Check mode: [rwnc][fl]?t?
	 * r: Read
	 * w: Write
	 * n: Create/Truncate
	 * c: Create
	 *
	 * d: force lock on database file
	 * l: force lock on lck file
	 * -: ignore locking
	 *
	 * t: test open database, warning if locked
	 */
	strlcpy(mode, Z_STRVAL(args[1]), sizeof(mode));
	pmode = &mode[0];
	if (pmode[0] && (pmode[1]=='d' || pmode[1]=='l' || pmode[1]=='-')) { /* force lock on db file or lck file or disable locking */
		switch (pmode[1]) {
		case 'd':
			lock_dbf = 1;
			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
				lock_flag = (hptr->flags & DBA_LOCK_ALL);
				break;
			}
			/* no break */
		case 'l':
			lock_flag = DBA_LOCK_ALL;
			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_NOTICE, "Handler %s does locking internally", hptr->name);
			}
			break;
		default:
		case '-':
			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Locking cannot be disabled for handler %s", hptr->name);
				FREENOW;
				RETURN_FALSE;
			}
			lock_flag = 0;
			break;
		}
	} else {
		lock_flag = (hptr->flags&DBA_LOCK_ALL);
		lock_dbf = 1;
	}
	switch (*pmode++) {
		case 'r':
			modenr = DBA_READER;
			lock_mode = (lock_flag & DBA_LOCK_READER) ? LOCK_SH : 0;
			file_mode = "r";
			break;
		case 'w':
			modenr = DBA_WRITER;
			lock_mode = (lock_flag & DBA_LOCK_WRITER) ? LOCK_EX : 0;
			file_mode = "r+b";
			break;
		case 'c':
			modenr = DBA_CREAT;
			lock_mode = (lock_flag & DBA_LOCK_CREAT) ? LOCK_EX : 0;
			if (lock_mode) {
				if (lock_dbf) {
					/* the create/append check will be done on the lock
					 * when the lib opens the file it is already created
					 */
					file_mode = "r+b";       /* read & write, seek 0 */
					lock_file_mode = "a+b";  /* append */
				} else {
					file_mode = "a+b";       /* append */
					lock_file_mode = "w+b";  /* create/truncate */
				}
			} else {
				file_mode = "a+b";
			}
			/* In case of the 'a+b' append mode, the handler is responsible
			 * to handle any rewind problems (see flatfile handler).
			 */
			break;
		case 'n':
			modenr = DBA_TRUNC;
			lock_mode = (lock_flag & DBA_LOCK_TRUNC) ? LOCK_EX : 0;
			file_mode = "w+b";
			break;
		default:
			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
			FREENOW;
			RETURN_FALSE;
	}
	if (!lock_file_mode) {
		lock_file_mode = file_mode;
	}
	if (*pmode=='d' || *pmode=='l' || *pmode=='-') {
		pmode++; /* done already - skip here */
	}
	if (*pmode=='t') {
		pmode++;
		if (!lock_flag) {
			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "You cannot combine modifiers - (no lock) and t (test lock)");
			FREENOW;
			RETURN_FALSE;
		}
		if (!lock_mode) {
			if ((hptr->flags & DBA_LOCK_ALL) == 0) {
				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s uses its own locking which doesn't support mode modifier t (test lock)", hptr->name);
				FREENOW;
				RETURN_FALSE;
			} else {
				php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Handler %s doesn't uses locking for this mode which makes modifier t (test lock) obsolete", hptr->name);
				FREENOW;
				RETURN_FALSE;
			}
		} else {
			lock_mode |= LOCK_NB; /* test =: non blocking */
		}
	}
	if (*pmode) {
		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Illegal DBA mode");
		FREENOW;
		RETURN_FALSE;
	}

	info = pemalloc(sizeof(dba_info), persistent);
	memset(info, 0, sizeof(dba_info));
	info->path = pestrdup(Z_STRVAL(args[0]), persistent);
	info->mode = modenr;
	info->argc = ac - 3;
	info->argv = args + 3;
	info->flags = (hptr->flags & ~DBA_LOCK_ALL) | (lock_flag & DBA_LOCK_ALL) | (persistent ? DBA_PERSISTENT : 0);
	info->lock.mode = lock_mode;

	/* if any open call is a locking call:
	 * check if we already habe a locking call open that should block this call
	 * the problem is some systems would allow read during write
	 */
	if (hptr->flags & DBA_LOCK_ALL) {
		if ((other = php_dba_find(info->path)) != NULL) {
			if (   ( (lock_mode&LOCK_EX)        && (other->lock.mode&(LOCK_EX|LOCK_SH)) )
			    || ( (other->lock.mode&LOCK_EX) && (lock_mode&(LOCK_EX|LOCK_SH))        )
			   ) {
				error = "Unable to establish lock (database file already open)"; /* force failure exit */
			}
		}
	}

	if (!error && lock_mode) {
		if (lock_dbf) {
			lock_name = Z_STRVAL(args[0]);
		} else {
			spprintf(&lock_name, 0, "%s.lck", info->path);
			if (!strcmp(file_mode, "r")) {
				/* when in read only mode try to use existing .lck file first */
				/* do not log errors for .lck file while in read ony mode on .lck file */
				lock_file_mode = "rb";
				info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, &opened_path);
			}
			if (!info->lock.fp) {
				/* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */
				lock_file_mode = "a+b";
			} else {
				if (opened_path) {
					info->lock.name = pestrndup(opened_path->val, opened_path->len, persistent);
					zend_string_release(opened_path);
				}
			}
		}
		if (!info->lock.fp) {
			info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path);
			if (info->lock.fp) {
				if (lock_dbf) {
					/* replace the path info with the real path of the opened file */
					pefree(info->path, persistent);
					info->path = pestrndup(opened_path->val, opened_path->len, persistent);
				}
				/* now store the name of the lock */
				info->lock.name = pestrndup(opened_path->val, opened_path->len, persistent);
				zend_string_release(opened_path);
			}
		}
		if (!lock_dbf) {
			efree(lock_name);
		}
		if (!info->lock.fp) {
			dba_close(info);
			/* stream operation already wrote an error message */
			FREENOW;
			RETURN_FALSE;
		}
		if (!php_stream_supports_lock(info->lock.fp)) {
			error = "Stream does not support locking";
		}
		if (php_stream_lock(info->lock.fp, lock_mode)) {
			error = "Unable to establish lock"; /* force failure exit */
		}
	}

	/* centralised open stream for builtin */
	if (!error && (hptr->flags&DBA_STREAM_OPEN)==DBA_STREAM_OPEN) {
		if (info->lock.fp && lock_dbf) {
			info->fp = info->lock.fp; /* use the same stream for locking and database access */
		} else {
			info->fp = php_stream_open_wrapper(info->path, file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL);
		}
		if (!info->fp) {
			dba_close(info);
			/* stream operation already wrote an error message */
			FREENOW;
			RETURN_FALSE;
		}
		if (hptr->flags & (DBA_NO_APPEND|DBA_CAST_AS_FD)) {
			/* Needed because some systems do not allow to write to the original
			 * file contents with O_APPEND being set.
			 */
			if (SUCCESS != php_stream_cast(info->fp, PHP_STREAM_AS_FD, (void*)&info->fd, 1)) {
				php_error_docref(NULL, E_WARNING, "Could not cast stream");
				dba_close(info);
				FREENOW;
				RETURN_FALSE;
#ifdef F_SETFL
			} else if (modenr == DBA_CREAT) {
				int flags = fcntl(info->fd, F_SETFL);
				fcntl(info->fd, F_SETFL, flags & ~O_APPEND);
#endif
			}

		}
	}

	if (error || hptr->open(info, &error) != SUCCESS) {
		dba_close(info);
		php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Driver initialization failed for handler: %s%s%s", hptr->name, error?": ":"", error?error:"");
		FREENOW;
		RETURN_FALSE;
	}

	info->hnd = hptr;
	info->argc = 0;
	info->argv = NULL;

	if (persistent) {
		zend_resource new_le;

		new_le.type = le_pdb;
		new_le.ptr = info;
		if (zend_hash_str_update_mem(&EG(persistent_list), key, keylen, &new_le, sizeof(zend_resource)) == NULL) {
			dba_close(info);
			php_error_docref2(NULL, Z_STRVAL(args[0]), Z_STRVAL(args[1]), E_WARNING, "Could not register persistent resource");
			FREENOW;
			RETURN_FALSE;
		}
	}

	RETVAL_RES(zend_register_resource(info, (persistent ? le_pdb : le_db)));
	FREENOW;
}
Пример #27
0
static int do_callback(struct pdo_sqlite_fci *fc, zval *cb,
		int argc, sqlite3_value **argv, sqlite3_context *context,
		int is_agg)
{
	zval *zargs = NULL;
	zval retval;
	int i;
	int ret;
	int fake_argc;
	zend_reference *agg_context = NULL;

	if (is_agg) {
		is_agg = 2;
	}

	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 = safe_emalloc(fake_argc, sizeof(zval), 0);
	}

	if (is_agg) {
		agg_context = (zend_reference*)sqlite3_aggregate_context(context, sizeof(zend_reference));
		if (!agg_context) {
			ZVAL_NULL(&zargs[0]);
		} else {
			if (Z_ISUNDEF(agg_context->val)) {
				GC_REFCOUNT(agg_context) = 1;
				GC_TYPE_INFO(agg_context) = IS_REFERENCE;
				ZVAL_NULL(&agg_context->val);
			}
			ZVAL_REF(&zargs[0], agg_context);
		}
		ZVAL_LONG(&zargs[1], sqlite3_aggregate_count(context));
	}

	for (i = 0; i < argc; i++) {
		/* get the value */
		switch (sqlite3_value_type(argv[i])) {
			case SQLITE_INTEGER:
				ZVAL_LONG(&zargs[i + is_agg], sqlite3_value_int(argv[i]));
				break;

			case SQLITE_FLOAT:
				ZVAL_DOUBLE(&zargs[i + is_agg], sqlite3_value_double(argv[i]));
				break;

			case SQLITE_NULL:
				ZVAL_NULL(&zargs[i + is_agg]);
				break;

			case SQLITE_BLOB:
			case SQLITE3_TEXT:
			default:
				ZVAL_STRINGL(&zargs[i + is_agg], (char*)sqlite3_value_text(argv[i]), sqlite3_value_bytes(argv[i]));
				break;
		}
	}

	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");
	}

	/* clean up the params */
	if (zargs) {
		for (i = is_agg; i < fake_argc; i++) {
			zval_ptr_dtor(&zargs[i]);
		}
		if (is_agg) {
			zval_ptr_dtor(&zargs[1]);
		}
		efree(zargs);
	}

	if (!is_agg || !argv) {
		/* only set the sqlite return value if we are a scalar function,
		 * or if we are finalizing an aggregate */
		if (!Z_ISUNDEF(retval)) {
			switch (Z_TYPE(retval)) {
				case IS_LONG:
					sqlite3_result_int(context, Z_LVAL(retval));
					break;

				case IS_NULL:
					sqlite3_result_null(context);
					break;

				case IS_DOUBLE:
					sqlite3_result_double(context, Z_DVAL(retval));
					break;

				default:
					convert_to_string_ex(&retval);
					sqlite3_result_text(context, Z_STRVAL(retval), Z_STRLEN(retval), SQLITE_TRANSIENT);
					break;
			}
		} else {
			sqlite3_result_error(context, "failed to invoke callback", 0);
		}

		if (agg_context) {
			zval_ptr_dtor(&agg_context->val);
		}
	} else {
		/* we're stepping in an aggregate; the return value goes into
		 * the context */
		if (agg_context) {
			zval_ptr_dtor(&agg_context->val);
		}
		if (!Z_ISUNDEF(retval)) {
			ZVAL_COPY_VALUE(&agg_context->val, &retval);
			ZVAL_UNDEF(&retval);
		} else {
			ZVAL_UNDEF(&agg_context->val);
		}
	}

	if (!Z_ISUNDEF(retval)) {
		zval_ptr_dtor(&retval);
	}

	return ret;
}
Пример #28
0
static void _str_dtor(zval *zv)
{
	zend_string *str = Z_STR_P(zv);
	GC_FLAGS(str) &= ~IS_STR_INTERNED;
	GC_REFCOUNT(str) = 1;
}
Пример #29
0
/* {{{ proto mixed Closure::call(object to [, mixed parameter] [, mixed ...] )
   Call closure, binding to a given object with its class as the scope */
ZEND_METHOD(Closure, call)
{
	zval *zclosure, *newthis, closure_result;
	zend_closure *closure;
	zend_fcall_info fci;
	zend_fcall_info_cache fci_cache;
	zval *my_params;
	int my_param_count = 0;
	zend_function my_function;
	zend_object *newobj;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o*", &newthis, &my_params, &my_param_count) == FAILURE) {
		return;
	}

	zclosure = getThis();
	closure = (zend_closure *) Z_OBJ_P(zclosure);

	newobj = Z_OBJ_P(newthis);

	if (!zend_valid_closure_binding(closure, newthis, Z_OBJCE_P(newthis))) {
		return;
	}

	/* This should never happen as closures will always be callable */
	if (zend_fcall_info_init(zclosure, 0, &fci, &fci_cache, NULL, NULL) != SUCCESS) {
		ZEND_ASSERT(0);
	}

	fci.retval = &closure_result;
	fci.params = my_params;
	fci.param_count = my_param_count;
	fci.object = fci_cache.object = newobj;
	fci_cache.initialized = 1;
	fci_cache.called_scope = Z_OBJCE_P(newthis);

	if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
		zval new_closure;
		zend_create_closure(&new_closure, fci_cache.function_handler, Z_OBJCE_P(newthis), closure->called_scope, newthis);
		closure = (zend_closure *) Z_OBJ(new_closure);
		fci_cache.function_handler = &closure->func;
	} else {
		memcpy(&my_function, fci_cache.function_handler, fci_cache.function_handler->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
		/* use scope of passed object */
		my_function.common.scope = Z_OBJCE_P(newthis);
		fci_cache.function_handler = &my_function;

		/* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
		if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
			my_function.op_array.run_time_cache = emalloc(my_function.op_array.cache_size);
			memset(my_function.op_array.run_time_cache, 0, my_function.op_array.cache_size);
		}
	}

	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) {
		ZVAL_COPY_VALUE(return_value, &closure_result);
	}

	if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
		/* copied upon generator creation */
		--GC_REFCOUNT(&closure->std);
	} else if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
		efree(my_function.op_array.run_time_cache);
	}
}
Пример #30
0
static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
{
	zval retval;
	int result, i;
	int error = 0;
	zend_fcall_info fci;
	xmlXPathObjectPtr obj;
	char *str;
	zend_string *callable = NULL;
	dom_xpath_object *intern;


	if (! zend_is_executing()) {
		xmlGenericError(xmlGenericErrorContext,
		"xmlExtFunctionTest: Function called from outside of PHP\n");
		error = 1;
	} else {
		intern = (dom_xpath_object *) ctxt->context->userData;
		if (intern == NULL) {
			xmlGenericError(xmlGenericErrorContext,
			"xmlExtFunctionTest: failed to get the internal object\n");
			error = 1;
		}
		else if (intern->registerPhpFunctions == 0) {
			xmlGenericError(xmlGenericErrorContext,
			"xmlExtFunctionTest: PHP Object did not register PHP functions\n");
			error = 1;
		}
	}

	if (error == 1) {
		for (i = nargs - 1; i >= 0; i--) {
			obj = valuePop(ctxt);
			xmlXPathFreeObject(obj);
		}
		return;
	}

	fci.param_count = nargs - 1;
	if (fci.param_count > 0) {
		fci.params = safe_emalloc(fci.param_count, sizeof(zval), 0);
	}
	/* Reverse order to pop values off ctxt stack */
	for (i = nargs - 2; i >= 0; i--) {
		obj = valuePop(ctxt);
		switch (obj->type) {
			case XPATH_STRING:
				ZVAL_STRING(&fci.params[i],  (char *)obj->stringval);
				break;
			case XPATH_BOOLEAN:
				ZVAL_BOOL(&fci.params[i],  obj->boolval);
				break;
			case XPATH_NUMBER:
				ZVAL_DOUBLE(&fci.params[i], obj->floatval);
				break;
			case XPATH_NODESET:
				if (type == 1) {
					str = (char *)xmlXPathCastToString(obj);
					ZVAL_STRING(&fci.params[i], str);
					xmlFree(str);
				} else if (type == 2) {
					int j;
					array_init(&fci.params[i]);
					if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
						for (j = 0; j < obj->nodesetval->nodeNr; j++) {
							xmlNodePtr node = obj->nodesetval->nodeTab[j];
							zval child;
							/* not sure, if we need this... it's copied from xpath.c */
							if (node->type == XML_NAMESPACE_DECL) {
								xmlNsPtr curns;
								xmlNodePtr nsparent;

								nsparent = node->_private;
								curns = xmlNewNs(NULL, node->name, NULL);
								if (node->children) {
									curns->prefix = xmlStrdup((xmlChar *) node->children);
								}
								if (node->children) {
									node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name);
								} else {
									node = xmlNewDocNode(node->doc, NULL, (xmlChar *) "xmlns", node->name);
								}
								node->type = XML_NAMESPACE_DECL;
								node->parent = nsparent;
								node->ns = curns;
							}
							php_dom_create_object(node, &child, &intern->dom);
							add_next_index_zval(&fci.params[i], &child);
						}
					}
				}
				break;
			default:
			ZVAL_STRING(&fci.params[i], (char *)xmlXPathCastToString(obj));
		}
		xmlXPathFreeObject(obj);
	}

	fci.size = sizeof(fci);
	fci.function_table = EG(function_table);

	obj = valuePop(ctxt);
	if (obj->stringval == NULL) {
		php_error_docref(NULL, E_WARNING, "Handler name must be a string");
		xmlXPathFreeObject(obj);
		if (fci.param_count > 0) {
			for (i = 0; i < nargs - 1; i++) {
				zval_ptr_dtor(&fci.params[i]);
			}
			efree(fci.params);
		}
		return;
	}
	ZVAL_STRING(&fci.function_name, (char *) obj->stringval);
	xmlXPathFreeObject(obj);

	fci.symbol_table = NULL;
	fci.object = NULL;
	fci.retval = &retval;
	fci.no_separation = 0;

	if (!zend_make_callable(&fci.function_name, &callable)) {
		php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", callable->val);
	} else if (intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
		php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'.", callable->val);
		/* Push an empty string, so that we at least have an xslt result... */
		valuePush(ctxt, xmlXPathNewString((xmlChar *)""));
	} else {
		result = zend_call_function(&fci, NULL);
		if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
			if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
				xmlNode *nodep;
				dom_object *obj;
				if (intern->node_list == NULL) {
					ALLOC_HASHTABLE(intern->node_list);
					zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0);
				}
				GC_REFCOUNT(&retval)++;
				zend_hash_next_index_insert(intern->node_list, &retval);
				obj = Z_DOMOBJ_P(&retval);
				nodep = dom_object_get_node(obj);
				valuePush(ctxt, xmlXPathNewNodeSet(nodep));
			} else if (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE) {
				valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
			} else if (Z_TYPE(retval) == IS_OBJECT) {
				php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
				valuePush(ctxt, xmlXPathNewString((xmlChar *)""));
			} else {
				zend_string *str = zval_get_string(&retval);
				valuePush(ctxt, xmlXPathNewString((xmlChar *) str->val));
				zend_string_release(str);
			}
			zval_ptr_dtor(&retval);
		}
	}
	zend_string_release(callable);
	zval_dtor(&fci.function_name);
	if (fci.param_count > 0) {
		for (i = 0; i < nargs - 1; i++) {
			zval_ptr_dtor(&fci.params[i]);
		}
		efree(fci.params);
	}
}