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