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