1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Christian Seiler <chris_se@gmx.net>                         |
16   |          Dmitry Stogov <dmitry@zend.com>                             |
17   |          Marcus Boerger <helly@php.net>                              |
18   +----------------------------------------------------------------------+
19*/
20
21/* $Id$ */
22
23#include "zend.h"
24#include "zend_API.h"
25#include "zend_closures.h"
26#include "zend_exceptions.h"
27#include "zend_interfaces.h"
28#include "zend_objects.h"
29#include "zend_objects_API.h"
30#include "zend_globals.h"
31
32#define ZEND_CLOSURE_PRINT_NAME "Closure object"
33
34#define ZEND_CLOSURE_PROPERTY_ERROR() \
35	zend_throw_error(NULL, "Closure object cannot have properties")
36
37/* reuse bit to mark "fake" closures (it wasn't used for functions before) */
38#define ZEND_ACC_FAKE_CLOSURE ZEND_ACC_INTERFACE
39
40typedef struct _zend_closure {
41	zend_object       std;
42	zend_function     func;
43	zval              this_ptr;
44	zend_class_entry *called_scope;
45	void (*orig_internal_handler)(INTERNAL_FUNCTION_PARAMETERS);
46} zend_closure;
47
48/* non-static since it needs to be referenced */
49ZEND_API zend_class_entry *zend_ce_closure;
50static zend_object_handlers closure_handlers;
51
52ZEND_METHOD(Closure, __invoke) /* {{{ */
53{
54	zend_function *func = EX(func);
55	zval *arguments;
56
57	arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS());
58	if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
59		efree(arguments);
60		zend_throw_error(NULL, "Cannot get arguments for calling closure");
61		RETVAL_FALSE;
62	} else if (call_user_function_ex(CG(function_table), NULL, getThis(), return_value, ZEND_NUM_ARGS(), arguments, 1, NULL) == FAILURE) {
63		RETVAL_FALSE;
64	}
65	efree(arguments);
66
67	/* destruct the function also, then - we have allocated it in get_method */
68	zend_string_release(func->internal_function.function_name);
69	efree(func);
70#if ZEND_DEBUG
71	execute_data->func = NULL;
72#endif
73}
74/* }}} */
75
76static zend_bool zend_valid_closure_binding(
77		zend_closure *closure, zval *newthis, zend_class_entry *scope) /* {{{ */
78{
79	zend_function *func = &closure->func;
80	if (newthis) {
81		if (func->common.fn_flags & ZEND_ACC_STATIC) {
82			zend_error(E_WARNING, "Cannot bind an instance to a static closure");
83			return 0;
84		}
85
86		if (func->type == ZEND_INTERNAL_FUNCTION && func->common.scope &&
87				!instanceof_function(Z_OBJCE_P(newthis), func->common.scope)) {
88			/* Binding incompatible $this to an internal method is not supported. */
89			zend_error(E_WARNING, "Cannot bind internal method %s::%s() to object of class %s",
90					ZSTR_VAL(func->common.scope->name),
91					ZSTR_VAL(func->common.function_name),
92					ZSTR_VAL(Z_OBJCE_P(newthis)->name));
93			return 0;
94		}
95	} else if (!(func->common.fn_flags & ZEND_ACC_STATIC) && func->common.scope
96			&& func->type == ZEND_INTERNAL_FUNCTION) {
97		zend_error(E_WARNING, "Cannot unbind $this of internal method");
98		return 0;
99	}
100
101	if (scope && scope != func->common.scope && scope->type == ZEND_INTERNAL_CLASS) {
102		/* rebinding to internal class is not allowed */
103		zend_error(E_WARNING, "Cannot bind closure to scope of internal class %s",
104				ZSTR_VAL(scope->name));
105		return 0;
106	}
107
108	if ((func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) && scope != func->common.scope) {
109		zend_error(E_WARNING, "Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()");
110		return 0;
111	}
112
113	return 1;
114}
115/* }}} */
116
117/* {{{ proto mixed Closure::call(object to [, mixed parameter] [, mixed ...] )
118   Call closure, binding to a given object with its class as the scope */
119ZEND_METHOD(Closure, call)
120{
121	zval *zclosure, *newthis, closure_result;
122	zend_closure *closure;
123	zend_fcall_info fci;
124	zend_fcall_info_cache fci_cache;
125	zval *my_params;
126	int my_param_count = 0;
127	zend_function my_function;
128	zend_object *newobj;
129
130	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o*", &newthis, &my_params, &my_param_count) == FAILURE) {
131		return;
132	}
133
134	zclosure = getThis();
135	closure = (zend_closure *) Z_OBJ_P(zclosure);
136
137	newobj = Z_OBJ_P(newthis);
138
139	if (!zend_valid_closure_binding(closure, newthis, Z_OBJCE_P(newthis))) {
140		return;
141	}
142
143	/* This should never happen as closures will always be callable */
144	if (zend_fcall_info_init(zclosure, 0, &fci, &fci_cache, NULL, NULL) != SUCCESS) {
145		ZEND_ASSERT(0);
146	}
147
148	fci.retval = &closure_result;
149	fci.params = my_params;
150	fci.param_count = my_param_count;
151	fci.object = fci_cache.object = newobj;
152	fci_cache.initialized = 1;
153	fci_cache.called_scope = Z_OBJCE_P(newthis);
154
155	if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
156		zval new_closure;
157		zend_create_closure(&new_closure, fci_cache.function_handler, Z_OBJCE_P(newthis), closure->called_scope, newthis);
158		closure = (zend_closure *) Z_OBJ(new_closure);
159		fci_cache.function_handler = &closure->func;
160	} else {
161		memcpy(&my_function, fci_cache.function_handler, fci_cache.function_handler->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
162		/* use scope of passed object */
163		my_function.common.scope = Z_OBJCE_P(newthis);
164		fci_cache.function_handler = &my_function;
165
166		/* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
167		if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
168			my_function.op_array.run_time_cache = emalloc(my_function.op_array.cache_size);
169			memset(my_function.op_array.run_time_cache, 0, my_function.op_array.cache_size);
170		}
171	}
172
173	if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) {
174		ZVAL_COPY_VALUE(return_value, &closure_result);
175	}
176
177	if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
178		/* copied upon generator creation */
179		--GC_REFCOUNT(&closure->std);
180	} else if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
181		efree(my_function.op_array.run_time_cache);
182	}
183}
184/* }}} */
185
186/* {{{ proto Closure Closure::bind(callable old, object to [, mixed scope])
187   Create a closure from another one and bind to another object and scope */
188ZEND_METHOD(Closure, bind)
189{
190	zval *newthis, *zclosure, *scope_arg = NULL;
191	zend_closure *closure, *new_closure;
192	zend_class_entry *ce, *called_scope;
193
194	if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
195		return;
196	}
197
198	closure = (zend_closure *)Z_OBJ_P(zclosure);
199
200	if (scope_arg != NULL) { /* scope argument was given */
201		if (Z_TYPE_P(scope_arg) == IS_OBJECT) {
202			ce = Z_OBJCE_P(scope_arg);
203		} else if (Z_TYPE_P(scope_arg) == IS_NULL) {
204			ce = NULL;
205		} else {
206			zend_string *class_name = zval_get_string(scope_arg);
207			if (zend_string_equals_literal(class_name, "static")) {
208				ce = closure->func.common.scope;
209			} else if ((ce = zend_lookup_class_ex(class_name, NULL, 1)) == NULL) {
210				zend_error(E_WARNING, "Class '%s' not found", ZSTR_VAL(class_name));
211				zend_string_release(class_name);
212				RETURN_NULL();
213			}
214			zend_string_release(class_name);
215		}
216	} else { /* scope argument not given; do not change the scope by default */
217		ce = closure->func.common.scope;
218	}
219
220	if (!zend_valid_closure_binding(closure, newthis, ce)) {
221		return;
222	}
223
224	if (newthis) {
225		called_scope = Z_OBJCE_P(newthis);
226	} else {
227		called_scope = ce;
228	}
229
230	zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
231	new_closure = (zend_closure *) Z_OBJ_P(return_value);
232
233	/* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
234	if (ZEND_USER_CODE(closure->func.type) && (closure->func.common.scope != new_closure->func.common.scope || (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA))) {
235		new_closure->func.op_array.run_time_cache = emalloc(new_closure->func.op_array.cache_size);
236		memset(new_closure->func.op_array.run_time_cache, 0, new_closure->func.op_array.cache_size);
237
238		new_closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
239	}
240}
241/* }}} */
242
243static ZEND_COLD zend_function *zend_closure_get_constructor(zend_object *object) /* {{{ */
244{
245	zend_throw_error(NULL, "Instantiation of 'Closure' is not allowed");
246	return NULL;
247}
248/* }}} */
249
250static int zend_closure_compare_objects(zval *o1, zval *o2) /* {{{ */
251{
252	return (Z_OBJ_P(o1) != Z_OBJ_P(o2));
253}
254/* }}} */
255
256ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* {{{ */
257{
258	zend_closure *closure = (zend_closure *)object;
259	zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
260	const uint32_t keep_flags =
261		ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC | ZEND_ACC_HAS_RETURN_TYPE;
262
263	invoke->common = closure->func.common;
264	/* We return ZEND_INTERNAL_FUNCTION, but arg_info representation is the
265	 * same as for ZEND_USER_FUNCTION (uses zend_string* instead of char*).
266	 * This is not a problem, because ZEND_ACC_HAS_TYPE_HINTS is never set,
267	 * and we won't check arguments on internal function. We also set
268	 * ZEND_ACC_USER_ARG_INFO flag to prevent invalid usage by Reflection */
269	invoke->type = ZEND_INTERNAL_FUNCTION;
270	invoke->internal_function.fn_flags =
271		ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & keep_flags);
272	if (closure->func.type != ZEND_INTERNAL_FUNCTION || (closure->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
273		invoke->internal_function.fn_flags |=
274			ZEND_ACC_USER_ARG_INFO;
275	}
276	invoke->internal_function.handler = ZEND_MN(Closure___invoke);
277	invoke->internal_function.module = 0;
278	invoke->internal_function.scope = zend_ce_closure;
279	invoke->internal_function.function_name = zend_string_init(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1, 0);
280	return invoke;
281}
282/* }}} */
283
284ZEND_API const zend_function *zend_get_closure_method_def(zval *obj) /* {{{ */
285{
286	zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
287	return &closure->func;
288}
289/* }}} */
290
291ZEND_API zval* zend_get_closure_this_ptr(zval *obj) /* {{{ */
292{
293	zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
294	return &closure->this_ptr;
295}
296/* }}} */
297
298static zend_function *zend_closure_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */
299{
300	zend_string *lc_name;
301
302	lc_name = zend_string_tolower(method);
303	if (zend_string_equals_literal(method, ZEND_INVOKE_FUNC_NAME)) {
304		zend_string_release(lc_name);
305		return zend_get_closure_invoke_method(*object);
306	}
307	zend_string_release(lc_name);
308	return std_object_handlers.get_method(object, method, key);
309}
310/* }}} */
311
312static zval *zend_closure_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
313{
314	ZEND_CLOSURE_PROPERTY_ERROR();
315	return &EG(uninitialized_zval);
316}
317/* }}} */
318
319static void zend_closure_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */
320{
321	ZEND_CLOSURE_PROPERTY_ERROR();
322}
323/* }}} */
324
325static zval *zend_closure_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */
326{
327	ZEND_CLOSURE_PROPERTY_ERROR();
328	return NULL;
329}
330/* }}} */
331
332static int zend_closure_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */
333{
334	if (has_set_exists != 2) {
335		ZEND_CLOSURE_PROPERTY_ERROR();
336	}
337	return 0;
338}
339/* }}} */
340
341static void zend_closure_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */
342{
343	ZEND_CLOSURE_PROPERTY_ERROR();
344}
345/* }}} */
346
347static void zend_closure_free_storage(zend_object *object) /* {{{ */
348{
349	zend_closure *closure = (zend_closure *)object;
350
351	zend_object_std_dtor(&closure->std);
352
353	if (closure->func.type == ZEND_USER_FUNCTION) {
354		if (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA) {
355			efree(closure->func.op_array.run_time_cache);
356			closure->func.op_array.run_time_cache = NULL;
357		}
358		destroy_op_array(&closure->func.op_array);
359	}
360
361	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
362		zval_ptr_dtor(&closure->this_ptr);
363	}
364}
365/* }}} */
366
367static zend_object *zend_closure_new(zend_class_entry *class_type) /* {{{ */
368{
369	zend_closure *closure;
370
371	closure = emalloc(sizeof(zend_closure));
372	memset(closure, 0, sizeof(zend_closure));
373
374	zend_object_std_init(&closure->std, class_type);
375	closure->std.handlers = &closure_handlers;
376
377	return (zend_object*)closure;
378}
379/* }}} */
380
381static zend_object *zend_closure_clone(zval *zobject) /* {{{ */
382{
383	zend_closure *closure = (zend_closure *)Z_OBJ_P(zobject);
384	zval result;
385
386	zend_create_closure(&result, &closure->func,
387		closure->func.common.scope, closure->called_scope, &closure->this_ptr);
388	return Z_OBJ(result);
389}
390/* }}} */
391
392int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
393{
394	zend_closure *closure;
395
396	if (Z_TYPE_P(obj) != IS_OBJECT) {
397		return FAILURE;
398	}
399
400	closure = (zend_closure *)Z_OBJ_P(obj);
401	*fptr_ptr = &closure->func;
402	*ce_ptr = closure->called_scope;
403
404	if (obj_ptr) {
405		if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
406			*obj_ptr = Z_OBJ(closure->this_ptr);
407		} else {
408			*obj_ptr = NULL;
409		}
410	}
411	return SUCCESS;
412}
413/* }}} */
414
415static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ */
416{
417	zend_closure *closure = (zend_closure *)Z_OBJ_P(object);
418	zval val;
419	struct _zend_arg_info *arg_info = closure->func.common.arg_info;
420	HashTable *debug_info;
421
422	*is_temp = 1;
423
424	ALLOC_HASHTABLE(debug_info);
425	zend_hash_init(debug_info, 8, NULL, ZVAL_PTR_DTOR, 0);
426
427	if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
428		HashTable *static_variables = closure->func.op_array.static_variables;
429		ZVAL_ARR(&val, zend_array_dup(static_variables));
430		zend_hash_str_update(debug_info, "static", sizeof("static")-1, &val);
431	}
432
433	if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
434		Z_ADDREF(closure->this_ptr);
435		zend_hash_str_update(debug_info, "this", sizeof("this")-1, &closure->this_ptr);
436	}
437
438	if (arg_info &&
439		(closure->func.common.num_args ||
440		 (closure->func.common.fn_flags & ZEND_ACC_VARIADIC))) {
441		uint32_t i, num_args, required = closure->func.common.required_num_args;
442
443		array_init(&val);
444
445		num_args = closure->func.common.num_args;
446		if (closure->func.common.fn_flags & ZEND_ACC_VARIADIC) {
447			num_args++;
448		}
449		for (i = 0; i < num_args; i++) {
450			zend_string *name;
451			zval info;
452			if (arg_info->name) {
453				name = zend_strpprintf(0, "%s$%s",
454						arg_info->pass_by_reference ? "&" : "",
455						ZSTR_VAL(arg_info->name));
456			} else {
457				name = zend_strpprintf(0, "%s$param%d",
458						arg_info->pass_by_reference ? "&" : "",
459						i + 1);
460			}
461			ZVAL_NEW_STR(&info, zend_strpprintf(0, "%s", i >= required ? "<optional>" : "<required>"));
462			zend_hash_update(Z_ARRVAL(val), name, &info);
463			zend_string_release(name);
464			arg_info++;
465		}
466		zend_hash_str_update(debug_info, "parameter", sizeof("parameter")-1, &val);
467	}
468
469	return debug_info;
470}
471/* }}} */
472
473static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n) /* {{{ */
474{
475	zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
476
477	*table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL;
478	*n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0;
479	return (closure->func.type == ZEND_USER_FUNCTION) ?
480		closure->func.op_array.static_variables : NULL;
481}
482/* }}} */
483
484/* {{{ proto Closure::__construct()
485   Private constructor preventing instantiation */
486ZEND_COLD ZEND_METHOD(Closure, __construct)
487{
488	zend_throw_error(NULL, "Instantiation of 'Closure' is not allowed");
489}
490/* }}} */
491
492ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
493	ZEND_ARG_INFO(0, newthis)
494	ZEND_ARG_INFO(0, newscope)
495ZEND_END_ARG_INFO()
496
497ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
498	ZEND_ARG_INFO(0, closure)
499	ZEND_ARG_INFO(0, newthis)
500	ZEND_ARG_INFO(0, newscope)
501ZEND_END_ARG_INFO()
502
503ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_call, 0, 0, 1)
504	ZEND_ARG_INFO(0, newthis)
505	ZEND_ARG_VARIADIC_INFO(0, parameters)
506ZEND_END_ARG_INFO()
507
508static const zend_function_entry closure_functions[] = {
509	ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
510	ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
511	ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
512	ZEND_ME(Closure, call, arginfo_closure_call, ZEND_ACC_PUBLIC)
513	ZEND_FE_END
514};
515
516void zend_register_closure_ce(void) /* {{{ */
517{
518	zend_class_entry ce;
519
520	INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
521	zend_ce_closure = zend_register_internal_class(&ce);
522	zend_ce_closure->ce_flags |= ZEND_ACC_FINAL;
523	zend_ce_closure->create_object = zend_closure_new;
524	zend_ce_closure->serialize = zend_class_serialize_deny;
525	zend_ce_closure->unserialize = zend_class_unserialize_deny;
526
527	memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
528	closure_handlers.free_obj = zend_closure_free_storage;
529	closure_handlers.clone_obj = NULL;
530	closure_handlers.get_constructor = zend_closure_get_constructor;
531	closure_handlers.get_method = zend_closure_get_method;
532	closure_handlers.write_property = zend_closure_write_property;
533	closure_handlers.read_property = zend_closure_read_property;
534	closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
535	closure_handlers.has_property = zend_closure_has_property;
536	closure_handlers.unset_property = zend_closure_unset_property;
537	closure_handlers.compare_objects = zend_closure_compare_objects;
538	closure_handlers.clone_obj = zend_closure_clone;
539	closure_handlers.get_debug_info = zend_closure_get_debug_info;
540	closure_handlers.get_closure = zend_closure_get_closure;
541	closure_handlers.get_gc = zend_closure_get_gc;
542}
543/* }}} */
544
545static void zend_closure_internal_handler(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
546{
547	zend_closure *closure = (zend_closure*)EX(func)->common.prototype;
548	closure->orig_internal_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
549	OBJ_RELEASE((zend_object*)closure);
550	EX(func) = NULL;
551}
552/* }}} */
553
554ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
555{
556	zend_closure *closure;
557
558	object_init_ex(res, zend_ce_closure);
559
560	closure = (zend_closure *)Z_OBJ_P(res);
561
562	if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) {
563		/* use dummy scope if we're binding an object without specifying a scope */
564		/* maybe it would be better to create one for this purpose */
565		scope = zend_ce_closure;
566	}
567
568	if (func->type == ZEND_USER_FUNCTION) {
569		memcpy(&closure->func, func, sizeof(zend_op_array));
570		closure->func.common.prototype = (zend_function*)closure;
571		closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
572		if (closure->func.op_array.static_variables) {
573			closure->func.op_array.static_variables =
574				zend_array_dup(closure->func.op_array.static_variables);
575		}
576		if (UNEXPECTED(!closure->func.op_array.run_time_cache)) {
577			closure->func.op_array.run_time_cache = func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
578			memset(func->op_array.run_time_cache, 0, func->op_array.cache_size);
579		}
580		if (closure->func.op_array.refcount) {
581			(*closure->func.op_array.refcount)++;
582		}
583	} else {
584		memcpy(&closure->func, func, sizeof(zend_internal_function));
585		closure->func.common.prototype = (zend_function*)closure;
586		closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
587		/* wrap internal function handler to avoid memory leak */
588		if (UNEXPECTED(closure->func.internal_function.handler == zend_closure_internal_handler)) {
589			/* avoid infinity recursion, by taking handler from nested closure */
590			zend_closure *nested = (zend_closure*)((char*)func - XtOffsetOf(zend_closure, func));
591			ZEND_ASSERT(nested->std.ce == zend_ce_closure);
592			closure->orig_internal_handler = nested->orig_internal_handler;
593		} else {
594			closure->orig_internal_handler = closure->func.internal_function.handler;
595		}
596		closure->func.internal_function.handler = zend_closure_internal_handler;
597		if (!func->common.scope) {
598			/* if it's a free function, we won't set scope & this since they're meaningless */
599			this_ptr = NULL;
600			scope = NULL;
601		}
602	}
603
604	ZVAL_UNDEF(&closure->this_ptr);
605	/* Invariant:
606	 * If the closure is unscoped or static, it has no bound object. */
607	closure->func.common.scope = scope;
608	closure->called_scope = called_scope;
609	if (scope) {
610		closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
611		if (this_ptr && Z_TYPE_P(this_ptr) == IS_OBJECT && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
612			ZVAL_COPY(&closure->this_ptr, this_ptr);
613		}
614	}
615}
616/* }}} */
617
618ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
619{
620	zend_closure *closure;
621
622	zend_create_closure(res, func, scope, called_scope, this_ptr);
623
624	closure = (zend_closure *)Z_OBJ_P(res);
625	closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE;
626}
627/* }}} */
628
629void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var) /* {{{ */
630{
631	zend_closure *closure = (zend_closure *) Z_OBJ_P(closure_zv);
632	HashTable *static_variables = closure->func.op_array.static_variables;
633	zend_hash_update(static_variables, var_name, var);
634}
635/* }}} */
636
637/*
638 * Local variables:
639 * tab-width: 4
640 * c-basic-offset: 4
641 * indent-tabs-mode: t
642 * End:
643 */
644