1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include <stdio.h>
22 #include <signal.h>
23
24 #include "zend.h"
25 #include "zend_compile.h"
26 #include "zend_execute.h"
27 #include "zend_API.h"
28 #include "zend_stack.h"
29 #include "zend_constants.h"
30 #include "zend_extensions.h"
31 #include "zend_exceptions.h"
32 #include "zend_closures.h"
33 #include "zend_generators.h"
34 #include "zend_vm.h"
35 #include "zend_float.h"
36 #include "zend_fibers.h"
37 #include "zend_weakrefs.h"
38 #include "zend_inheritance.h"
39 #include "zend_observer.h"
40 #include "zend_call_stack.h"
41 #include "zend_frameless_function.h"
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #ifdef ZEND_MAX_EXECUTION_TIMERS
49 #include <sys/syscall.h>
50 #endif
51
52 ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
53 ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
54 ZEND_API zend_class_entry *(*zend_autoload)(zend_string *name, zend_string *lc_name);
55
56 /* true globals */
57 ZEND_API const zend_fcall_info empty_fcall_info = {0};
58 ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = {0};
59
60 #ifdef ZEND_WIN32
61 ZEND_TLS HANDLE tq_timer = NULL;
62 #endif
63
64 #if 0&&ZEND_DEBUG
65 static void (*original_sigsegv_handler)(int);
66 static void zend_handle_sigsegv(void) /* {{{ */
67 {
68 fflush(stdout);
69 fflush(stderr);
70 if (original_sigsegv_handler == zend_handle_sigsegv) {
71 signal(SIGSEGV, original_sigsegv_handler);
72 } else {
73 signal(SIGSEGV, SIG_DFL);
74 }
75 {
76
77 fprintf(stderr, "SIGSEGV caught on opcode %d on opline %d of %s() at %s:%d\n\n",
78 active_opline->opcode,
79 active_opline-EG(active_op_array)->opcodes,
80 get_active_function_name(),
81 zend_get_executed_filename(),
82 zend_get_executed_lineno());
83 /* See http://support.microsoft.com/kb/190351 */
84 #ifdef ZEND_WIN32
85 fflush(stderr);
86 #endif
87 }
88 if (original_sigsegv_handler!=zend_handle_sigsegv) {
89 original_sigsegv_handler(dummy);
90 }
91 }
92 /* }}} */
93 #endif
94
zend_extension_activator(zend_extension * extension)95 static void zend_extension_activator(zend_extension *extension) /* {{{ */
96 {
97 if (extension->activate) {
98 extension->activate();
99 }
100 }
101 /* }}} */
102
zend_extension_deactivator(zend_extension * extension)103 static void zend_extension_deactivator(zend_extension *extension) /* {{{ */
104 {
105 if (extension->deactivate) {
106 extension->deactivate();
107 }
108 }
109 /* }}} */
110
clean_non_persistent_constant_full(zval * zv)111 static int clean_non_persistent_constant_full(zval *zv) /* {{{ */
112 {
113 zend_constant *c = Z_PTR_P(zv);
114 return (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
115 }
116 /* }}} */
117
clean_non_persistent_function_full(zval * zv)118 static int clean_non_persistent_function_full(zval *zv) /* {{{ */
119 {
120 zend_function *function = Z_PTR_P(zv);
121 return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
122 }
123 /* }}} */
124
clean_non_persistent_class_full(zval * zv)125 static int clean_non_persistent_class_full(zval *zv) /* {{{ */
126 {
127 zend_class_entry *ce = Z_PTR_P(zv);
128 return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
129 }
130 /* }}} */
131
init_executor(void)132 void init_executor(void) /* {{{ */
133 {
134 zend_init_fpu();
135
136 ZVAL_NULL(&EG(uninitialized_zval));
137 ZVAL_ERROR(&EG(error_zval));
138 /* destroys stack frame, therefore makes core dumps worthless */
139 #if 0&&ZEND_DEBUG
140 original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
141 #endif
142
143 EG(symtable_cache_ptr) = EG(symtable_cache);
144 EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE;
145 EG(no_extensions) = 0;
146
147 EG(function_table) = CG(function_table);
148 EG(class_table) = CG(class_table);
149
150 EG(in_autoload) = NULL;
151 EG(error_handling) = EH_NORMAL;
152 EG(flags) = EG_FLAGS_INITIAL;
153
154 zend_vm_stack_init();
155
156 zend_hash_init(&EG(symbol_table), 64, NULL, ZVAL_PTR_DTOR, 0);
157
158 zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator);
159
160 zend_hash_init(&EG(included_files), 8, NULL, NULL, 0);
161
162 EG(ticks_count) = 0;
163
164 ZVAL_UNDEF(&EG(user_error_handler));
165 ZVAL_UNDEF(&EG(user_exception_handler));
166
167 EG(current_execute_data) = NULL;
168
169 zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int));
170 zend_stack_init(&EG(user_error_handlers), sizeof(zval));
171 zend_stack_init(&EG(user_exception_handlers), sizeof(zval));
172
173 zend_objects_store_init(&EG(objects_store), 1024);
174 zend_lazy_objects_init(&EG(lazy_objects_store));
175
176 EG(full_tables_cleanup) = 0;
177 ZEND_ATOMIC_BOOL_INIT(&EG(vm_interrupt), false);
178 ZEND_ATOMIC_BOOL_INIT(&EG(timed_out), false);
179
180 EG(exception) = NULL;
181 EG(prev_exception) = NULL;
182
183 EG(fake_scope) = NULL;
184 EG(trampoline).common.function_name = NULL;
185
186 EG(ht_iterators_count) = sizeof(EG(ht_iterators_slots)) / sizeof(HashTableIterator);
187 EG(ht_iterators_used) = 0;
188 EG(ht_iterators) = EG(ht_iterators_slots);
189 memset(EG(ht_iterators), 0, sizeof(EG(ht_iterators_slots)));
190
191 EG(persistent_constants_count) = EG(zend_constants)->nNumUsed;
192 EG(persistent_functions_count) = EG(function_table)->nNumUsed;
193 EG(persistent_classes_count) = EG(class_table)->nNumUsed;
194
195 EG(get_gc_buffer).start = EG(get_gc_buffer).end = EG(get_gc_buffer).cur = NULL;
196
197 EG(record_errors) = false;
198 EG(num_errors) = 0;
199 EG(errors) = NULL;
200
201 EG(filename_override) = NULL;
202 EG(lineno_override) = -1;
203
204 zend_max_execution_timer_init();
205 zend_fiber_init();
206 zend_weakrefs_init();
207
208 EG(active) = 1;
209 }
210 /* }}} */
211
zval_call_destructor(zval * zv)212 static int zval_call_destructor(zval *zv) /* {{{ */
213 {
214 if (Z_TYPE_P(zv) == IS_INDIRECT) {
215 zv = Z_INDIRECT_P(zv);
216 }
217 if (Z_TYPE_P(zv) == IS_OBJECT && Z_REFCOUNT_P(zv) == 1) {
218 return ZEND_HASH_APPLY_REMOVE;
219 } else {
220 return ZEND_HASH_APPLY_KEEP;
221 }
222 }
223 /* }}} */
224
zend_unclean_zval_ptr_dtor(zval * zv)225 static void zend_unclean_zval_ptr_dtor(zval *zv) /* {{{ */
226 {
227 if (Z_TYPE_P(zv) == IS_INDIRECT) {
228 zv = Z_INDIRECT_P(zv);
229 }
230 i_zval_ptr_dtor(zv);
231 }
232 /* }}} */
233
zend_throw_or_error(int fetch_type,zend_class_entry * exception_ce,const char * format,...)234 static ZEND_COLD void zend_throw_or_error(int fetch_type, zend_class_entry *exception_ce, const char *format, ...) /* {{{ */
235 {
236 va_list va;
237 char *message = NULL;
238
239 va_start(va, format);
240 zend_vspprintf(&message, 0, format, va);
241
242 if (fetch_type & ZEND_FETCH_CLASS_EXCEPTION) {
243 zend_throw_error(exception_ce, "%s", message);
244 } else {
245 zend_error_noreturn(E_ERROR, "%s", message);
246 }
247
248 efree(message);
249 va_end(va);
250 }
251 /* }}} */
252
shutdown_destructors(void)253 void shutdown_destructors(void) /* {{{ */
254 {
255 if (CG(unclean_shutdown)) {
256 EG(symbol_table).pDestructor = zend_unclean_zval_ptr_dtor;
257 }
258 zend_try {
259 uint32_t symbols;
260 do {
261 symbols = zend_hash_num_elements(&EG(symbol_table));
262 zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor);
263 } while (symbols != zend_hash_num_elements(&EG(symbol_table)));
264 zend_objects_store_call_destructors(&EG(objects_store));
265 } zend_catch {
266 /* if we couldn't destruct cleanly, mark all objects as destructed anyway */
267 zend_objects_store_mark_destructed(&EG(objects_store));
268 } zend_end_try();
269 }
270 /* }}} */
271
272 /* Free values held by the executor. */
zend_shutdown_executor_values(bool fast_shutdown)273 ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
274 {
275 zend_string *key;
276 zval *zv;
277
278 EG(flags) |= EG_FLAGS_IN_RESOURCE_SHUTDOWN;
279 zend_try {
280 zend_close_rsrc_list(&EG(regular_list));
281 } zend_end_try();
282
283 /* No PHP callback functions should be called after this point. */
284 EG(active) = 0;
285
286 if (!fast_shutdown) {
287 zend_hash_graceful_reverse_destroy(&EG(symbol_table));
288
289 /* Constants may contain objects, destroy them before the object store. */
290 if (EG(full_tables_cleanup)) {
291 zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
292 } else {
293 ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
294 zend_constant *c = Z_PTR_P(zv);
295 if (_idx == EG(persistent_constants_count)) {
296 break;
297 }
298 zval_ptr_dtor_nogc(&c->value);
299 if (c->name) {
300 zend_string_release_ex(c->name, 0);
301 }
302 efree(c);
303 zend_string_release_ex(key, 0);
304 } ZEND_HASH_MAP_FOREACH_END_DEL();
305 }
306
307 /* Release static properties and static variables prior to the final GC run,
308 * as they may hold GC roots. */
309 ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(function_table), zv) {
310 zend_op_array *op_array = Z_PTR_P(zv);
311 if (op_array->type == ZEND_INTERNAL_FUNCTION) {
312 break;
313 }
314 if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
315 HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
316 if (ht) {
317 zend_array_destroy(ht);
318 ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
319 }
320 }
321 } ZEND_HASH_FOREACH_END();
322 ZEND_HASH_MAP_REVERSE_FOREACH_VAL(EG(class_table), zv) {
323 zend_class_entry *ce = Z_PTR_P(zv);
324
325 if (ce->default_static_members_count) {
326 zend_cleanup_internal_class_data(ce);
327 }
328
329 if (ZEND_MAP_PTR(ce->mutable_data)) {
330 if (ZEND_MAP_PTR_GET_IMM(ce->mutable_data)) {
331 zend_cleanup_mutable_class_data(ce);
332 }
333 } else if (ce->type == ZEND_USER_CLASS && !(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
334 /* Constants may contain objects, destroy the values before the object store. */
335 zend_class_constant *c;
336 ZEND_HASH_MAP_FOREACH_PTR(&ce->constants_table, c) {
337 if (c->ce == ce) {
338 zval_ptr_dtor_nogc(&c->value);
339 ZVAL_UNDEF(&c->value);
340 }
341 } ZEND_HASH_FOREACH_END();
342
343 /* properties may contain objects as well */
344 if (ce->default_properties_table) {
345 zval *p = ce->default_properties_table;
346 zval *end = p + ce->default_properties_count;
347
348 while (p != end) {
349 i_zval_ptr_dtor(p);
350 ZVAL_UNDEF(p);
351 p++;
352 }
353 }
354 }
355
356 if (ce->type == ZEND_USER_CLASS && ce->backed_enum_table) {
357 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
358 zend_hash_release(ce->backed_enum_table);
359 ce->backed_enum_table = NULL;
360 }
361
362 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
363 zend_op_array *op_array;
364 ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
365 if (op_array->type == ZEND_USER_FUNCTION) {
366 if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
367 HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
368 if (ht) {
369 zend_array_destroy(ht);
370 ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
371 }
372 }
373 }
374 } ZEND_HASH_FOREACH_END();
375
376 if (ce->num_hooked_props) {
377 zend_property_info *prop_info;
378 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop_info) {
379 if (prop_info->ce == ce) {
380 if (prop_info->hooks) {
381 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
382 if (prop_info->hooks[i]) {
383 ZEND_ASSERT(ZEND_USER_CODE(prop_info->hooks[i]->type));
384 op_array = &prop_info->hooks[i]->op_array;
385 if (ZEND_MAP_PTR(op_array->static_variables_ptr)) {
386 HashTable *ht = ZEND_MAP_PTR_GET(op_array->static_variables_ptr);
387 if (ht) {
388 zend_array_destroy(ht);
389 ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
390 }
391 }
392 }
393 }
394 }
395 }
396 } ZEND_HASH_FOREACH_END();
397 }
398 }
399 } ZEND_HASH_FOREACH_END();
400
401 /* Also release error and exception handlers, which may hold objects. */
402 if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
403 zval_ptr_dtor(&EG(user_error_handler));
404 ZVAL_UNDEF(&EG(user_error_handler));
405 }
406
407 if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
408 zval_ptr_dtor(&EG(user_exception_handler));
409 ZVAL_UNDEF(&EG(user_exception_handler));
410 }
411
412 zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
413 zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
414 zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
415
416 #if ZEND_DEBUG
417 if (!CG(unclean_shutdown)) {
418 gc_collect_cycles();
419 }
420 #endif
421 } else {
422 zend_hash_discard(EG(zend_constants), EG(persistent_constants_count));
423 }
424
425 zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
426 }
427
shutdown_executor(void)428 void shutdown_executor(void) /* {{{ */
429 {
430 zend_string *key;
431 zval *zv;
432 #if ZEND_DEBUG
433 bool fast_shutdown = 0;
434 #else
435 bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
436 #endif
437
438 zend_try {
439 zend_stream_shutdown();
440 } zend_end_try();
441
442 zend_shutdown_executor_values(fast_shutdown);
443
444 zend_weakrefs_shutdown();
445 zend_max_execution_timer_shutdown();
446 zend_fiber_shutdown();
447
448 zend_try {
449 zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
450 } zend_end_try();
451
452 if (fast_shutdown) {
453 /* Fast Request Shutdown
454 * =====================
455 * Zend Memory Manager frees memory by its own. We don't have to free
456 * each allocated block separately.
457 */
458 zend_hash_discard(EG(function_table), EG(persistent_functions_count));
459 zend_hash_discard(EG(class_table), EG(persistent_classes_count));
460 } else {
461 zend_vm_stack_destroy();
462
463 if (EG(full_tables_cleanup)) {
464 zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
465 zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
466 } else {
467 ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
468 zend_function *func = Z_PTR_P(zv);
469 if (_idx == EG(persistent_functions_count)) {
470 break;
471 }
472 destroy_op_array(&func->op_array);
473 zend_string_release_ex(key, 0);
474 } ZEND_HASH_MAP_FOREACH_END_DEL();
475
476 ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
477 if (_idx == EG(persistent_classes_count)) {
478 break;
479 }
480 destroy_zend_class(zv);
481 zend_string_release_ex(key, 0);
482 } ZEND_HASH_MAP_FOREACH_END_DEL();
483 }
484
485 while (EG(symtable_cache_ptr) > EG(symtable_cache)) {
486 EG(symtable_cache_ptr)--;
487 zend_hash_destroy(*EG(symtable_cache_ptr));
488 FREE_HASHTABLE(*EG(symtable_cache_ptr));
489 }
490
491 zend_hash_destroy(&EG(included_files));
492
493 zend_stack_destroy(&EG(user_error_handlers_error_reporting));
494 zend_stack_destroy(&EG(user_error_handlers));
495 zend_stack_destroy(&EG(user_exception_handlers));
496 zend_lazy_objects_destroy(&EG(lazy_objects_store));
497 zend_objects_store_destroy(&EG(objects_store));
498 if (EG(in_autoload)) {
499 zend_hash_destroy(EG(in_autoload));
500 FREE_HASHTABLE(EG(in_autoload));
501 }
502
503 if (EG(ht_iterators) != EG(ht_iterators_slots)) {
504 efree(EG(ht_iterators));
505 }
506 }
507
508 #if ZEND_DEBUG
509 if (EG(ht_iterators_used) && !CG(unclean_shutdown)) {
510 zend_error(E_WARNING, "Leaked %" PRIu32 " hashtable iterators", EG(ht_iterators_used));
511 }
512 #endif
513
514 /* Check whether anyone is hogging the trampoline. */
515 ZEND_ASSERT(EG(trampoline).common.function_name == NULL || CG(unclean_shutdown));
516
517 EG(ht_iterators_used) = 0;
518
519 zend_shutdown_fpu();
520 }
521 /* }}} */
522
523 /* return class name and "::" or "". */
get_active_class_name(const char ** space)524 ZEND_API const char *get_active_class_name(const char **space) /* {{{ */
525 {
526 zend_function *func;
527
528 if (!zend_is_executing()) {
529 if (space) {
530 *space = "";
531 }
532 return "";
533 }
534
535 func = zend_active_function();
536
537 switch (func->type) {
538 case ZEND_USER_FUNCTION:
539 case ZEND_INTERNAL_FUNCTION:
540 {
541 zend_class_entry *ce = func->common.scope;
542
543 if (space) {
544 *space = ce ? "::" : "";
545 }
546 return ce ? ZSTR_VAL(ce->name) : "";
547 }
548 default:
549 if (space) {
550 *space = "";
551 }
552 return "";
553 }
554 }
555 /* }}} */
556
get_active_function_name(void)557 ZEND_API const char *get_active_function_name(void) /* {{{ */
558 {
559 zend_function *func;
560
561 if (!zend_is_executing()) {
562 return NULL;
563 }
564
565 func = zend_active_function();
566
567 switch (func->type) {
568 case ZEND_USER_FUNCTION: {
569 zend_string *function_name = func->common.function_name;
570
571 if (function_name) {
572 return ZSTR_VAL(function_name);
573 } else {
574 return "main";
575 }
576 }
577 break;
578 case ZEND_INTERNAL_FUNCTION:
579 return ZSTR_VAL(func->common.function_name);
580 break;
581 default:
582 return NULL;
583 }
584 }
585 /* }}} */
586
zend_active_function_ex(zend_execute_data * execute_data)587 ZEND_API zend_function *zend_active_function_ex(zend_execute_data *execute_data)
588 {
589 zend_function *func = EX(func);
590
591 /* Resolve function if op is a frameless call. */
592 if (ZEND_USER_CODE(func->type)) {
593 const zend_op *op = EX(opline);
594 if (ZEND_OP_IS_FRAMELESS_ICALL(op->opcode)) {
595 func = ZEND_FLF_FUNC(op);
596 }
597 }
598
599 return func;
600 }
601
get_active_function_or_method_name(void)602 ZEND_API zend_string *get_active_function_or_method_name(void) /* {{{ */
603 {
604 ZEND_ASSERT(zend_is_executing());
605
606 return get_function_or_method_name(zend_active_function());
607 }
608 /* }}} */
609
get_function_or_method_name(const zend_function * func)610 ZEND_API zend_string *get_function_or_method_name(const zend_function *func) /* {{{ */
611 {
612 if (func->common.scope && func->common.function_name) {
613 return zend_create_member_string(func->common.scope->name, func->common.function_name);
614 }
615
616 return func->common.function_name ? zend_string_copy(func->common.function_name) : ZSTR_INIT_LITERAL("main", 0);
617 }
618 /* }}} */
619
get_active_function_arg_name(uint32_t arg_num)620 ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */
621 {
622 if (!zend_is_executing()) {
623 return NULL;
624 }
625
626 zend_function *func = zend_active_function();
627
628 return get_function_arg_name(func, arg_num);
629 }
630 /* }}} */
631
get_function_arg_name(const zend_function * func,uint32_t arg_num)632 ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num) /* {{{ */
633 {
634 if (!func || arg_num == 0 || func->common.num_args < arg_num) {
635 return NULL;
636 }
637
638 if (func->type == ZEND_USER_FUNCTION || (func->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
639 return ZSTR_VAL(func->common.arg_info[arg_num - 1].name);
640 } else {
641 return ((zend_internal_arg_info*) func->common.arg_info)[arg_num - 1].name;
642 }
643 }
644 /* }}} */
645
zend_get_executed_filename(void)646 ZEND_API const char *zend_get_executed_filename(void) /* {{{ */
647 {
648 zend_string *filename = zend_get_executed_filename_ex();
649 return filename != NULL ? ZSTR_VAL(filename) : "[no active file]";
650 }
651 /* }}} */
652
zend_get_executed_filename_ex(void)653 ZEND_API zend_string *zend_get_executed_filename_ex(void) /* {{{ */
654 {
655 zend_string *filename_override = EG(filename_override);
656 if (filename_override != NULL) {
657 return filename_override;
658 }
659
660 zend_execute_data *ex = EG(current_execute_data);
661
662 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
663 ex = ex->prev_execute_data;
664 }
665 if (ex) {
666 return ex->func->op_array.filename;
667 } else {
668 return NULL;
669 }
670 }
671 /* }}} */
672
zend_get_executed_lineno(void)673 ZEND_API uint32_t zend_get_executed_lineno(void) /* {{{ */
674 {
675 zend_long lineno_override = EG(lineno_override);
676 if (lineno_override != -1) {
677 return lineno_override;
678 }
679
680 zend_execute_data *ex = EG(current_execute_data);
681
682 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
683 ex = ex->prev_execute_data;
684 }
685 if (ex) {
686 if (!ex->opline) {
687 /* Missing SAVE_OPLINE()? Falling back to first line of function */
688 return ex->func->op_array.opcodes[0].lineno;
689 }
690 if (EG(exception) && ex->opline->opcode == ZEND_HANDLE_EXCEPTION &&
691 ex->opline->lineno == 0 && EG(opline_before_exception)) {
692 return EG(opline_before_exception)->lineno;
693 }
694 return ex->opline->lineno;
695 } else {
696 return 0;
697 }
698 }
699 /* }}} */
700
zend_get_executed_scope(void)701 ZEND_API zend_class_entry *zend_get_executed_scope(void) /* {{{ */
702 {
703 zend_execute_data *ex = EG(current_execute_data);
704
705 while (1) {
706 if (!ex) {
707 return NULL;
708 } else if (ex->func && (ZEND_USER_CODE(ex->func->type) || ex->func->common.scope)) {
709 return ex->func->common.scope;
710 }
711 ex = ex->prev_execute_data;
712 }
713 }
714 /* }}} */
715
zend_is_executing(void)716 ZEND_API bool zend_is_executing(void) /* {{{ */
717 {
718 return EG(current_execute_data) != 0;
719 }
720 /* }}} */
721
zval_update_constant_with_ctx(zval * p,zend_class_entry * scope,zend_ast_evaluate_ctx * ctx)722 ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *p, zend_class_entry *scope, zend_ast_evaluate_ctx *ctx)
723 {
724 if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
725 zend_ast *ast = Z_ASTVAL_P(p);
726
727 if (ast->kind == ZEND_AST_CONSTANT) {
728 zend_string *name = zend_ast_get_constant_name(ast);
729 zval *zv = zend_get_constant_ex(name, scope, ast->attr);
730 if (UNEXPECTED(zv == NULL)) {
731 return FAILURE;
732 }
733
734 zval_ptr_dtor_nogc(p);
735 ZVAL_COPY_OR_DUP(p, zv);
736 } else {
737 zval tmp;
738 bool short_circuited;
739
740 // Increase the refcount during zend_ast_evaluate to avoid releasing the ast too early
741 // on nested calls to zval_update_constant_ex which can happen when retriggering ast
742 // evaluation during autoloading.
743 zend_ast_ref *ast_ref = Z_AST_P(p);
744 bool ast_is_refcounted = !(GC_FLAGS(ast_ref) & GC_IMMUTABLE);
745 if (ast_is_refcounted) {
746 GC_ADDREF(ast_ref);
747 }
748 zend_result result = zend_ast_evaluate_ex(&tmp, ast, scope, &short_circuited, ctx) != SUCCESS;
749 if (ast_is_refcounted && !GC_DELREF(ast_ref)) {
750 rc_dtor_func((zend_refcounted *)ast_ref);
751 }
752 if (UNEXPECTED(result != SUCCESS)) {
753 return FAILURE;
754 }
755 zval_ptr_dtor_nogc(p);
756 ZVAL_COPY_VALUE(p, &tmp);
757 }
758 }
759 return SUCCESS;
760 }
761 /* }}} */
762
zval_update_constant_ex(zval * p,zend_class_entry * scope)763 ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *p, zend_class_entry *scope)
764 {
765 zend_ast_evaluate_ctx ctx = {0};
766 return zval_update_constant_with_ctx(p, scope, &ctx);
767 }
768
zval_update_constant(zval * pp)769 ZEND_API zend_result ZEND_FASTCALL zval_update_constant(zval *pp) /* {{{ */
770 {
771 return zval_update_constant_ex(pp, EG(current_execute_data) ? zend_get_executed_scope() : CG(active_class_entry));
772 }
773 /* }}} */
774
_call_user_function_impl(zval * object,zval * function_name,zval * retval_ptr,uint32_t param_count,zval params[],HashTable * named_params)775 zend_result _call_user_function_impl(zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[], HashTable *named_params) /* {{{ */
776 {
777 zend_fcall_info fci;
778
779 fci.size = sizeof(fci);
780 if (object) {
781 ZEND_ASSERT(Z_TYPE_P(object) == IS_OBJECT);
782 fci.object = Z_OBJ_P(object);
783 } else {
784 fci.object = NULL;
785 }
786 ZVAL_COPY_VALUE(&fci.function_name, function_name);
787 fci.retval = retval_ptr;
788 fci.param_count = param_count;
789 fci.params = params;
790 fci.named_params = named_params;
791
792 return zend_call_function(&fci, NULL);
793 }
794 /* }}} */
795
zend_call_function(zend_fcall_info * fci,zend_fcall_info_cache * fci_cache)796 zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /* {{{ */
797 {
798 uint32_t i;
799 zend_execute_data *call;
800 zend_fcall_info_cache fci_cache_local;
801 zend_function *func;
802 uint32_t call_info;
803 void *object_or_called_scope;
804 zend_class_entry *orig_fake_scope;
805
806 ZVAL_UNDEF(fci->retval);
807
808 if (!EG(active)) {
809 return FAILURE; /* executor is already inactive */
810 }
811
812 if (EG(exception)) {
813 if (fci_cache) {
814 zend_release_fcall_info_cache(fci_cache);
815 }
816 return SUCCESS; /* we would result in an unstable executor otherwise */
817 }
818
819 ZEND_ASSERT(fci->size == sizeof(zend_fcall_info));
820
821 if (!fci_cache || !fci_cache->function_handler) {
822 char *error = NULL;
823
824 if (!fci_cache) {
825 fci_cache = &fci_cache_local;
826 }
827
828 if (!zend_is_callable_ex(&fci->function_name, fci->object, 0, NULL, fci_cache, &error)) {
829 ZEND_ASSERT(error && "Should have error if not callable");
830 zend_string *callable_name
831 = zend_get_callable_name_ex(&fci->function_name, fci->object);
832 zend_throw_error(NULL, "Invalid callback %s, %s", ZSTR_VAL(callable_name), error);
833 efree(error);
834 zend_string_release_ex(callable_name, 0);
835 return SUCCESS;
836 }
837
838 ZEND_ASSERT(!error);
839 }
840
841 func = fci_cache->function_handler;
842 if ((func->common.fn_flags & ZEND_ACC_STATIC) || !fci_cache->object) {
843 object_or_called_scope = fci_cache->called_scope;
844 call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC;
845 } else {
846 object_or_called_scope = fci_cache->object;
847 call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_HAS_THIS;
848 }
849
850 call = zend_vm_stack_push_call_frame(call_info,
851 func, fci->param_count, object_or_called_scope);
852
853 if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_DEPRECATED)) {
854 zend_deprecated_function(func);
855
856 if (UNEXPECTED(EG(exception))) {
857 zend_vm_stack_free_call_frame(call);
858 return SUCCESS;
859 }
860 }
861
862 for (i=0; i<fci->param_count; i++) {
863 zval *param = ZEND_CALL_ARG(call, i+1);
864 zval *arg = &fci->params[i];
865 bool must_wrap = 0;
866 if (UNEXPECTED(Z_ISUNDEF_P(arg))) {
867 /* Allow forwarding undef slots. This is only used by Closure::__invoke(). */
868 ZVAL_UNDEF(param);
869 ZEND_ADD_CALL_FLAG(call, ZEND_CALL_MAY_HAVE_UNDEF);
870 continue;
871 }
872
873 if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
874 if (UNEXPECTED(!Z_ISREF_P(arg))) {
875 if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
876 /* By-value send is not allowed -- emit a warning,
877 * and perform the call with the value wrapped in a reference. */
878 zend_param_must_be_ref(func, i + 1);
879 must_wrap = 1;
880 if (UNEXPECTED(EG(exception))) {
881 ZEND_CALL_NUM_ARGS(call) = i;
882 cleanup_args:
883 zend_vm_stack_free_args(call);
884 zend_vm_stack_free_call_frame(call);
885 return SUCCESS;
886 }
887 }
888 }
889 } else {
890 if (Z_ISREF_P(arg) &&
891 !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
892 /* don't separate references for __call */
893 arg = Z_REFVAL_P(arg);
894 }
895 }
896
897 if (EXPECTED(!must_wrap)) {
898 ZVAL_COPY(param, arg);
899 } else {
900 Z_TRY_ADDREF_P(arg);
901 ZVAL_NEW_REF(param, arg);
902 }
903 }
904
905 if (fci->named_params) {
906 zend_string *name;
907 zval *arg;
908 uint32_t arg_num = ZEND_CALL_NUM_ARGS(call) + 1;
909 bool have_named_params = 0;
910 ZEND_HASH_FOREACH_STR_KEY_VAL(fci->named_params, name, arg) {
911 bool must_wrap = 0;
912 zval *target;
913 if (name) {
914 void *cache_slot[2] = {NULL, NULL};
915 have_named_params = 1;
916 target = zend_handle_named_arg(&call, name, &arg_num, cache_slot);
917 if (!target) {
918 goto cleanup_args;
919 }
920 } else {
921 if (have_named_params) {
922 zend_throw_error(NULL,
923 "Cannot use positional argument after named argument");
924 goto cleanup_args;
925 }
926
927 zend_vm_stack_extend_call_frame(&call, arg_num - 1, 1);
928 target = ZEND_CALL_ARG(call, arg_num);
929 }
930
931 if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) {
932 if (UNEXPECTED(!Z_ISREF_P(arg))) {
933 if (!ARG_MAY_BE_SENT_BY_REF(func, arg_num)) {
934 /* By-value send is not allowed -- emit a warning,
935 * and perform the call with the value wrapped in a reference. */
936 zend_param_must_be_ref(func, arg_num);
937 must_wrap = 1;
938 if (UNEXPECTED(EG(exception))) {
939 goto cleanup_args;
940 }
941 }
942 }
943 } else {
944 if (Z_ISREF_P(arg) &&
945 !(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
946 /* don't separate references for __call */
947 arg = Z_REFVAL_P(arg);
948 }
949 }
950
951 if (EXPECTED(!must_wrap)) {
952 ZVAL_COPY(target, arg);
953 } else {
954 Z_TRY_ADDREF_P(arg);
955 ZVAL_NEW_REF(target, arg);
956 }
957 if (!name) {
958 ZEND_CALL_NUM_ARGS(call)++;
959 arg_num++;
960 }
961 } ZEND_HASH_FOREACH_END();
962 }
963
964 if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_MAY_HAVE_UNDEF)) {
965 /* zend_handle_undef_args assumes prev_execute_data is initialized. */
966 call->prev_execute_data = NULL;
967 if (zend_handle_undef_args(call) == FAILURE) {
968 zend_vm_stack_free_args(call);
969 zend_vm_stack_free_call_frame(call);
970 return SUCCESS;
971 }
972 }
973
974 if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
975 uint32_t call_info;
976
977 GC_ADDREF(ZEND_CLOSURE_OBJECT(func));
978 call_info = ZEND_CALL_CLOSURE;
979 if (func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
980 call_info |= ZEND_CALL_FAKE_CLOSURE;
981 }
982 ZEND_ADD_CALL_FLAG(call, call_info);
983 }
984
985 if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
986 fci_cache->function_handler = NULL;
987 }
988
989 orig_fake_scope = EG(fake_scope);
990 EG(fake_scope) = NULL;
991 if (func->type == ZEND_USER_FUNCTION) {
992 uint32_t orig_jit_trace_num = EG(jit_trace_num);
993
994 zend_init_func_execute_data(call, &func->op_array, fci->retval);
995 ZEND_OBSERVER_FCALL_BEGIN(call);
996 zend_execute_ex(call);
997 EG(jit_trace_num) = orig_jit_trace_num;
998 } else {
999 ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
1000 ZVAL_NULL(fci->retval);
1001 call->prev_execute_data = EG(current_execute_data);
1002 EG(current_execute_data) = call;
1003 #if ZEND_DEBUG
1004 bool should_throw = zend_internal_call_should_throw(func, call);
1005 #endif
1006 ZEND_OBSERVER_FCALL_BEGIN(call);
1007 if (EXPECTED(zend_execute_internal == NULL)) {
1008 /* saves one function call if zend_execute_internal is not used */
1009 func->internal_function.handler(call, fci->retval);
1010 } else {
1011 zend_execute_internal(call, fci->retval);
1012 }
1013
1014 #if ZEND_DEBUG
1015 if (!EG(exception) && call->func) {
1016 if (should_throw) {
1017 zend_internal_call_arginfo_violation(call->func);
1018 }
1019 ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
1020 zend_verify_internal_return_type(call->func, fci->retval));
1021 ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1022 ? Z_ISREF_P(fci->retval) : !Z_ISREF_P(fci->retval));
1023 }
1024 #endif
1025 ZEND_OBSERVER_FCALL_END(call, fci->retval);
1026 EG(current_execute_data) = call->prev_execute_data;
1027 zend_vm_stack_free_args(call);
1028 if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {
1029 zend_array_release(call->extra_named_params);
1030 }
1031
1032 if (EG(exception)) {
1033 zval_ptr_dtor(fci->retval);
1034 ZVAL_UNDEF(fci->retval);
1035 }
1036
1037 /* This flag is regularly checked while running user functions, but not internal
1038 * So see whether interrupt flag was set while the function was running... */
1039 if (zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false)) {
1040 if (zend_atomic_bool_load_ex(&EG(timed_out))) {
1041 zend_timeout();
1042 } else if (zend_interrupt_function) {
1043 zend_interrupt_function(EG(current_execute_data));
1044 }
1045 }
1046
1047 if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
1048 OBJ_RELEASE(Z_OBJ(call->This));
1049 }
1050 }
1051 EG(fake_scope) = orig_fake_scope;
1052
1053 zend_vm_stack_free_call_frame(call);
1054
1055 if (UNEXPECTED(EG(exception))) {
1056 if (UNEXPECTED(!EG(current_execute_data))) {
1057 zend_throw_exception_internal(NULL);
1058 } else if (EG(current_execute_data)->func &&
1059 ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
1060 zend_rethrow_exception(EG(current_execute_data));
1061 }
1062 }
1063
1064 return SUCCESS;
1065 }
1066 /* }}} */
1067
zend_call_known_function(zend_function * fn,zend_object * object,zend_class_entry * called_scope,zval * retval_ptr,uint32_t param_count,zval * params,HashTable * named_params)1068 ZEND_API void zend_call_known_function(
1069 zend_function *fn, zend_object *object, zend_class_entry *called_scope, zval *retval_ptr,
1070 uint32_t param_count, zval *params, HashTable *named_params)
1071 {
1072 zval retval;
1073 zend_fcall_info fci;
1074 zend_fcall_info_cache fcic;
1075
1076 ZEND_ASSERT(fn && "zend_function must be passed!");
1077
1078 fci.size = sizeof(fci);
1079 fci.object = object;
1080 fci.retval = retval_ptr ? retval_ptr : &retval;
1081 fci.param_count = param_count;
1082 fci.params = params;
1083 fci.named_params = named_params;
1084 ZVAL_UNDEF(&fci.function_name); /* Unused */
1085
1086 fcic.function_handler = fn;
1087 fcic.object = object;
1088 fcic.called_scope = called_scope;
1089
1090 zend_result result = zend_call_function(&fci, &fcic);
1091 if (UNEXPECTED(result == FAILURE)) {
1092 if (!EG(exception)) {
1093 zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s",
1094 fn->common.scope ? ZSTR_VAL(fn->common.scope->name) : "",
1095 fn->common.scope ? "::" : "", ZSTR_VAL(fn->common.function_name));
1096 }
1097 }
1098
1099 if (!retval_ptr) {
1100 zval_ptr_dtor(&retval);
1101 }
1102 }
1103
zend_call_known_instance_method_with_2_params(zend_function * fn,zend_object * object,zval * retval_ptr,zval * param1,zval * param2)1104 ZEND_API void zend_call_known_instance_method_with_2_params(
1105 zend_function *fn, zend_object *object, zval *retval_ptr, zval *param1, zval *param2)
1106 {
1107 zval params[2];
1108 ZVAL_COPY_VALUE(¶ms[0], param1);
1109 ZVAL_COPY_VALUE(¶ms[1], param2);
1110 zend_call_known_instance_method(fn, object, retval_ptr, 2, params);
1111 }
1112
zend_call_method_if_exists(zend_object * object,zend_string * method_name,zval * retval,uint32_t param_count,zval * params)1113 ZEND_API zend_result zend_call_method_if_exists(
1114 zend_object *object, zend_string *method_name, zval *retval,
1115 uint32_t param_count, zval *params)
1116 {
1117 zend_fcall_info fci;
1118 fci.size = sizeof(zend_fcall_info);
1119 fci.object = object;
1120 ZVAL_STR(&fci.function_name, method_name);
1121 fci.retval = retval;
1122 fci.param_count = param_count;
1123 fci.params = params;
1124 fci.named_params = NULL;
1125
1126 zend_fcall_info_cache fcc;
1127 if (!zend_is_callable_ex(&fci.function_name, fci.object, IS_CALLABLE_SUPPRESS_DEPRECATIONS, NULL, &fcc, NULL)) {
1128 ZVAL_UNDEF(retval);
1129 return FAILURE;
1130 }
1131
1132 return zend_call_function(&fci, &fcc);
1133 }
1134
1135 /* 0-9 a-z A-Z _ \ 0x80-0xff */
1136 static const uint32_t valid_chars[8] = {
1137 0x00000000,
1138 0x03ff0000,
1139 0x97fffffe,
1140 0x07fffffe,
1141 0xffffffff,
1142 0xffffffff,
1143 0xffffffff,
1144 0xffffffff,
1145 };
1146
zend_is_valid_class_name(zend_string * name)1147 ZEND_API bool zend_is_valid_class_name(zend_string *name) {
1148 for (size_t i = 0; i < ZSTR_LEN(name); i++) {
1149 unsigned char c = ZSTR_VAL(name)[i];
1150 if (!ZEND_BIT_TEST(valid_chars, c)) {
1151 return 0;
1152 }
1153 }
1154 return 1;
1155 }
1156
zend_lookup_class_ex(zend_string * name,zend_string * key,uint32_t flags)1157 ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */
1158 {
1159 zend_class_entry *ce = NULL;
1160 zval *zv;
1161 zend_string *lc_name;
1162 zend_string *autoload_name;
1163 uint32_t ce_cache = 0;
1164
1165 if (ZSTR_HAS_CE_CACHE(name) && ZSTR_VALID_CE_CACHE(name)) {
1166 ce_cache = GC_REFCOUNT(name);
1167 ce = GET_CE_CACHE(ce_cache);
1168 if (EXPECTED(ce)) {
1169 return ce;
1170 }
1171 }
1172
1173 if (key) {
1174 lc_name = key;
1175 } else {
1176 if (!ZSTR_LEN(name)) {
1177 return NULL;
1178 }
1179
1180 if (ZSTR_VAL(name)[0] == '\\') {
1181 lc_name = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1182 zend_str_tolower_copy(ZSTR_VAL(lc_name), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1183 } else {
1184 lc_name = zend_string_tolower(name);
1185 }
1186 }
1187
1188 zv = zend_hash_find(EG(class_table), lc_name);
1189 if (zv) {
1190 if (!key) {
1191 zend_string_release_ex(lc_name, 0);
1192 }
1193 ce = (zend_class_entry*)Z_PTR_P(zv);
1194 if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) {
1195 if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) ||
1196 ((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) &&
1197 (ce->ce_flags & ZEND_ACC_NEARLY_LINKED))) {
1198 if (!CG(unlinked_uses)) {
1199 ALLOC_HASHTABLE(CG(unlinked_uses));
1200 zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0);
1201 }
1202 zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(uintptr_t)ce);
1203 return ce;
1204 }
1205 return NULL;
1206 }
1207 /* Don't populate CE_CACHE for mutable classes during compilation.
1208 * The class may be freed while persisting. */
1209 if (ce_cache &&
1210 (!CG(in_compilation) || (ce->ce_flags & ZEND_ACC_IMMUTABLE))) {
1211 SET_CE_CACHE(ce_cache, ce);
1212 }
1213 return ce;
1214 }
1215
1216 /* The compiler is not-reentrant. Make sure we autoload only during run-time. */
1217 if ((flags & ZEND_FETCH_CLASS_NO_AUTOLOAD) || zend_is_compiling()) {
1218 if (!key) {
1219 zend_string_release_ex(lc_name, 0);
1220 }
1221 return NULL;
1222 }
1223
1224 if (!zend_autoload) {
1225 if (!key) {
1226 zend_string_release_ex(lc_name, 0);
1227 }
1228 return NULL;
1229 }
1230
1231 /* Verify class name before passing it to the autoloader. */
1232 if (!key && !ZSTR_HAS_CE_CACHE(name) && !zend_is_valid_class_name(name)) {
1233 zend_string_release_ex(lc_name, 0);
1234 return NULL;
1235 }
1236
1237 if (EG(in_autoload) == NULL) {
1238 ALLOC_HASHTABLE(EG(in_autoload));
1239 zend_hash_init(EG(in_autoload), 8, NULL, NULL, 0);
1240 }
1241
1242 if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) {
1243 if (!key) {
1244 zend_string_release_ex(lc_name, 0);
1245 }
1246 return NULL;
1247 }
1248
1249 if (ZSTR_VAL(name)[0] == '\\') {
1250 autoload_name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
1251 } else {
1252 autoload_name = zend_string_copy(name);
1253 }
1254
1255 zend_string *previous_filename = EG(filename_override);
1256 zend_long previous_lineno = EG(lineno_override);
1257 EG(filename_override) = NULL;
1258 EG(lineno_override) = -1;
1259 zend_exception_save();
1260 ce = zend_autoload(autoload_name, lc_name);
1261 zend_exception_restore();
1262 EG(filename_override) = previous_filename;
1263 EG(lineno_override) = previous_lineno;
1264
1265 zend_string_release_ex(autoload_name, 0);
1266 zend_hash_del(EG(in_autoload), lc_name);
1267
1268 if (!key) {
1269 zend_string_release_ex(lc_name, 0);
1270 }
1271 if (ce) {
1272 ZEND_ASSERT(!CG(in_compilation));
1273 if (ce_cache) {
1274 SET_CE_CACHE(ce_cache, ce);
1275 }
1276 }
1277 return ce;
1278 }
1279 /* }}} */
1280
zend_lookup_class(zend_string * name)1281 ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */
1282 {
1283 return zend_lookup_class_ex(name, NULL, 0);
1284 }
1285 /* }}} */
1286
zend_get_called_scope(zend_execute_data * ex)1287 ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex) /* {{{ */
1288 {
1289 while (ex) {
1290 if (Z_TYPE(ex->This) == IS_OBJECT) {
1291 return Z_OBJCE(ex->This);
1292 } else if (Z_CE(ex->This)) {
1293 return Z_CE(ex->This);
1294 } else if (ex->func) {
1295 if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
1296 return NULL;
1297 }
1298 }
1299 ex = ex->prev_execute_data;
1300 }
1301 return NULL;
1302 }
1303 /* }}} */
1304
zend_get_this_object(zend_execute_data * ex)1305 ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex) /* {{{ */
1306 {
1307 while (ex) {
1308 if (Z_TYPE(ex->This) == IS_OBJECT) {
1309 return Z_OBJ(ex->This);
1310 } else if (ex->func) {
1311 if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
1312 return NULL;
1313 }
1314 }
1315 ex = ex->prev_execute_data;
1316 }
1317 return NULL;
1318 }
1319 /* }}} */
1320
zend_eval_stringl(const char * str,size_t str_len,zval * retval_ptr,const char * string_name)1321 ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *retval_ptr, const char *string_name) /* {{{ */
1322 {
1323 zend_op_array *new_op_array;
1324 uint32_t original_compiler_options;
1325 zend_result retval;
1326 zend_string *code_str;
1327
1328 if (retval_ptr) {
1329 code_str = zend_string_concat3(
1330 "return ", sizeof("return ")-1, str, str_len, ";", sizeof(";")-1);
1331 } else {
1332 code_str = zend_string_init(str, str_len, 0);
1333 }
1334
1335 /*printf("Evaluating '%s'\n", pv.value.str.val);*/
1336
1337 original_compiler_options = CG(compiler_options);
1338 CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
1339 new_op_array = zend_compile_string(code_str, string_name, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG);
1340 CG(compiler_options) = original_compiler_options;
1341
1342 if (new_op_array) {
1343 zval local_retval;
1344
1345 EG(no_extensions)=1;
1346
1347 new_op_array->scope = zend_get_executed_scope();
1348
1349 zend_try {
1350 ZVAL_UNDEF(&local_retval);
1351 zend_execute(new_op_array, &local_retval);
1352 } zend_catch {
1353 destroy_op_array(new_op_array);
1354 efree_size(new_op_array, sizeof(zend_op_array));
1355 zend_bailout();
1356 } zend_end_try();
1357
1358 if (Z_TYPE(local_retval) != IS_UNDEF) {
1359 if (retval_ptr) {
1360 ZVAL_COPY_VALUE(retval_ptr, &local_retval);
1361 } else {
1362 zval_ptr_dtor(&local_retval);
1363 }
1364 } else {
1365 if (retval_ptr) {
1366 ZVAL_NULL(retval_ptr);
1367 }
1368 }
1369
1370 EG(no_extensions)=0;
1371 zend_destroy_static_vars(new_op_array);
1372 destroy_op_array(new_op_array);
1373 efree_size(new_op_array, sizeof(zend_op_array));
1374 retval = SUCCESS;
1375 } else {
1376 retval = FAILURE;
1377 }
1378 zend_string_release(code_str);
1379 return retval;
1380 }
1381 /* }}} */
1382
zend_eval_string(const char * str,zval * retval_ptr,const char * string_name)1383 ZEND_API zend_result zend_eval_string(const char *str, zval *retval_ptr, const char *string_name) /* {{{ */
1384 {
1385 return zend_eval_stringl(str, strlen(str), retval_ptr, string_name);
1386 }
1387 /* }}} */
1388
zend_eval_stringl_ex(const char * str,size_t str_len,zval * retval_ptr,const char * string_name,bool handle_exceptions)1389 ZEND_API zend_result zend_eval_stringl_ex(const char *str, size_t str_len, zval *retval_ptr, const char *string_name, bool handle_exceptions) /* {{{ */
1390 {
1391 zend_result result;
1392
1393 result = zend_eval_stringl(str, str_len, retval_ptr, string_name);
1394 if (handle_exceptions && EG(exception)) {
1395 result = zend_exception_error(EG(exception), E_ERROR);
1396 }
1397 return result;
1398 }
1399 /* }}} */
1400
zend_eval_string_ex(const char * str,zval * retval_ptr,const char * string_name,bool handle_exceptions)1401 ZEND_API zend_result zend_eval_string_ex(const char *str, zval *retval_ptr, const char *string_name, bool handle_exceptions) /* {{{ */
1402 {
1403 return zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
1404 }
1405 /* }}} */
1406
1407 static void zend_set_timeout_ex(zend_long seconds, bool reset_signals);
1408
zend_timeout(void)1409 ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
1410 {
1411 #if defined(PHP_WIN32)
1412 # ifndef ZTS
1413 /* No action is needed if we're timed out because zero seconds are
1414 just ignored. Also, the hard timeout needs to be respected. If the
1415 timer is not restarted properly, it could hang in the shutdown
1416 function. */
1417 if (EG(hard_timeout) > 0) {
1418 zend_atomic_bool_store_ex(&EG(timed_out), false);
1419 zend_set_timeout_ex(EG(hard_timeout), 1);
1420 /* XXX Abused, introduce an additional flag if the value needs to be kept. */
1421 EG(hard_timeout) = 0;
1422 }
1423 # endif
1424 #else
1425 zend_atomic_bool_store_ex(&EG(timed_out), false);
1426 zend_set_timeout_ex(0, 1);
1427 #endif
1428
1429 zend_error_noreturn(E_ERROR, "Maximum execution time of " ZEND_LONG_FMT " second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
1430 }
1431 /* }}} */
1432
1433 #ifndef ZEND_WIN32
1434 # ifdef ZEND_MAX_EXECUTION_TIMERS
zend_timeout_handler(int dummy,siginfo_t * si,void * uc)1435 static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */
1436 {
1437 #ifdef ZTS
1438 if (!tsrm_is_managed_thread()) {
1439 fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n");
1440
1441 return;
1442 }
1443 #endif
1444
1445 if (si->si_value.sival_ptr != &EG(max_execution_timer_timer)) {
1446 #ifdef MAX_EXECUTION_TIMERS_DEBUG
1447 fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid));
1448 #endif
1449
1450 if (EG(oldact).sa_sigaction) {
1451 EG(oldact).sa_sigaction(dummy, si, uc);
1452
1453 return;
1454 }
1455 if (EG(oldact).sa_handler) EG(oldact).sa_handler(dummy);
1456
1457 return;
1458 }
1459 # else
1460 static void zend_timeout_handler(int dummy) /* {{{ */
1461 {
1462 # endif
1463 #ifdef ZTS
1464 if (!tsrm_is_managed_thread()) {
1465 fprintf(stderr, "zend_timeout_handler() called in a thread not managed by PHP. The expected signal handler will not be called. This is probably a bug.\n");
1466
1467 return;
1468 }
1469 #else
1470 if (zend_atomic_bool_load_ex(&EG(timed_out))) {
1471 /* Die on hard timeout */
1472 const char *error_filename = NULL;
1473 uint32_t error_lineno = 0;
1474 char log_buffer[2048];
1475 int output_len = 0;
1476
1477 if (zend_is_compiling()) {
1478 error_filename = ZSTR_VAL(zend_get_compiled_filename());
1479 error_lineno = zend_get_compiled_lineno();
1480 } else if (zend_is_executing()) {
1481 error_filename = zend_get_executed_filename();
1482 if (error_filename[0] == '[') { /* [no active file] */
1483 error_filename = NULL;
1484 error_lineno = 0;
1485 } else {
1486 error_lineno = zend_get_executed_lineno();
1487 }
1488 }
1489 if (!error_filename) {
1490 error_filename = "Unknown";
1491 }
1492
1493 output_len = snprintf(log_buffer, sizeof(log_buffer), "\nFatal error: Maximum execution time of " ZEND_LONG_FMT "+" ZEND_LONG_FMT " seconds exceeded (terminated) in %s on line %d\n", EG(timeout_seconds), EG(hard_timeout), error_filename, error_lineno);
1494 if (output_len > 0) {
1495 zend_quiet_write(2, log_buffer, MIN(output_len, sizeof(log_buffer)));
1496 }
1497 _exit(124);
1498 }
1499 #endif
1500
1501 if (zend_on_timeout) {
1502 zend_on_timeout(EG(timeout_seconds));
1503 }
1504
1505 zend_atomic_bool_store_ex(&EG(timed_out), true);
1506 zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
1507
1508 #ifndef ZTS
1509 if (EG(hard_timeout) > 0) {
1510 /* Set hard timeout */
1511 zend_set_timeout_ex(EG(hard_timeout), 1);
1512 }
1513 #endif
1514 }
1515 /* }}} */
1516 #endif
1517
1518 #ifdef ZEND_WIN32
1519 VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out)
1520 {
1521 zend_executor_globals *eg;
1522
1523 /* The doc states it'll be always true, however it theoretically
1524 could be FALSE when the thread was signaled. */
1525 if (!timed_out) {
1526 return;
1527 }
1528
1529 eg = (zend_executor_globals *)arg;
1530 zend_atomic_bool_store_ex(&eg->timed_out, true);
1531 zend_atomic_bool_store_ex(&eg->vm_interrupt, true);
1532 }
1533 #endif
1534
1535 /* This one doesn't exists on QNX */
1536 #ifndef SIGPROF
1537 #define SIGPROF 27
1538 #endif
1539
1540 static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
1541 {
1542 #ifdef ZEND_WIN32
1543 zend_executor_globals *eg;
1544
1545 if (!seconds) {
1546 return;
1547 }
1548
1549 /* Don't use ChangeTimerQueueTimer() as it will not restart an expired
1550 * timer, so we could end up with just an ignored timeout. Instead
1551 * delete and recreate. */
1552 if (NULL != tq_timer) {
1553 if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
1554 tq_timer = NULL;
1555 zend_error_noreturn(E_ERROR, "Could not delete queued timer");
1556 return;
1557 }
1558 tq_timer = NULL;
1559 }
1560
1561 /* XXX passing NULL means the default timer queue provided by the system is used */
1562 eg = ZEND_MODULE_GLOBALS_BULK(executor);
1563 if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)eg, seconds*1000, 0, WT_EXECUTEONLYONCE)) {
1564 tq_timer = NULL;
1565 zend_error_noreturn(E_ERROR, "Could not queue new timer");
1566 return;
1567 }
1568 #elif defined(ZEND_MAX_EXECUTION_TIMERS)
1569 zend_max_execution_timer_settime(seconds);
1570
1571 if (reset_signals) {
1572 sigset_t sigset;
1573 struct sigaction act;
1574
1575 act.sa_sigaction = zend_timeout_handler;
1576 sigemptyset(&act.sa_mask);
1577 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
1578 sigaction(SIGRTMIN, &act, NULL);
1579 sigemptyset(&sigset);
1580 sigaddset(&sigset, SIGRTMIN);
1581 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1582 }
1583 #elif defined(HAVE_SETITIMER)
1584 {
1585 struct itimerval t_r; /* timeout requested */
1586 int signo;
1587
1588 // Prevent EINVAL error
1589 if (seconds < 0 || seconds > 999999999) {
1590 seconds = 0;
1591 }
1592
1593 if(seconds) {
1594 t_r.it_value.tv_sec = seconds;
1595 t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
1596
1597 # if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
1598 // ITIMER_PROF is broken in Apple Silicon system with MacOS >= 14
1599 // See https://openradar.appspot.com/radar?id=5583058442911744.
1600 setitimer(ITIMER_REAL, &t_r, NULL);
1601 }
1602 signo = SIGALRM;
1603 # else
1604 setitimer(ITIMER_PROF, &t_r, NULL);
1605 }
1606 signo = SIGPROF;
1607 # endif
1608
1609 if (reset_signals) {
1610 # ifdef ZEND_SIGNALS
1611 zend_signal(signo, zend_timeout_handler);
1612 # else
1613 sigset_t sigset;
1614 # ifdef HAVE_SIGACTION
1615 struct sigaction act;
1616
1617 act.sa_handler = zend_timeout_handler;
1618 sigemptyset(&act.sa_mask);
1619 act.sa_flags = SA_ONSTACK | SA_RESETHAND | SA_NODEFER;
1620 sigaction(signo, &act, NULL);
1621 # else
1622 signal(signo, zend_timeout_handler);
1623 # endif /* HAVE_SIGACTION */
1624 sigemptyset(&sigset);
1625 sigaddset(&sigset, signo);
1626 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1627 # endif /* ZEND_SIGNALS */
1628 }
1629 }
1630 #endif /* HAVE_SETITIMER */
1631 }
1632 /* }}} */
1633
zend_set_timeout(zend_long seconds,bool reset_signals)1634 void zend_set_timeout(zend_long seconds, bool reset_signals) /* {{{ */
1635 {
1636
1637 EG(timeout_seconds) = seconds;
1638 zend_set_timeout_ex(seconds, reset_signals);
1639 zend_atomic_bool_store_ex(&EG(timed_out), false);
1640 }
1641 /* }}} */
1642
zend_unset_timeout(void)1643 void zend_unset_timeout(void) /* {{{ */
1644 {
1645 #ifdef ZEND_WIN32
1646 if (NULL != tq_timer) {
1647 if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
1648 zend_atomic_bool_store_ex(&EG(timed_out), false);
1649 tq_timer = NULL;
1650 zend_error_noreturn(E_ERROR, "Could not delete queued timer");
1651 return;
1652 }
1653 tq_timer = NULL;
1654 }
1655 #elif defined(ZEND_MAX_EXECUTION_TIMERS)
1656 zend_max_execution_timer_settime(0);
1657 #elif defined(HAVE_SETITIMER)
1658 if (EG(timeout_seconds)) {
1659 struct itimerval no_timeout;
1660
1661 no_timeout.it_value.tv_sec = no_timeout.it_value.tv_usec = no_timeout.it_interval.tv_sec = no_timeout.it_interval.tv_usec = 0;
1662
1663 # if defined(__CYGWIN__) || defined(__PASE__) || (defined(__aarch64__) && defined(__APPLE__))
1664 setitimer(ITIMER_REAL, &no_timeout, NULL);
1665 # else
1666 setitimer(ITIMER_PROF, &no_timeout, NULL);
1667 # endif
1668 }
1669 #endif
1670 zend_atomic_bool_store_ex(&EG(timed_out), false);
1671 }
1672 /* }}} */
1673
report_class_fetch_error(zend_string * class_name,uint32_t fetch_type)1674 static ZEND_COLD void report_class_fetch_error(zend_string *class_name, uint32_t fetch_type)
1675 {
1676 if (fetch_type & ZEND_FETCH_CLASS_SILENT) {
1677 return;
1678 }
1679
1680 if (EG(exception)) {
1681 if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
1682 zend_exception_uncaught_error("During class fetch");
1683 }
1684 return;
1685 }
1686
1687 if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
1688 zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name));
1689 } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
1690 zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name));
1691 } else {
1692 zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name));
1693 }
1694 }
1695
zend_fetch_class(zend_string * class_name,uint32_t fetch_type)1696 zend_class_entry *zend_fetch_class(zend_string *class_name, uint32_t fetch_type) /* {{{ */
1697 {
1698 zend_class_entry *ce, *scope;
1699 uint32_t fetch_sub_type = fetch_type & ZEND_FETCH_CLASS_MASK;
1700
1701 check_fetch_type:
1702 switch (fetch_sub_type) {
1703 case ZEND_FETCH_CLASS_SELF:
1704 scope = zend_get_executed_scope();
1705 if (UNEXPECTED(!scope)) {
1706 zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
1707 }
1708 return scope;
1709 case ZEND_FETCH_CLASS_PARENT:
1710 scope = zend_get_executed_scope();
1711 if (UNEXPECTED(!scope)) {
1712 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
1713 return NULL;
1714 }
1715 if (UNEXPECTED(!scope->parent)) {
1716 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
1717 }
1718 return scope->parent;
1719 case ZEND_FETCH_CLASS_STATIC:
1720 ce = zend_get_called_scope(EG(current_execute_data));
1721 if (UNEXPECTED(!ce)) {
1722 zend_throw_or_error(fetch_type, NULL, "Cannot access \"static\" when no class scope is active");
1723 return NULL;
1724 }
1725 return ce;
1726 case ZEND_FETCH_CLASS_AUTO: {
1727 fetch_sub_type = zend_get_class_fetch_type(class_name);
1728 if (UNEXPECTED(fetch_sub_type != ZEND_FETCH_CLASS_DEFAULT)) {
1729 goto check_fetch_type;
1730 }
1731 }
1732 break;
1733 }
1734
1735 ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
1736 if (!ce) {
1737 report_class_fetch_error(class_name, fetch_type);
1738 return NULL;
1739 }
1740 return ce;
1741 }
1742 /* }}} */
1743
zend_fetch_class_with_scope(zend_string * class_name,uint32_t fetch_type,zend_class_entry * scope)1744 zend_class_entry *zend_fetch_class_with_scope(
1745 zend_string *class_name, uint32_t fetch_type, zend_class_entry *scope)
1746 {
1747 zend_class_entry *ce;
1748 switch (fetch_type & ZEND_FETCH_CLASS_MASK) {
1749 case ZEND_FETCH_CLASS_SELF:
1750 if (UNEXPECTED(!scope)) {
1751 zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
1752 }
1753 return scope;
1754 case ZEND_FETCH_CLASS_PARENT:
1755 if (UNEXPECTED(!scope)) {
1756 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
1757 return NULL;
1758 }
1759 if (UNEXPECTED(!scope->parent)) {
1760 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
1761 }
1762 return scope->parent;
1763 case 0:
1764 break;
1765 /* Other fetch types are not supported by this function. */
1766 EMPTY_SWITCH_DEFAULT_CASE()
1767 }
1768
1769 ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
1770 if (!ce) {
1771 report_class_fetch_error(class_name, fetch_type);
1772 return NULL;
1773 }
1774 return ce;
1775 }
1776
zend_fetch_class_by_name(zend_string * class_name,zend_string * key,uint32_t fetch_type)1777 zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *key, uint32_t fetch_type) /* {{{ */
1778 {
1779 zend_class_entry *ce = zend_lookup_class_ex(class_name, key, fetch_type);
1780 if (!ce) {
1781 report_class_fetch_error(class_name, fetch_type);
1782 return NULL;
1783 }
1784 return ce;
1785 }
1786 /* }}} */
1787
zend_delete_global_variable(zend_string * name)1788 ZEND_API zend_result zend_delete_global_variable(zend_string *name) /* {{{ */
1789 {
1790 return zend_hash_del_ind(&EG(symbol_table), name);
1791 }
1792 /* }}} */
1793
zend_rebuild_symbol_table(void)1794 ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */
1795 {
1796 zend_execute_data *ex;
1797 zend_array *symbol_table;
1798
1799 /* Search for last called user function */
1800 ex = EG(current_execute_data);
1801 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) {
1802 ex = ex->prev_execute_data;
1803 }
1804 if (!ex) {
1805 return NULL;
1806 }
1807 if (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE) {
1808 return ex->symbol_table;
1809 }
1810
1811 ZEND_ADD_CALL_FLAG(ex, ZEND_CALL_HAS_SYMBOL_TABLE);
1812 if (EG(symtable_cache_ptr) > EG(symtable_cache)) {
1813 symbol_table = ex->symbol_table = *(--EG(symtable_cache_ptr));
1814 if (!ex->func->op_array.last_var) {
1815 return symbol_table;
1816 }
1817 zend_hash_extend(symbol_table, ex->func->op_array.last_var, 0);
1818 } else {
1819 symbol_table = ex->symbol_table = zend_new_array(ex->func->op_array.last_var);
1820 if (!ex->func->op_array.last_var) {
1821 return symbol_table;
1822 }
1823 zend_hash_real_init_mixed(symbol_table);
1824 /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
1825 }
1826 if (EXPECTED(ex->func->op_array.last_var)) {
1827 zend_string **str = ex->func->op_array.vars;
1828 zend_string **end = str + ex->func->op_array.last_var;
1829 zval *var = ZEND_CALL_VAR_NUM(ex, 0);
1830
1831 do {
1832 _zend_hash_append_ind(symbol_table, *str, var);
1833 str++;
1834 var++;
1835 } while (str != end);
1836 }
1837 return symbol_table;
1838 }
1839 /* }}} */
1840
zend_attach_symbol_table(zend_execute_data * execute_data)1841 ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1842 {
1843 zend_op_array *op_array = &execute_data->func->op_array;
1844 HashTable *ht = execute_data->symbol_table;
1845
1846 /* copy real values from symbol table into CV slots and create
1847 INDIRECT references to CV in symbol table */
1848 if (EXPECTED(op_array->last_var)) {
1849 zend_string **str = op_array->vars;
1850 zend_string **end = str + op_array->last_var;
1851 zval *var = EX_VAR_NUM(0);
1852
1853 do {
1854 zval *zv = zend_hash_find_known_hash(ht, *str);
1855
1856 if (zv) {
1857 if (Z_TYPE_P(zv) == IS_INDIRECT) {
1858 zval *val = Z_INDIRECT_P(zv);
1859
1860 ZVAL_COPY_VALUE(var, val);
1861 } else {
1862 ZVAL_COPY_VALUE(var, zv);
1863 }
1864 } else {
1865 ZVAL_UNDEF(var);
1866 zv = zend_hash_add_new(ht, *str, var);
1867 }
1868 ZVAL_INDIRECT(zv, var);
1869 str++;
1870 var++;
1871 } while (str != end);
1872 }
1873 }
1874 /* }}} */
1875
zend_detach_symbol_table(zend_execute_data * execute_data)1876 ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1877 {
1878 zend_op_array *op_array = &execute_data->func->op_array;
1879 HashTable *ht = execute_data->symbol_table;
1880
1881 /* copy real values from CV slots into symbol table */
1882 if (EXPECTED(op_array->last_var)) {
1883 zend_string **str = op_array->vars;
1884 zend_string **end = str + op_array->last_var;
1885 zval *var = EX_VAR_NUM(0);
1886
1887 do {
1888 if (Z_TYPE_P(var) == IS_UNDEF) {
1889 zend_hash_del(ht, *str);
1890 } else {
1891 zend_hash_update(ht, *str, var);
1892 ZVAL_UNDEF(var);
1893 }
1894 str++;
1895 var++;
1896 } while (str != end);
1897 }
1898 }
1899 /* }}} */
1900
zend_set_local_var(zend_string * name,zval * value,bool force)1901 ZEND_API zend_result zend_set_local_var(zend_string *name, zval *value, bool force) /* {{{ */
1902 {
1903 zend_execute_data *execute_data = EG(current_execute_data);
1904
1905 while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1906 execute_data = execute_data->prev_execute_data;
1907 }
1908
1909 if (execute_data) {
1910 if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1911 zend_ulong h = zend_string_hash_val(name);
1912 zend_op_array *op_array = &execute_data->func->op_array;
1913
1914 if (EXPECTED(op_array->last_var)) {
1915 zend_string **str = op_array->vars;
1916 zend_string **end = str + op_array->last_var;
1917
1918 do {
1919 if (ZSTR_H(*str) == h &&
1920 zend_string_equal_content(*str, name)) {
1921 zval *var = EX_VAR_NUM(str - op_array->vars);
1922 ZVAL_COPY_VALUE(var, value);
1923 return SUCCESS;
1924 }
1925 str++;
1926 } while (str != end);
1927 }
1928 if (force) {
1929 zend_array *symbol_table = zend_rebuild_symbol_table();
1930 if (symbol_table) {
1931 zend_hash_update(symbol_table, name, value);
1932 return SUCCESS;
1933 }
1934 }
1935 } else {
1936 zend_hash_update_ind(execute_data->symbol_table, name, value);
1937 return SUCCESS;
1938 }
1939 }
1940 return FAILURE;
1941 }
1942 /* }}} */
1943
zend_set_local_var_str(const char * name,size_t len,zval * value,bool force)1944 ZEND_API zend_result zend_set_local_var_str(const char *name, size_t len, zval *value, bool force) /* {{{ */
1945 {
1946 zend_execute_data *execute_data = EG(current_execute_data);
1947
1948 while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1949 execute_data = execute_data->prev_execute_data;
1950 }
1951
1952 if (execute_data) {
1953 if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1954 zend_ulong h = zend_hash_func(name, len);
1955 zend_op_array *op_array = &execute_data->func->op_array;
1956 if (EXPECTED(op_array->last_var)) {
1957 zend_string **str = op_array->vars;
1958 zend_string **end = str + op_array->last_var;
1959
1960 do {
1961 if (ZSTR_H(*str) == h &&
1962 zend_string_equals_cstr(*str, name, len)) {
1963 zval *var = EX_VAR_NUM(str - op_array->vars);
1964 zval_ptr_dtor(var);
1965 ZVAL_COPY_VALUE(var, value);
1966 return SUCCESS;
1967 }
1968 str++;
1969 } while (str != end);
1970 }
1971 if (force) {
1972 zend_array *symbol_table = zend_rebuild_symbol_table();
1973 if (symbol_table) {
1974 zend_hash_str_update(symbol_table, name, len, value);
1975 return SUCCESS;
1976 }
1977 }
1978 } else {
1979 zend_hash_str_update_ind(execute_data->symbol_table, name, len, value);
1980 return SUCCESS;
1981 }
1982 }
1983 return FAILURE;
1984 }
1985 /* }}} */
1986