Пример #1
0
/* call userland key distributor function */
zend_bool
ra_call_distributor(RedisArray *ra, const char *key, int key_len, int *pos) {

    zval z_ret;
    zval z_argv0;

    /* check that we can call the extractor function */
    if (!zend_is_callable_ex(&ra->z_dist, NULL, 0, NULL, NULL, NULL)) {
        php_error_docref(NULL, E_ERROR, "Could not call distributor function");
        return 0;
    }
    //convert_to_string(ra->z_fun);

    /* call extraction function */
    ZVAL_STRINGL(&z_argv0, key, key_len);
    call_user_function(EG(function_table), NULL, &ra->z_dist, &z_ret, 1, &z_argv0);
    efree(&z_argv0);

    if (Z_TYPE(z_ret) != IS_LONG) {
        zval_dtor(&z_ret);
        return 0;
    }

    *pos = Z_LVAL(z_ret);
    zval_dtor(&z_ret);
    return 1;
}
Пример #2
0
static int zend_create_closure_from_callable(zval *return_value, zval *callable, char **error) /* {{{ */ {
	zend_fcall_info_cache fcc;
	zend_function *mptr;
	zval instance;
	zend_internal_function call;

	if (!zend_is_callable_ex(callable, NULL, 0, NULL, &fcc, error)) {
		return FAILURE;
	}

	mptr = fcc.function_handler;
	if (mptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
		memset(&call, 0, sizeof(zend_internal_function));

		call.type = ZEND_INTERNAL_FUNCTION;
		call.handler = zend_closure_call_magic;
		call.function_name = mptr->common.function_name;
		call.arg_info = (zend_internal_arg_info *) mptr->common.prototype;
		call.scope = mptr->common.scope;

		zend_free_trampoline(mptr);
		mptr = (zend_function *) &call;
	}

	if (fcc.object) {
		ZVAL_OBJ(&instance, fcc.object);
		zend_create_fake_closure(return_value, mptr, mptr->common.scope, fcc.called_scope, &instance);
	} else {
		zend_create_fake_closure(return_value, mptr, mptr->common.scope, fcc.called_scope, NULL);
	}

	return SUCCESS;
}
Пример #3
0
/* call userland key extraction function */
char *
ra_call_extractor(RedisArray *ra, const char *key, int key_len, int *out_len) {

    char *out;
    zval z_ret;
    zval z_argv0;

    /* check that we can call the extractor function */
    if (!zend_is_callable_ex(&ra->z_fun, NULL, 0, NULL, NULL, NULL)) {
        php_error_docref(NULL, E_ERROR, "Could not call extractor function");
        return NULL;
    }
    //convert_to_string(ra->z_fun);

    /* call extraction function */
    ZVAL_STRINGL(&z_argv0, key, key_len);
    call_user_function(EG(function_table), NULL, &ra->z_fun, &z_ret, 1, &z_argv0);
    efree(&z_argv0);

    if (Z_TYPE(z_ret) != IS_STRING) {
        zval_dtor(&z_ret);
        return NULL;
    }
    *out_len = Z_STRLEN(z_ret);
    out = emalloc(*out_len + 1);
    out[*out_len] = 0;
    memcpy(out, Z_STRVAL(z_ret), *out_len);
    zval_dtor(&z_ret);
    return out;
}
Пример #4
0
VALUE php_value_callable(VALUE self) {
    char *error;
    zend_bool retval;

    retval = zend_is_callable_ex(get_zval(self), NULL, 0, NULL, NULL, NULL, &error TSRMLS_CC);
    if (error) {
        efree(error);
    }

    return (retval) ? Qtrue : Qfalse;
}
Пример #5
0
/**
 * Checks if a zval is callable
 */
int zephir_is_callable(zval *var)
{
	char *error = NULL;
	zend_bool retval;

	retval = zend_is_callable_ex(var, NULL, 0, NULL, NULL, &error);
	if (error) {
		efree(error);
	}

	return (int) retval;
}
Пример #6
0
/**
 * Lookups a function call and caches its zend_fcall_info_cache for further calls
 */
int phalcon_cache_lookup_function(zval *fn, int fcache_pointer TSRMLS_DC){
	if(!phalcon_fcall_cache[fcache_pointer]){
		{
			char *callable_name;
			char *error = NULL;

			phalcon_fcall_cache[fcache_pointer] = emalloc(sizeof(zend_fcall_info_cache));
			if (!zend_is_callable_ex(fn, NULL, IS_CALLABLE_CHECK_SILENT, &callable_name, NULL, phalcon_fcall_cache[fcache_pointer], &error TSRMLS_CC)) {
				if (error) {
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback %s, %s", callable_name, error);
					efree(error);
					return FAILURE;
				}
			}

			efree(callable_name);
		}
	}
	return SUCCESS;
}
Пример #7
0
/**
 * Copies of internal methods from Zend/zend_execute_API.c
 * These are used to call internal methods (not in the function table) from the external method.
 * TODO: See if xdebug works
 */
