Beispiel #1
0
/* {{{ pthreads_get_method will attempt to apply pthreads specific modifiers */
zend_function * pthreads_get_method(PTHREADS_GET_METHOD_PASSTHRU_D) {
	zend_class_entry *scope;
	zend_function *call;
	zend_function *callable;
	char *lcname;
	int access = 0;
	PTHREAD thread = PTHREADS_FETCH_FROM(*pobject);
	
	if (thread) {
		switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){
			case ZEND_ACC_PRIVATE:
			case ZEND_ACC_PROTECTED:
				scope = Z_OBJCE_PP(pobject);
				lcname =  (char*) calloc(1, methodl+1);
				zend_str_tolower_copy(lcname, method, methodl);
				if (zend_hash_find(&scope->function_table, lcname, methodl+1, (void**)&call)==SUCCESS) {
					callable = (zend_function*) emalloc(sizeof(zend_function));
					callable->type = ZEND_OVERLOADED_FUNCTION;
					callable->common.function_name = call->common.function_name;
					callable->common.fn_flags = ZEND_ACC_PUBLIC;
					callable->common.scope = scope;
					callable->common.arg_info = call->common.arg_info;
					callable->common.num_args = call->common.num_args;
					callable->common.required_num_args = call->common.required_num_args;
#if PHP_VERSION_ID < 50400
					callable->common.pass_rest_by_reference = call->common.pass_rest_by_reference;
					callable->common.return_reference = call->common.return_reference;
#endif
					free(lcname);
					return callable;
				}
				free(lcname);
				/* TODO : if not found ? switch to default ? or return some error ? */

			default: call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C);
		}
		
	} else call = zend_handlers->get_method(PTHREADS_GET_METHOD_PASSTHRU_C);
	
	return call;
} /* }}} */
Beispiel #2
0
/* {{{ pthreads_call_method */
int pthreads_call_method(PTHREADS_CALL_METHOD_PASSTHRU_D) {
	zval 					***argv = NULL, zmethod, *zresult;
	zend_function 			*call = NULL;
	zend_fcall_info 		info;
	zend_fcall_info_cache	cache;
	zend_class_entry		*scope;
	int 					called = -1, argc = ZEND_NUM_ARGS(), access = ZEND_ACC_PUBLIC, mlength = 0;
	char					*lcname;
	zend_bool				unprotect;
	
	if (getThis()) {
		PTHREAD thread = PTHREADS_FETCH;
		if (thread) {
			switch((access=pthreads_modifiers_get(thread->modifiers, method TSRMLS_CC))){
				case ZEND_ACC_PRIVATE:
				case ZEND_ACC_PROTECTED: {
					scope = Z_OBJCE_P(getThis());
					
					/*
					* Stop invalid private method calls
					*/
					if (access == ZEND_ACC_PRIVATE && !PTHREADS_IN_THREAD(thread)) {
						zend_error_noreturn(
							E_ERROR, 
							"pthreads detected an attempt to call private method %s::%s from outside the threading context", 
							scope->name,
							method
						);
						return FAILURE;
					}
					
					/*
					* Get arguments from stack
					*/
					if (ZEND_NUM_ARGS()) 
					{
						argv = safe_emalloc(sizeof(zval **), argc, 0);
						if (argv) {
							zend_get_parameters_array_ex(argc, argv);
						}
					}
							
					mlength = strlen(method);
					lcname =  calloc(1, mlength+1);
					zend_str_tolower_copy(lcname, method, mlength);
					
					if (zend_hash_find(&scope->function_table, lcname, mlength+1, (void**)&call)==SUCCESS) {
						if (call) {
							/*
							* Make protected method call
							*/
							{
								if (access != ZEND_ACC_PROTECTED || pthreads_modifiers_protect(thread->modifiers, method, &unprotect TSRMLS_CC)) {
								
									ZVAL_STRINGL(&zmethod, method, strlen(method), 0);
									
									info.size = sizeof(info);
									info.object_ptr = getThis();
									info.function_name = &zmethod;
									info.retval_ptr_ptr = &zresult;
									info.no_separation = 1;
									info.symbol_table = NULL;
									info.param_count = argc;
									info.params = argv;
									
									cache.initialized = 1;
									cache.function_handler = call;
									cache.calling_scope = EG(called_scope);
									cache.called_scope = scope;
									cache.object_ptr = getThis();
									
									if ((called=zend_call_function(&info, &cache TSRMLS_CC))!=SUCCESS) {
										zend_error_noreturn(
											E_ERROR, 
											"pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", 
											(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
											scope->name,
											method
										);
									} else {
#if PHP_VERSION_ID > 50399
										{
											zend_op_array *ops = (zend_op_array*) call;
										
											if (ops) {
												if (ops->run_time_cache) {
													efree(ops->run_time_cache);
													ops->run_time_cache = NULL;
												}
											}
										}
#endif
										if (!return_value_used) {
											zval_ptr_dtor(&zresult);
										} else {
											ZVAL_ZVAL(return_value, zresult, 1, 1);
										}
									}
									
									if (access == ZEND_ACC_PROTECTED) {
										pthreads_modifiers_unprotect(thread->modifiers, method, unprotect TSRMLS_CC);
									}
								} else {
									zend_error_noreturn(
										E_ERROR, 
										"pthreads has experienced an internal error while calling %s method %s::%s and cannot continue", 
										(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
										scope->name,
										method
									);
									called = FAILURE;
								}
							}
						} else {
							zend_error_noreturn(
								E_ERROR, 
								"pthreads has experienced an internal error while finding %s method %s::%s and cannot continue", 
								(access == ZEND_ACC_PROTECTED) ? "protected" : "private",
								scope->name,
								method
							);
							called = FAILURE;
						}
					}
					/*
					* Free unstacked arguments
					*/
					if (argc) {
						efree(argv);
					}
					free(lcname);
					return called;
				} break;
			}
		}
	}
	
	switch (called) {
		case -1: 
			return zend_handlers->call_method(PTHREADS_CALL_METHOD_PASSTHRU_C);
			
		default: return called;
	}
	
} /* }}} */