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 = EG(current_execute_data)->func;
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_exception_save();
1231 ce = zend_autoload(autoload_name, lc_name);
1232 zend_exception_restore();
1233
1234 zend_string_release_ex(autoload_name, 0);
1235 zend_hash_del(EG(in_autoload), lc_name);
1236
1237 if (!key) {
1238 zend_string_release_ex(lc_name, 0);
1239 }
1240 if (ce) {
1241 ZEND_ASSERT(!CG(in_compilation));
1242 if (ce_cache) {
1243 SET_CE_CACHE(ce_cache, ce);
1244 }
1245 }
1246 return ce;
1247 }
1248 /* }}} */
1249
zend_lookup_class(zend_string * name)1250 ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */
1251 {
1252 return zend_lookup_class_ex(name, NULL, 0);
1253 }
1254 /* }}} */
1255
zend_get_called_scope(zend_execute_data * ex)1256 ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex) /* {{{ */
1257 {
1258 while (ex) {
1259 if (Z_TYPE(ex->This) == IS_OBJECT) {
1260 return Z_OBJCE(ex->This);
1261 } else if (Z_CE(ex->This)) {
1262 return Z_CE(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_get_this_object(zend_execute_data * ex)1274 ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex) /* {{{ */
1275 {
1276 while (ex) {
1277 if (Z_TYPE(ex->This) == IS_OBJECT) {
1278 return Z_OBJ(ex->This);
1279 } else if (ex->func) {
1280 if (ex->func->type != ZEND_INTERNAL_FUNCTION || ex->func->common.scope) {
1281 return NULL;
1282 }
1283 }
1284 ex = ex->prev_execute_data;
1285 }
1286 return NULL;
1287 }
1288 /* }}} */
1289
zend_eval_stringl(const char * str,size_t str_len,zval * retval_ptr,const char * string_name)1290 ZEND_API zend_result zend_eval_stringl(const char *str, size_t str_len, zval *retval_ptr, const char *string_name) /* {{{ */
1291 {
1292 zend_op_array *new_op_array;
1293 uint32_t original_compiler_options;
1294 zend_result retval;
1295 zend_string *code_str;
1296
1297 if (retval_ptr) {
1298 code_str = zend_string_concat3(
1299 "return ", sizeof("return ")-1, str, str_len, ";", sizeof(";")-1);
1300 } else {
1301 code_str = zend_string_init(str, str_len, 0);
1302 }
1303
1304 /*printf("Evaluating '%s'\n", pv.value.str.val);*/
1305
1306 original_compiler_options = CG(compiler_options);
1307 CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
1308 new_op_array = zend_compile_string(code_str, string_name, ZEND_COMPILE_POSITION_AFTER_OPEN_TAG);
1309 CG(compiler_options) = original_compiler_options;
1310
1311 if (new_op_array) {
1312 zval local_retval;
1313
1314 EG(no_extensions)=1;
1315
1316 new_op_array->scope = zend_get_executed_scope();
1317
1318 zend_try {
1319 ZVAL_UNDEF(&local_retval);
1320 zend_execute(new_op_array, &local_retval);
1321 } zend_catch {
1322 destroy_op_array(new_op_array);
1323 efree_size(new_op_array, sizeof(zend_op_array));
1324 zend_bailout();
1325 } zend_end_try();
1326
1327 if (Z_TYPE(local_retval) != IS_UNDEF) {
1328 if (retval_ptr) {
1329 ZVAL_COPY_VALUE(retval_ptr, &local_retval);
1330 } else {
1331 zval_ptr_dtor(&local_retval);
1332 }
1333 } else {
1334 if (retval_ptr) {
1335 ZVAL_NULL(retval_ptr);
1336 }
1337 }
1338
1339 EG(no_extensions)=0;
1340 zend_destroy_static_vars(new_op_array);
1341 destroy_op_array(new_op_array);
1342 efree_size(new_op_array, sizeof(zend_op_array));
1343 retval = SUCCESS;
1344 } else {
1345 retval = FAILURE;
1346 }
1347 zend_string_release(code_str);
1348 return retval;
1349 }
1350 /* }}} */
1351
zend_eval_string(const char * str,zval * retval_ptr,const char * string_name)1352 ZEND_API zend_result zend_eval_string(const char *str, zval *retval_ptr, const char *string_name) /* {{{ */
1353 {
1354 return zend_eval_stringl(str, strlen(str), retval_ptr, string_name);
1355 }
1356 /* }}} */
1357
zend_eval_stringl_ex(const char * str,size_t str_len,zval * retval_ptr,const char * string_name,bool handle_exceptions)1358 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) /* {{{ */
1359 {
1360 zend_result result;
1361
1362 result = zend_eval_stringl(str, str_len, retval_ptr, string_name);
1363 if (handle_exceptions && EG(exception)) {
1364 result = zend_exception_error(EG(exception), E_ERROR);
1365 }
1366 return result;
1367 }
1368 /* }}} */
1369
zend_eval_string_ex(const char * str,zval * retval_ptr,const char * string_name,bool handle_exceptions)1370 ZEND_API zend_result zend_eval_string_ex(const char *str, zval *retval_ptr, const char *string_name, bool handle_exceptions) /* {{{ */
1371 {
1372 return zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
1373 }
1374 /* }}} */
1375
1376 static void zend_set_timeout_ex(zend_long seconds, bool reset_signals);
1377
zend_timeout(void)1378 ZEND_API ZEND_NORETURN void ZEND_FASTCALL zend_timeout(void) /* {{{ */
1379 {
1380 #if defined(PHP_WIN32)
1381 # ifndef ZTS
1382 /* No action is needed if we're timed out because zero seconds are
1383 just ignored. Also, the hard timeout needs to be respected. If the
1384 timer is not restarted properly, it could hang in the shutdown
1385 function. */
1386 if (EG(hard_timeout) > 0) {
1387 zend_atomic_bool_store_ex(&EG(timed_out), false);
1388 zend_set_timeout_ex(EG(hard_timeout), 1);
1389 /* XXX Abused, introduce an additional flag if the value needs to be kept. */
1390 EG(hard_timeout) = 0;
1391 }
1392 # endif
1393 #else
1394 zend_atomic_bool_store_ex(&EG(timed_out), false);
1395 zend_set_timeout_ex(0, 1);
1396 #endif
1397
1398 zend_error_noreturn(E_ERROR, "Maximum execution time of " ZEND_LONG_FMT " second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
1399 }
1400 /* }}} */
1401
1402 #ifndef ZEND_WIN32
1403 # ifdef ZEND_MAX_EXECUTION_TIMERS
zend_timeout_handler(int dummy,siginfo_t * si,void * uc)1404 static void zend_timeout_handler(int dummy, siginfo_t *si, void *uc) /* {{{ */
1405 {
1406 #ifdef ZTS
1407 if (!tsrm_is_managed_thread()) {
1408 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");
1409
1410 return;
1411 }
1412 #endif
1413
1414 if (si->si_value.sival_ptr != &EG(max_execution_timer_timer)) {
1415 #ifdef MAX_EXECUTION_TIMERS_DEBUG
1416 fprintf(stderr, "Executing previous handler (if set) for unexpected signal SIGRTMIN received on thread %d\n", (pid_t) syscall(SYS_gettid));
1417 #endif
1418
1419 if (EG(oldact).sa_sigaction) {
1420 EG(oldact).sa_sigaction(dummy, si, uc);
1421
1422 return;
1423 }
1424 if (EG(oldact).sa_handler) EG(oldact).sa_handler(dummy);
1425
1426 return;
1427 }
1428 # else
1429 static void zend_timeout_handler(int dummy) /* {{{ */
1430 {
1431 # endif
1432 #ifdef ZTS
1433 if (!tsrm_is_managed_thread()) {
1434 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");
1435
1436 return;
1437 }
1438 #else
1439 if (zend_atomic_bool_load_ex(&EG(timed_out))) {
1440 /* Die on hard timeout */
1441 const char *error_filename = NULL;
1442 uint32_t error_lineno = 0;
1443 char log_buffer[2048];
1444 int output_len = 0;
1445
1446 if (zend_is_compiling()) {
1447 error_filename = ZSTR_VAL(zend_get_compiled_filename());
1448 error_lineno = zend_get_compiled_lineno();
1449 } else if (zend_is_executing()) {
1450 error_filename = zend_get_executed_filename();
1451 if (error_filename[0] == '[') { /* [no active file] */
1452 error_filename = NULL;
1453 error_lineno = 0;
1454 } else {
1455 error_lineno = zend_get_executed_lineno();
1456 }
1457 }
1458 if (!error_filename) {
1459 error_filename = "Unknown";
1460 }
1461
1462 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);
1463 if (output_len > 0) {
1464 zend_quiet_write(2, log_buffer, MIN(output_len, sizeof(log_buffer)));
1465 }
1466 _exit(124);
1467 }
1468 #endif
1469
1470 if (zend_on_timeout) {
1471 zend_on_timeout(EG(timeout_seconds));
1472 }
1473
1474 zend_atomic_bool_store_ex(&EG(timed_out), true);
1475 zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
1476
1477 #ifndef ZTS
1478 if (EG(hard_timeout) > 0) {
1479 /* Set hard timeout */
1480 zend_set_timeout_ex(EG(hard_timeout), 1);
1481 }
1482 #endif
1483 }
1484 /* }}} */
1485 #endif
1486
1487 #ifdef ZEND_WIN32
1488 VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out)
1489 {
1490 zend_executor_globals *eg;
1491
1492 /* The doc states it'll be always true, however it theoretically
1493 could be FALSE when the thread was signaled. */
1494 if (!timed_out) {
1495 return;
1496 }
1497
1498 eg = (zend_executor_globals *)arg;
1499 zend_atomic_bool_store_ex(&eg->timed_out, true);
1500 zend_atomic_bool_store_ex(&eg->vm_interrupt, true);
1501 }
1502 #endif
1503
1504 /* This one doesn't exists on QNX */
1505 #ifndef SIGPROF
1506 #define SIGPROF 27
1507 #endif
1508
1509 static void zend_set_timeout_ex(zend_long seconds, bool reset_signals) /* {{{ */
1510 {
1511 #ifdef ZEND_WIN32
1512 zend_executor_globals *eg;
1513
1514 if (!seconds) {
1515 return;
1516 }
1517
1518 /* Don't use ChangeTimerQueueTimer() as it will not restart an expired
1519 * timer, so we could end up with just an ignored timeout. Instead
1520 * delete and recreate. */
1521 if (NULL != tq_timer) {
1522 if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
1523 tq_timer = NULL;
1524 zend_error_noreturn(E_ERROR, "Could not delete queued timer");
1525 return;
1526 }
1527 tq_timer = NULL;
1528 }
1529
1530 /* XXX passing NULL means the default timer queue provided by the system is used */
1531 eg = ZEND_MODULE_GLOBALS_BULK(executor);
1532 if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)eg, seconds*1000, 0, WT_EXECUTEONLYONCE)) {
1533 tq_timer = NULL;
1534 zend_error_noreturn(E_ERROR, "Could not queue new timer");
1535 return;
1536 }
1537 #elif defined(ZEND_MAX_EXECUTION_TIMERS)
1538 zend_max_execution_timer_settime(seconds);
1539
1540 if (reset_signals) {
1541 sigset_t sigset;
1542 struct sigaction act;
1543
1544 act.sa_sigaction = zend_timeout_handler;
1545 sigemptyset(&act.sa_mask);
1546 act.sa_flags = SA_ONSTACK | SA_SIGINFO;
1547 sigaction(SIGRTMIN, &act, NULL);
1548 sigemptyset(&sigset);
1549 sigaddset(&sigset, SIGRTMIN);
1550 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1551 }
1552 #elif defined(HAVE_SETITIMER)
1553 {
1554 struct itimerval t_r; /* timeout requested */
1555 int signo;
1556
1557 if(seconds) {
1558 t_r.it_value.tv_sec = seconds;
1559 t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
1560
1561 # if defined(__CYGWIN__) || defined(__PASE__)
1562 setitimer(ITIMER_REAL, &t_r, NULL);
1563 }
1564 signo = SIGALRM;
1565 # else
1566 setitimer(ITIMER_PROF, &t_r, NULL);
1567 }
1568 signo = SIGPROF;
1569 # endif
1570
1571 if (reset_signals) {
1572 # ifdef ZEND_SIGNALS
1573 zend_signal(signo, zend_timeout_handler);
1574 # else
1575 sigset_t sigset;
1576 # ifdef HAVE_SIGACTION
1577 struct sigaction act;
1578
1579 act.sa_handler = zend_timeout_handler;
1580 sigemptyset(&act.sa_mask);
1581 act.sa_flags = SA_ONSTACK | SA_RESETHAND | SA_NODEFER;
1582 sigaction(signo, &act, NULL);
1583 # else
1584 signal(signo, zend_timeout_handler);
1585 # endif /* HAVE_SIGACTION */
1586 sigemptyset(&sigset);
1587 sigaddset(&sigset, signo);
1588 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1589 # endif /* ZEND_SIGNALS */
1590 }
1591 }
1592 #endif /* HAVE_SETITIMER */
1593 }
1594 /* }}} */
1595
zend_set_timeout(zend_long seconds,bool reset_signals)1596 void zend_set_timeout(zend_long seconds, bool reset_signals) /* {{{ */
1597 {
1598
1599 EG(timeout_seconds) = seconds;
1600 zend_set_timeout_ex(seconds, reset_signals);
1601 zend_atomic_bool_store_ex(&EG(timed_out), false);
1602 }
1603 /* }}} */
1604
zend_unset_timeout(void)1605 void zend_unset_timeout(void) /* {{{ */
1606 {
1607 #ifdef ZEND_WIN32
1608 if (NULL != tq_timer) {
1609 if (!DeleteTimerQueueTimer(NULL, tq_timer, INVALID_HANDLE_VALUE)) {
1610 zend_atomic_bool_store_ex(&EG(timed_out), false);
1611 tq_timer = NULL;
1612 zend_error_noreturn(E_ERROR, "Could not delete queued timer");
1613 return;
1614 }
1615 tq_timer = NULL;
1616 }
1617 #elif ZEND_MAX_EXECUTION_TIMERS
1618 zend_max_execution_timer_settime(0);
1619 #elif defined(HAVE_SETITIMER)
1620 if (EG(timeout_seconds)) {
1621 struct itimerval no_timeout;
1622
1623 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;
1624
1625 # if defined(__CYGWIN__) || defined(__PASE__)
1626 setitimer(ITIMER_REAL, &no_timeout, NULL);
1627 # else
1628 setitimer(ITIMER_PROF, &no_timeout, NULL);
1629 # endif
1630 }
1631 #endif
1632 zend_atomic_bool_store_ex(&EG(timed_out), false);
1633 }
1634 /* }}} */
1635
report_class_fetch_error(zend_string * class_name,uint32_t fetch_type)1636 static ZEND_COLD void report_class_fetch_error(zend_string *class_name, uint32_t fetch_type)
1637 {
1638 if (fetch_type & ZEND_FETCH_CLASS_SILENT) {
1639 return;
1640 }
1641
1642 if (EG(exception)) {
1643 if (!(fetch_type & ZEND_FETCH_CLASS_EXCEPTION)) {
1644 zend_exception_uncaught_error("During class fetch");
1645 }
1646 return;
1647 }
1648
1649 if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
1650 zend_throw_or_error(fetch_type, NULL, "Interface \"%s\" not found", ZSTR_VAL(class_name));
1651 } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
1652 zend_throw_or_error(fetch_type, NULL, "Trait \"%s\" not found", ZSTR_VAL(class_name));
1653 } else {
1654 zend_throw_or_error(fetch_type, NULL, "Class \"%s\" not found", ZSTR_VAL(class_name));
1655 }
1656 }
1657
zend_fetch_class(zend_string * class_name,uint32_t fetch_type)1658 zend_class_entry *zend_fetch_class(zend_string *class_name, uint32_t fetch_type) /* {{{ */
1659 {
1660 zend_class_entry *ce, *scope;
1661 uint32_t fetch_sub_type = fetch_type & ZEND_FETCH_CLASS_MASK;
1662
1663 check_fetch_type:
1664 switch (fetch_sub_type) {
1665 case ZEND_FETCH_CLASS_SELF:
1666 scope = zend_get_executed_scope();
1667 if (UNEXPECTED(!scope)) {
1668 zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
1669 }
1670 return scope;
1671 case ZEND_FETCH_CLASS_PARENT:
1672 scope = zend_get_executed_scope();
1673 if (UNEXPECTED(!scope)) {
1674 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
1675 return NULL;
1676 }
1677 if (UNEXPECTED(!scope->parent)) {
1678 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
1679 }
1680 return scope->parent;
1681 case ZEND_FETCH_CLASS_STATIC:
1682 ce = zend_get_called_scope(EG(current_execute_data));
1683 if (UNEXPECTED(!ce)) {
1684 zend_throw_or_error(fetch_type, NULL, "Cannot access \"static\" when no class scope is active");
1685 return NULL;
1686 }
1687 return ce;
1688 case ZEND_FETCH_CLASS_AUTO: {
1689 fetch_sub_type = zend_get_class_fetch_type(class_name);
1690 if (UNEXPECTED(fetch_sub_type != ZEND_FETCH_CLASS_DEFAULT)) {
1691 goto check_fetch_type;
1692 }
1693 }
1694 break;
1695 }
1696
1697 ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
1698 if (!ce) {
1699 report_class_fetch_error(class_name, fetch_type);
1700 return NULL;
1701 }
1702 return ce;
1703 }
1704 /* }}} */
1705
zend_fetch_class_with_scope(zend_string * class_name,uint32_t fetch_type,zend_class_entry * scope)1706 zend_class_entry *zend_fetch_class_with_scope(
1707 zend_string *class_name, uint32_t fetch_type, zend_class_entry *scope)
1708 {
1709 zend_class_entry *ce;
1710 switch (fetch_type & ZEND_FETCH_CLASS_MASK) {
1711 case ZEND_FETCH_CLASS_SELF:
1712 if (UNEXPECTED(!scope)) {
1713 zend_throw_or_error(fetch_type, NULL, "Cannot access \"self\" when no class scope is active");
1714 }
1715 return scope;
1716 case ZEND_FETCH_CLASS_PARENT:
1717 if (UNEXPECTED(!scope)) {
1718 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when no class scope is active");
1719 return NULL;
1720 }
1721 if (UNEXPECTED(!scope->parent)) {
1722 zend_throw_or_error(fetch_type, NULL, "Cannot access \"parent\" when current class scope has no parent");
1723 }
1724 return scope->parent;
1725 case 0:
1726 break;
1727 /* Other fetch types are not supported by this function. */
1728 EMPTY_SWITCH_DEFAULT_CASE()
1729 }
1730
1731 ce = zend_lookup_class_ex(class_name, NULL, fetch_type);
1732 if (!ce) {
1733 report_class_fetch_error(class_name, fetch_type);
1734 return NULL;
1735 }
1736 return ce;
1737 }
1738
zend_fetch_class_by_name(zend_string * class_name,zend_string * key,uint32_t fetch_type)1739 zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, zend_string *key, uint32_t fetch_type) /* {{{ */
1740 {
1741 zend_class_entry *ce = zend_lookup_class_ex(class_name, key, fetch_type);
1742 if (!ce) {
1743 report_class_fetch_error(class_name, fetch_type);
1744 return NULL;
1745 }
1746 return ce;
1747 }
1748 /* }}} */
1749
zend_delete_global_variable(zend_string * name)1750 ZEND_API zend_result zend_delete_global_variable(zend_string *name) /* {{{ */
1751 {
1752 return zend_hash_del_ind(&EG(symbol_table), name);
1753 }
1754 /* }}} */
1755
zend_rebuild_symbol_table(void)1756 ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */
1757 {
1758 zend_execute_data *ex;
1759 zend_array *symbol_table;
1760
1761 /* Search for last called user function */
1762 ex = EG(current_execute_data);
1763 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) {
1764 ex = ex->prev_execute_data;
1765 }
1766 if (!ex) {
1767 return NULL;
1768 }
1769 if (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE) {
1770 return ex->symbol_table;
1771 }
1772
1773 ZEND_ADD_CALL_FLAG(ex, ZEND_CALL_HAS_SYMBOL_TABLE);
1774 if (EG(symtable_cache_ptr) > EG(symtable_cache)) {
1775 symbol_table = ex->symbol_table = *(--EG(symtable_cache_ptr));
1776 if (!ex->func->op_array.last_var) {
1777 return symbol_table;
1778 }
1779 zend_hash_extend(symbol_table, ex->func->op_array.last_var, 0);
1780 } else {
1781 symbol_table = ex->symbol_table = zend_new_array(ex->func->op_array.last_var);
1782 if (!ex->func->op_array.last_var) {
1783 return symbol_table;
1784 }
1785 zend_hash_real_init_mixed(symbol_table);
1786 /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/
1787 }
1788 if (EXPECTED(ex->func->op_array.last_var)) {
1789 zend_string **str = ex->func->op_array.vars;
1790 zend_string **end = str + ex->func->op_array.last_var;
1791 zval *var = ZEND_CALL_VAR_NUM(ex, 0);
1792
1793 do {
1794 _zend_hash_append_ind(symbol_table, *str, var);
1795 str++;
1796 var++;
1797 } while (str != end);
1798 }
1799 return symbol_table;
1800 }
1801 /* }}} */
1802
zend_attach_symbol_table(zend_execute_data * execute_data)1803 ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1804 {
1805 zend_op_array *op_array = &execute_data->func->op_array;
1806 HashTable *ht = execute_data->symbol_table;
1807
1808 /* copy real values from symbol table into CV slots and create
1809 INDIRECT references to CV in symbol table */
1810 if (EXPECTED(op_array->last_var)) {
1811 zend_string **str = op_array->vars;
1812 zend_string **end = str + op_array->last_var;
1813 zval *var = EX_VAR_NUM(0);
1814
1815 do {
1816 zval *zv = zend_hash_find_known_hash(ht, *str);
1817
1818 if (zv) {
1819 if (Z_TYPE_P(zv) == IS_INDIRECT) {
1820 zval *val = Z_INDIRECT_P(zv);
1821
1822 ZVAL_COPY_VALUE(var, val);
1823 } else {
1824 ZVAL_COPY_VALUE(var, zv);
1825 }
1826 } else {
1827 ZVAL_UNDEF(var);
1828 zv = zend_hash_add_new(ht, *str, var);
1829 }
1830 ZVAL_INDIRECT(zv, var);
1831 str++;
1832 var++;
1833 } while (str != end);
1834 }
1835 }
1836 /* }}} */
1837
zend_detach_symbol_table(zend_execute_data * execute_data)1838 ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1839 {
1840 zend_op_array *op_array = &execute_data->func->op_array;
1841 HashTable *ht = execute_data->symbol_table;
1842
1843 /* copy real values from CV slots into symbol table */
1844 if (EXPECTED(op_array->last_var)) {
1845 zend_string **str = op_array->vars;
1846 zend_string **end = str + op_array->last_var;
1847 zval *var = EX_VAR_NUM(0);
1848
1849 do {
1850 if (Z_TYPE_P(var) == IS_UNDEF) {
1851 zend_hash_del(ht, *str);
1852 } else {
1853 zend_hash_update(ht, *str, var);
1854 ZVAL_UNDEF(var);
1855 }
1856 str++;
1857 var++;
1858 } while (str != end);
1859 }
1860 }
1861 /* }}} */
1862
zend_set_local_var(zend_string * name,zval * value,bool force)1863 ZEND_API zend_result zend_set_local_var(zend_string *name, zval *value, bool force) /* {{{ */
1864 {
1865 zend_execute_data *execute_data = EG(current_execute_data);
1866
1867 while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1868 execute_data = execute_data->prev_execute_data;
1869 }
1870
1871 if (execute_data) {
1872 if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1873 zend_ulong h = zend_string_hash_val(name);
1874 zend_op_array *op_array = &execute_data->func->op_array;
1875
1876 if (EXPECTED(op_array->last_var)) {
1877 zend_string **str = op_array->vars;
1878 zend_string **end = str + op_array->last_var;
1879
1880 do {
1881 if (ZSTR_H(*str) == h &&
1882 zend_string_equal_content(*str, name)) {
1883 zval *var = EX_VAR_NUM(str - op_array->vars);
1884 ZVAL_COPY_VALUE(var, value);
1885 return SUCCESS;
1886 }
1887 str++;
1888 } while (str != end);
1889 }
1890 if (force) {
1891 zend_array *symbol_table = zend_rebuild_symbol_table();
1892 if (symbol_table) {
1893 zend_hash_update(symbol_table, name, value);
1894 return SUCCESS;
1895 }
1896 }
1897 } else {
1898 zend_hash_update_ind(execute_data->symbol_table, name, value);
1899 return SUCCESS;
1900 }
1901 }
1902 return FAILURE;
1903 }
1904 /* }}} */
1905
zend_set_local_var_str(const char * name,size_t len,zval * value,bool force)1906 ZEND_API zend_result zend_set_local_var_str(const char *name, size_t len, zval *value, bool force) /* {{{ */
1907 {
1908 zend_execute_data *execute_data = EG(current_execute_data);
1909
1910 while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1911 execute_data = execute_data->prev_execute_data;
1912 }
1913
1914 if (execute_data) {
1915 if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1916 zend_ulong h = zend_hash_func(name, len);
1917 zend_op_array *op_array = &execute_data->func->op_array;
1918 if (EXPECTED(op_array->last_var)) {
1919 zend_string **str = op_array->vars;
1920 zend_string **end = str + op_array->last_var;
1921
1922 do {
1923 if (ZSTR_H(*str) == h &&
1924 zend_string_equals_cstr(*str, name, len)) {
1925 zval *var = EX_VAR_NUM(str - op_array->vars);
1926 zval_ptr_dtor(var);
1927 ZVAL_COPY_VALUE(var, value);
1928 return SUCCESS;
1929 }
1930 str++;
1931 } while (str != end);
1932 }
1933 if (force) {
1934 zend_array *symbol_table = zend_rebuild_symbol_table();
1935 if (symbol_table) {
1936 zend_hash_str_update(symbol_table, name, len, value);
1937 return SUCCESS;
1938 }
1939 }
1940 } else {
1941 zend_hash_str_update_ind(execute_data->symbol_table, name, len, value);
1942 return SUCCESS;
1943 }
1944 }
1945 return FAILURE;
1946 }
1947 /* }}} */
1948