int runkit_forward_call_user_function(zend_function *fbc, zend_function *fbc_inner, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
	uint32_t i;
	zend_execute_data *call, dummy_execute_data;
	zend_fcall_info_cache fci_cache_local = {0};
	zend_function *func;
	/* {{{ patch for runkit */
	zend_fcall_info fci = {0};
	zend_fcall_info_cache *fci_cache = NULL;

	fci.size = sizeof(fci);
	fci.object = NULL; // FIXME for methods? // object ? Z_OBJ_P(object) : NULL;
	ZVAL_STR(&fci.function_name, fbc_inner->common.function_name);
	zend_string_addref(fbc_inner->common.function_name);
	fci.retval = return_value;
	fci.param_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
	fci.params = ZEND_CALL_ARG(EG(current_execute_data), 1);  // params and param_count From zend_API.c
	fci.no_separation = (zend_bool)1;			  // ???
	/* end patch for runkit }}} */

	ZVAL_UNDEF(fci.retval);

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

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

	/* 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;
	}

	if (!fci_cache || !RUNKIT_IS_FCI_CACHE_INITIALIZED(fci_cache)) {
		zend_string *callable_name;
		char *error = NULL;

		if (!fci_cache) {
			fci_cache = &fci_cache_local;
		}

		if (!zend_is_callable_ex(&fci.function_name, fci.object, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error)) {
			if (error) {
				zend_error(E_WARNING, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error);
				efree(error);
			}
			if (callable_name) {
				zend_string_release(callable_name);
			}
			if (EG(current_execute_data) == &dummy_execute_data) {
				EG(current_execute_data) = dummy_execute_data.prev_execute_data;
			}
			return FAILURE;
		} else if (error) {
			/* Capitalize the first latter of the error message */
			if (error[0] >= 'a' && error[0] <= 'z') {
				error[0] += ('A' - 'a');
			}
			zend_error(E_DEPRECATED, "%s", error);
			efree(error);
		}
		zend_string_release(callable_name);
	}

	func = fbc_inner;
    fci.object = (func->common.fn_flags & ZEND_ACC_STATIC) ?
	   NULL : fci_cache->object;

    call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC,
	   func, fci.param_count, fci_cache->called_scope, fci.object);
	if (fci.object &&
	    (!EG(objects_store).object_buckets ||
	     !IS_OBJ_VALID(EG(objects_store).object_buckets[fci.object->handle]))) {
		if (EG(current_execute_data) == &dummy_execute_data) {
			EG(current_execute_data) = dummy_execute_data.prev_execute_data;
		}
		return FAILURE;
	}

	if (func->common.fn_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_DEPRECATED)) {
		if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
			zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(func->common.scope->name), 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;
		}
		if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
 			zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
				func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
				func->common.scope ? "::" : "",
				ZSTR_VAL(func->common.function_name));
		}
	}

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

		if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
			if (UNEXPECTED(!Z_ISREF_P(arg))) {
				if (!fci.no_separation) {
					/* Separation is enabled -- create a ref */
					ZVAL_NEW_REF(arg, arg);
				} else if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
					/* By-value send is not allowed -- emit a warning,
					 * but still perform the call with a by-value send. */
					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));
				}
			}
		} 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);
			}
		}
		param = ZEND_CALL_ARG(call, i + 1);
		ZVAL_COPY(param, arg);
	}

	if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
		ZEND_ASSERT(GC_TYPE((zend_object *)func->op_array.prototype) == IS_OBJECT);
		GC_ADDREF((zend_object *)func->op_array.prototype);
		ZEND_ADD_CALL_FLAG(call, ZEND_CALL_CLOSURE);
	}

	if (func->type == ZEND_USER_FUNCTION) {
		int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
		zend_init_execute_data(call, &func->op_array, fci.retval);
		zend_execute_ex(call);
		if (call_via_handler) {
			/* We must re-initialize function again */
			RUNKIT_CLEAR_FCI_CACHE(fci_cache);
		}
	} else if (func->type == ZEND_INTERNAL_FUNCTION) {
		int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
		ZVAL_NULL(fci.retval);
		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, fci.retval);
		} else {
			zend_execute_internal(call, fci.retval);
		}
		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(fci.retval);
			ZVAL_UNDEF(fci.retval);
		}

		if (call_via_handler) {
			/* We must re-initialize function again */
			RUNKIT_CLEAR_FCI_CACHE(fci_cache);
		}
	} else { /* ZEND_OVERLOADED_FUNCTION */
		ZVAL_NULL(fci.retval);

		/* Not sure what should be done here if it's a static method */
		if (fci.object) {
			call->prev_execute_data = EG(current_execute_data);
			EG(current_execute_data) = call;
			fci.object->handlers->call_method(func->common.function_name, fci.object, call, fci.retval);
			EG(current_execute_data) = call->prev_execute_data;
		} else {
			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(fci.retval);
			ZVAL_UNDEF(fci.retval);
		}
	}

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