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