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