@@ -127,9 +127,19 @@ ZEND_METHOD(Closure, call)
127
127
my_function .common .scope = Z_OBJCE_P (newthis );
128
128
fci_cache .function_handler = & my_function ;
129
129
130
+ /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
131
+ if (ZEND_USER_CODE (my_function .type ) && closure -> func .common .scope != Z_OBJCE_P (newthis )) {
132
+ my_function .op_array .run_time_cache = emalloc (my_function .op_array .cache_size );
133
+ memset (my_function .op_array .run_time_cache , 0 , my_function .op_array .cache_size );
134
+ }
135
+
130
136
if (zend_call_function (& fci , & fci_cache ) == SUCCESS && Z_TYPE (closure_result ) != IS_UNDEF ) {
131
137
ZVAL_COPY_VALUE (return_value , & closure_result );
132
138
}
139
+
140
+ if (ZEND_USER_CODE (my_function .type ) && closure -> func .common .scope != Z_OBJCE_P (newthis )) {
141
+ efree (my_function .op_array .run_time_cache );
142
+ }
133
143
}
134
144
/* }}} */
135
145
@@ -138,7 +148,7 @@ ZEND_METHOD(Closure, call)
138
148
ZEND_METHOD (Closure , bind )
139
149
{
140
150
zval * newthis , * zclosure , * scope_arg = NULL ;
141
- zend_closure * closure ;
151
+ zend_closure * closure , * new_closure ;
142
152
zend_class_entry * ce , * called_scope ;
143
153
144
154
if (zend_parse_method_parameters (ZEND_NUM_ARGS (), getThis (), "Oo!|z" , & zclosure , zend_ce_closure , & newthis , & scope_arg ) == FAILURE ) {
@@ -183,6 +193,15 @@ ZEND_METHOD(Closure, bind)
183
193
}
184
194
185
195
zend_create_closure (return_value , & closure -> func , ce , called_scope , newthis );
196
+ new_closure = (zend_closure * ) Z_OBJ_P (return_value );
197
+
198
+ /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
199
+ 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 ))) {
200
+ new_closure -> func .op_array .run_time_cache = emalloc (new_closure -> func .op_array .cache_size );
201
+ memset (new_closure -> func .op_array .run_time_cache , 0 , new_closure -> func .op_array .cache_size );
202
+
203
+ new_closure -> func .op_array .fn_flags |= ZEND_ACC_NO_RT_ARENA ;
204
+ }
186
205
}
187
206
/* }}} */
188
207
@@ -297,6 +316,10 @@ static void zend_closure_free_storage(zend_object *object) /* {{{ */
297
316
zend_object_std_dtor (& closure -> std );
298
317
299
318
if (closure -> func .type == ZEND_USER_FUNCTION ) {
319
+ if (closure -> func .op_array .fn_flags & ZEND_ACC_NO_RT_ARENA ) {
320
+ efree (closure -> func .op_array .run_time_cache );
321
+ closure -> func .op_array .run_time_cache = NULL ;
322
+ }
300
323
destroy_op_array (& closure -> func .op_array );
301
324
}
302
325
@@ -510,7 +533,10 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent
510
533
zend_hash_init (closure -> func .op_array .static_variables , zend_hash_num_elements (static_variables ), NULL , ZVAL_PTR_DTOR , 0 );
511
534
zend_hash_apply_with_arguments (static_variables , zval_copy_static_var , 1 , closure -> func .op_array .static_variables );
512
535
}
513
- closure -> func .op_array .run_time_cache = NULL ;
536
+ if (UNEXPECTED (!closure -> func .op_array .run_time_cache )) {
537
+ closure -> func .op_array .run_time_cache = func -> op_array .run_time_cache = zend_arena_alloc (& CG (arena ), func -> op_array .cache_size );
538
+ memset (func -> op_array .run_time_cache , 0 , func -> op_array .cache_size );
539
+ }
514
540
if (closure -> func .op_array .refcount ) {
515
541
(* closure -> func .op_array .refcount )++ ;
516
542
}
0 commit comments