1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2014 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@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#include <stdio.h>
23#include <signal.h>
24
25#include "zend.h"
26#include "zend_compile.h"
27#include "zend_execute.h"
28#include "zend_API.h"
29#include "zend_stack.h"
30#include "zend_constants.h"
31#include "zend_extensions.h"
32#include "zend_exceptions.h"
33#include "zend_closures.h"
34#include "zend_generators.h"
35#include "zend_vm.h"
36#include "zend_float.h"
37#ifdef HAVE_SYS_TIME_H
38#include <sys/time.h>
39#endif
40
41ZEND_API void (*zend_execute_ex)(zend_execute_data *execute_data);
42ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data, zval *return_value);
43
44/* true globals */
45ZEND_API const zend_fcall_info empty_fcall_info = { 0, NULL, {{0}, {{0}}, {0}}, NULL, NULL, NULL, NULL, 0, 0 };
46ZEND_API const zend_fcall_info_cache empty_fcall_info_cache = { 0, NULL, NULL, NULL, NULL };
47
48#ifdef ZEND_WIN32
49#ifdef ZTS
50__declspec(thread)
51#endif
52HANDLE tq_timer = NULL;
53#endif
54
55#if 0&&ZEND_DEBUG
56static void (*original_sigsegv_handler)(int);
57static void zend_handle_sigsegv(int dummy) /* {{{ */
58{
59    fflush(stdout);
60    fflush(stderr);
61    if (original_sigsegv_handler == zend_handle_sigsegv) {
62        signal(SIGSEGV, original_sigsegv_handler);
63    } else {
64        signal(SIGSEGV, SIG_DFL);
65    }
66    {
67
68        fprintf(stderr, "SIGSEGV caught on opcode %d on opline %d of %s() at %s:%d\n\n",
69                active_opline->opcode,
70                active_opline-EG(active_op_array)->opcodes,
71                get_active_function_name(),
72                zend_get_executed_filename(),
73                zend_get_executed_lineno());
74/* See http://support.microsoft.com/kb/190351 */
75#ifdef PHP_WIN32
76        fflush(stderr);
77#endif
78    }
79    if (original_sigsegv_handler!=zend_handle_sigsegv) {
80        original_sigsegv_handler(dummy);
81    }
82}
83/* }}} */
84#endif
85
86static void zend_extension_activator(zend_extension *extension) /* {{{ */
87{
88    if (extension->activate) {
89        extension->activate();
90    }
91}
92/* }}} */
93
94static void zend_extension_deactivator(zend_extension *extension) /* {{{ */
95{
96    if (extension->deactivate) {
97        extension->deactivate();
98    }
99}
100/* }}} */
101
102static int clean_non_persistent_function(zval *zv) /* {{{ */
103{
104    zend_function *function = Z_PTR_P(zv);
105    return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
106}
107/* }}} */
108
109ZEND_API int clean_non_persistent_function_full(zval *zv) /* {{{ */
110{
111    zend_function *function = Z_PTR_P(zv);
112    return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
113}
114/* }}} */
115
116static int clean_non_persistent_class(zval *zv) /* {{{ */
117{
118    zend_class_entry *ce = Z_PTR_P(zv);
119    return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
120}
121/* }}} */
122
123ZEND_API int clean_non_persistent_class_full(zval *zv) /* {{{ */
124{
125    zend_class_entry *ce = Z_PTR_P(zv);
126    return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
127}
128/* }}} */
129
130void init_executor(void) /* {{{ */
131{
132    zend_init_fpu();
133
134    ZVAL_NULL(&EG(uninitialized_zval));
135    /* trick to make uninitialized_zval never be modified, passed by ref, etc. */
136    ZVAL_NULL(&EG(error_zval));
137/* destroys stack frame, therefore makes core dumps worthless */
138#if 0&&ZEND_DEBUG
139    original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
140#endif
141
142    EG(symtable_cache_ptr) = EG(symtable_cache) - 1;
143    EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - 1;
144    EG(no_extensions) = 0;
145
146    EG(function_table) = CG(function_table);
147    EG(class_table) = CG(class_table);
148
149    EG(in_autoload) = NULL;
150    EG(autoload_func) = NULL;
151    EG(error_handling) = EH_NORMAL;
152
153    zend_vm_stack_init();
154
155    zend_hash_init(&EG(symbol_table).ht, 64, NULL, ZVAL_PTR_DTOR, 0);
156    GC_REFCOUNT(&EG(symbol_table)) = 1;
157    GC_TYPE_INFO(&EG(symbol_table)) = IS_ARRAY;
158    EG(valid_symbol_table) = 1;
159
160    zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator);
161
162    zend_hash_init(&EG(included_files), 8, NULL, NULL, 0);
163
164    EG(ticks_count) = 0;
165
166    ZVAL_UNDEF(&EG(user_error_handler));
167
168    EG(current_execute_data) = NULL;
169
170    zend_stack_init(&EG(user_error_handlers_error_reporting), sizeof(int));
171    zend_stack_init(&EG(user_error_handlers), sizeof(zval));
172    zend_stack_init(&EG(user_exception_handlers), sizeof(zval));
173
174    zend_objects_store_init(&EG(objects_store), 1024);
175
176    EG(full_tables_cleanup) = 0;
177#ifdef ZEND_WIN32
178    EG(timed_out) = 0;
179#endif
180
181    EG(exception) = NULL;
182    EG(prev_exception) = NULL;
183
184    EG(scope) = NULL;
185
186    EG(active) = 1;
187}
188/* }}} */
189
190static int zval_call_destructor(zval *zv) /* {{{ */
191{
192    if (Z_TYPE_P(zv) == IS_INDIRECT) {
193        zv = Z_INDIRECT_P(zv);
194    }
195    if (Z_TYPE_P(zv) == IS_OBJECT && Z_REFCOUNT_P(zv) == 1) {
196        return ZEND_HASH_APPLY_REMOVE;
197    } else {
198        return ZEND_HASH_APPLY_KEEP;
199    }
200}
201/* }}} */
202
203static void zend_unclean_zval_ptr_dtor(zval *zv) /* {{{ */
204{
205
206    if (Z_TYPE_P(zv) == IS_INDIRECT) {
207        zv = Z_INDIRECT_P(zv);
208    }
209    i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC);
210}
211/* }}} */
212
213void shutdown_destructors(void) /* {{{ */
214{
215    if (CG(unclean_shutdown)) {
216        EG(symbol_table).ht.pDestructor = zend_unclean_zval_ptr_dtor;
217    }
218    zend_try {
219        uint32_t symbols;
220        do {
221            symbols = zend_hash_num_elements(&EG(symbol_table).ht);
222            zend_hash_reverse_apply(&EG(symbol_table).ht, (apply_func_t) zval_call_destructor);
223        } while (symbols != zend_hash_num_elements(&EG(symbol_table).ht));
224        zend_objects_store_call_destructors(&EG(objects_store));
225    } zend_catch {
226        /* if we couldn't destruct cleanly, mark all objects as destructed anyway */
227        zend_objects_store_mark_destructed(&EG(objects_store));
228    } zend_end_try();
229}
230/* }}} */
231
232void shutdown_executor(void) /* {{{ */
233{
234    zend_function *func;
235    zend_class_entry *ce;
236
237    zend_try {
238
239/* Removed because this can not be safely done, e.g. in this situation:
240   Object 1 creates object 2
241   Object 3 holds reference to object 2.
242   Now when 1 and 2 are destroyed, 3 can still access 2 in its destructor, with
243   very problematic results */
244/*      zend_objects_store_call_destructors(&EG(objects_store)); */
245
246/* Moved after symbol table cleaners, because  some of the cleaners can call
247   destructors, which would use EG(symtable_cache_ptr) and thus leave leaks */
248/*      while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
249            zend_hash_destroy(*EG(symtable_cache_ptr));
250            efree(*EG(symtable_cache_ptr));
251            EG(symtable_cache_ptr)--;
252        }
253*/
254        zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
255
256        if (CG(unclean_shutdown)) {
257            EG(symbol_table).ht.pDestructor = zend_unclean_zval_ptr_dtor;
258        }
259        zend_hash_graceful_reverse_destroy(&EG(symbol_table).ht);
260    } zend_end_try();
261    EG(valid_symbol_table) = 0;
262
263    zend_try {
264        zval *zeh;
265        /* remove error handlers before destroying classes and functions,
266         * so that if handler used some class, crash would not happen */
267        if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
268            zeh = &EG(user_error_handler);
269            zval_ptr_dtor(zeh);
270            ZVAL_UNDEF(&EG(user_error_handler));
271        }
272
273        if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
274            zeh = &EG(user_exception_handler);
275            zval_ptr_dtor(zeh);
276            ZVAL_UNDEF(&EG(user_exception_handler));
277        }
278
279        zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
280        zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_DESTRUCTOR, 1);
281        zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_DESTRUCTOR, 1);
282    } zend_end_try();
283
284    zend_try {
285        /* Cleanup static data for functions and arrays.
286         * We need a separate cleanup stage because of the following problem:
287         * Suppose we destroy class X, which destroys the class's function table,
288         * and in the function table we have function foo() that has static $bar.
289         * Now if an object of class X is assigned to $bar, its destructor will be
290         * called and will fail since X's function table is in mid-destruction.
291         * So we want first of all to clean up all data and then move to tables destruction.
292         * Note that only run-time accessed data need to be cleaned up, pre-defined data can
293         * not contain objects and thus are not probelmatic */
294        if (EG(full_tables_cleanup)) {
295            ZEND_HASH_FOREACH_PTR(EG(function_table), func) {
296                if (func->type == ZEND_USER_FUNCTION) {
297                    zend_cleanup_op_array_data((zend_op_array *) func);
298                }
299            } ZEND_HASH_FOREACH_END();
300            ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
301                if (ce->type == ZEND_USER_CLASS) {
302                    zend_cleanup_user_class_data(ce);
303                } else {
304                    zend_cleanup_internal_class_data(ce);
305                }
306            } ZEND_HASH_FOREACH_END();
307        } else {
308            ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) {
309                if (func->type != ZEND_USER_FUNCTION) {
310                    break;
311                }
312                zend_cleanup_op_array_data((zend_op_array *) func);
313            } ZEND_HASH_FOREACH_END();
314            ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
315                if (ce->type != ZEND_USER_CLASS) {
316                    break;
317                }
318                zend_cleanup_user_class_data(ce);
319            } ZEND_HASH_FOREACH_END();
320            zend_cleanup_internal_classes();
321        }
322    } zend_end_try();
323
324    zend_try {
325        zend_llist_destroy(&CG(open_files));
326    } zend_end_try();
327
328    zend_try {
329        zend_close_rsrc_list(&EG(regular_list));
330    } zend_end_try();
331
332    zend_try {
333        zend_objects_store_free_object_storage(&EG(objects_store));
334
335        zend_vm_stack_destroy();
336
337        /* Destroy all op arrays */
338        if (EG(full_tables_cleanup)) {
339            zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
340            zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
341        } else {
342            zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function);
343            zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class);
344        }
345
346        while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
347            zend_hash_destroy(&(*EG(symtable_cache_ptr))->ht);
348            FREE_HASHTABLE(*EG(symtable_cache_ptr));
349            EG(symtable_cache_ptr)--;
350        }
351    } zend_end_try();
352
353    zend_try {
354        clean_non_persistent_constants();
355    } zend_end_try();
356
357    zend_try {
358#if 0&&ZEND_DEBUG
359    signal(SIGSEGV, original_sigsegv_handler);
360#endif
361
362        zend_hash_destroy(&EG(included_files));
363
364        zend_stack_destroy(&EG(user_error_handlers_error_reporting));
365        zend_stack_destroy(&EG(user_error_handlers));
366        zend_stack_destroy(&EG(user_exception_handlers));
367        zend_objects_store_destroy(&EG(objects_store));
368        if (EG(in_autoload)) {
369            zend_hash_destroy(EG(in_autoload));
370            FREE_HASHTABLE(EG(in_autoload));
371        }
372    } zend_end_try();
373
374    zend_shutdown_fpu();
375
376    EG(active) = 0;
377}
378/* }}} */
379
380/* return class name and "::" or "". */
381ZEND_API const char *get_active_class_name(const char **space) /* {{{ */
382{
383    zend_function *func;
384
385    if (!zend_is_executing()) {
386        if (space) {
387            *space = "";
388        }
389        return "";
390    }
391
392    func = EG(current_execute_data)->func;
393    switch (func->type) {
394        case ZEND_USER_FUNCTION:
395        case ZEND_INTERNAL_FUNCTION:
396        {
397            zend_class_entry *ce = func->common.scope;
398
399            if (space) {
400                *space = ce ? "::" : "";
401            }
402            return ce ? ce->name->val : "";
403        }
404        default:
405            if (space) {
406                *space = "";
407            }
408            return "";
409    }
410}
411/* }}} */
412
413ZEND_API const char *get_active_function_name(void) /* {{{ */
414{
415    zend_function *func;
416
417    if (!zend_is_executing()) {
418        return NULL;
419    }
420    func = EG(current_execute_data)->func;
421    switch (func->type) {
422        case ZEND_USER_FUNCTION: {
423                zend_string *function_name = func->common.function_name;
424
425                if (function_name) {
426                    return function_name->val;
427                } else {
428                    return "main";
429                }
430            }
431            break;
432        case ZEND_INTERNAL_FUNCTION:
433            return func->common.function_name->val;
434            break;
435        default:
436            return NULL;
437    }
438}
439/* }}} */
440
441ZEND_API const char *zend_get_executed_filename(void) /* {{{ */
442{
443    zend_execute_data *ex = EG(current_execute_data);
444
445    while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
446        ex = ex->prev_execute_data;
447    }
448    if (ex) {
449        return ex->func->op_array.filename->val;
450    } else {
451        return "[no active file]";
452    }
453}
454/* }}} */
455
456ZEND_API uint zend_get_executed_lineno(void) /* {{{ */
457{
458    zend_execute_data *ex = EG(current_execute_data);
459
460    while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
461        ex = ex->prev_execute_data;
462    }
463    if (ex) {
464        if (EG(exception) && ex->opline->opcode == ZEND_HANDLE_EXCEPTION &&
465            ex->opline->lineno == 0 && EG(opline_before_exception)) {
466            return EG(opline_before_exception)->lineno;
467        }
468        return ex->opline->lineno;
469    } else {
470        return 0;
471    }
472}
473/* }}} */
474
475ZEND_API zend_bool zend_is_executing(void) /* {{{ */
476{
477    return EG(current_execute_data) != 0;
478}
479/* }}} */
480
481ZEND_API void _zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
482{
483    i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC);
484}
485/* }}} */
486
487ZEND_API void _zval_internal_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) /* {{{ */
488{
489    if (Z_REFCOUNTED_P(zval_ptr)) {
490        Z_DELREF_P(zval_ptr);
491        if (Z_REFCOUNT_P(zval_ptr) == 0) {
492            _zval_internal_dtor_for_ptr(zval_ptr ZEND_FILE_LINE_CC);
493        }
494    }
495}
496/* }}} */
497
498#define IS_VISITED_CONSTANT         0x80
499#define IS_CONSTANT_VISITED(p)      (Z_TYPE_P(p) & IS_VISITED_CONSTANT)
500#define MARK_CONSTANT_VISITED(p)    Z_TYPE_INFO_P(p) |= IS_VISITED_CONSTANT
501
502ZEND_API int zval_update_constant_ex(zval *p, zend_bool inline_change, zend_class_entry *scope) /* {{{ */
503{
504    zval *const_value;
505    char *colon;
506
507    if (IS_CONSTANT_VISITED(p)) {
508        zend_error(E_ERROR, "Cannot declare self-referencing constant '%s'", Z_STRVAL_P(p));
509    } else if (Z_TYPE_P(p) == IS_CONSTANT) {
510        int refcount;
511
512        SEPARATE_ZVAL_NOREF(p);
513        MARK_CONSTANT_VISITED(p);
514        refcount =  Z_REFCOUNTED_P(p) ? Z_REFCOUNT_P(p) : 1;
515        const_value = zend_get_constant_ex(Z_STR_P(p), scope, Z_CONST_FLAGS_P(p));
516        if (!const_value) {
517            char *actual = Z_STRVAL_P(p);
518
519            if ((colon = (char*)zend_memrchr(Z_STRVAL_P(p), ':', Z_STRLEN_P(p)))) {
520                size_t len;
521
522                zend_error(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(p));
523                len = Z_STRLEN_P(p) - ((colon - Z_STRVAL_P(p)) + 1);
524                if (inline_change) {
525                    zend_string *tmp = zend_string_init(colon + 1, len, 0);
526                    zend_string_release(Z_STR_P(p));
527                    Z_STR_P(p) = tmp;
528                } else {
529                    Z_STR_P(p) = zend_string_init(colon + 1, len, 0);
530                }
531                Z_TYPE_FLAGS_P(p) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE;
532            } else {
533                zend_string *save = Z_STR_P(p);
534                char *slash;
535                size_t actual_len = Z_STRLEN_P(p);
536                if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) && (slash = (char *)zend_memrchr(actual, '\\', actual_len))) {
537                    actual = slash + 1;
538                    actual_len -= (actual - Z_STRVAL_P(p));
539                    if (inline_change) {
540                        zend_string *s = zend_string_init(actual, actual_len, 0);
541                        Z_STR_P(p) = s;
542                        Z_TYPE_FLAGS_P(p) = IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE;
543                    }
544                }
545                if (actual[0] == '\\') {
546                    if (inline_change) {
547                        memmove(Z_STRVAL_P(p), Z_STRVAL_P(p)+1, Z_STRLEN_P(p));
548                        --Z_STRLEN_P(p);
549                    } else {
550                        ++actual;
551                    }
552                    --actual_len;
553                }
554                if ((Z_CONST_FLAGS_P(p) & IS_CONSTANT_UNQUALIFIED) == 0) {
555                    if (save->val[0] == '\\') {
556                        zend_error(E_ERROR, "Undefined constant '%s'", save->val + 1);
557                    } else {
558                        zend_error(E_ERROR, "Undefined constant '%s'", save->val);
559                    }
560                    if (inline_change) {
561                        zend_string_release(save);
562                    }
563                    save = NULL;
564                }
565                zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",  actual,  actual);
566                if (!inline_change) {
567                    ZVAL_STRINGL(p, actual, actual_len);
568                } else {
569                    Z_TYPE_INFO_P(p) = Z_REFCOUNTED_P(p) ?
570                        IS_STRING_EX : IS_INTERNED_STRING_EX;
571                    if (save && save->val != actual) {
572                        zend_string_release(save);
573                    }
574                }
575            }
576        } else {
577            if (inline_change) {
578                zend_string_release(Z_STR_P(p));
579            }
580            ZVAL_COPY_VALUE(p, const_value);
581            if (Z_OPT_CONSTANT_P(p)) {
582                zval_update_constant_ex(p, 1, NULL);
583            }
584            zval_opt_copy_ctor(p);
585        }
586
587        if (Z_REFCOUNTED_P(p)) Z_SET_REFCOUNT_P(p, refcount);
588    } else if (Z_TYPE_P(p) == IS_CONSTANT_AST) {
589        zval tmp;
590        SEPARATE_ZVAL_NOREF(p);
591
592        zend_ast_evaluate(&tmp, Z_ASTVAL_P(p), scope);
593        if (inline_change) {
594            zend_ast_destroy_and_free(Z_ASTVAL_P(p));
595            efree_size(Z_AST_P(p), sizeof(zend_ast_ref));
596        }
597        ZVAL_COPY_VALUE(p, &tmp);
598    }
599    return 0;
600}
601/* }}} */
602
603ZEND_API int zval_update_constant_inline_change(zval *pp, zend_class_entry *scope) /* {{{ */
604{
605    return zval_update_constant_ex(pp, 1, scope);
606}
607/* }}} */
608
609ZEND_API int zval_update_constant_no_inline_change(zval *pp, zend_class_entry *scope) /* {{{ */
610{
611    return zval_update_constant_ex(pp, 0, scope);
612}
613/* }}} */
614
615ZEND_API int zval_update_constant(zval *pp, zend_bool inline_change) /* {{{ */
616{
617    return zval_update_constant_ex(pp, inline_change, NULL);
618}
619/* }}} */
620
621int call_user_function(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[]) /* {{{ */
622{
623    return call_user_function_ex(function_table, object, function_name, retval_ptr, param_count, params, 1, NULL);
624}
625/* }}} */
626
627int call_user_function_ex(HashTable *function_table, zval *object, zval *function_name, zval *retval_ptr, uint32_t param_count, zval params[], int no_separation, zend_array *symbol_table) /* {{{ */
628{
629    zend_fcall_info fci;
630
631    fci.size = sizeof(fci);
632    fci.function_table = function_table;
633    fci.object = object ? Z_OBJ_P(object) : NULL;
634    ZVAL_COPY_VALUE(&fci.function_name, function_name);
635    fci.retval = retval_ptr;
636    fci.param_count = param_count;
637    fci.params = params;
638    fci.no_separation = (zend_bool) no_separation;
639    fci.symbol_table = symbol_table;
640
641    return zend_call_function(&fci, NULL);
642}
643/* }}} */
644
645int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /* {{{ */
646{
647    uint32_t i;
648    zend_class_entry *calling_scope = NULL;
649    zend_execute_data *call, dummy_execute_data;
650    zend_fcall_info_cache fci_cache_local;
651    zend_function *func;
652    zend_class_entry *orig_scope;
653    zval tmp;
654
655    ZVAL_UNDEF(fci->retval);
656
657    if (!EG(active)) {
658        return FAILURE; /* executor is already inactive */
659    }
660
661    if (EG(exception)) {
662        return FAILURE; /* we would result in an instable executor otherwise */
663    }
664
665    switch (fci->size) {
666        case sizeof(zend_fcall_info):
667            break; /* nothing to do currently */
668        default:
669            zend_error(E_ERROR, "Corrupted fcall_info provided to zend_call_function()");
670            break;
671    }
672
673    orig_scope = EG(scope);
674
675    /* Initialize execute_data */
676    if (!EG(current_execute_data)) {
677        /* This only happens when we're called outside any execute()'s
678         * It shouldn't be strictly necessary to NULL execute_data out,
679         * but it may make bugs easier to spot
680         */
681        memset(&dummy_execute_data, 0, sizeof(zend_execute_data));
682        EG(current_execute_data) = &dummy_execute_data;
683    } else if (EG(current_execute_data)->func &&
684               ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
685               EG(current_execute_data)->opline->opcode != ZEND_DO_FCALL) {
686        /* Insert fake frame in case of include or magic calls */
687        dummy_execute_data = *EG(current_execute_data);
688        dummy_execute_data.prev_execute_data = EG(current_execute_data);
689        dummy_execute_data.call = NULL;
690        dummy_execute_data.opline = NULL;
691        dummy_execute_data.func = NULL;
692        EG(current_execute_data) = &dummy_execute_data;
693    }
694
695    if (!fci_cache || !fci_cache->initialized) {
696        zend_string *callable_name;
697        char *error = NULL;
698
699        if (!fci_cache) {
700            fci_cache = &fci_cache_local;
701        }
702
703        if (!zend_is_callable_ex(&fci->function_name, fci->object, IS_CALLABLE_CHECK_SILENT, &callable_name, fci_cache, &error)) {
704            if (error) {
705                zend_error(E_WARNING, "Invalid callback %s, %s", callable_name->val, error);
706                efree(error);
707            }
708            if (callable_name) {
709                zend_string_release(callable_name);
710            }
711            if (EG(current_execute_data) == &dummy_execute_data) {
712                EG(current_execute_data) = dummy_execute_data.prev_execute_data;
713            }
714            return FAILURE;
715        } else if (error) {
716            /* Capitalize the first latter of the error message */
717            if (error[0] >= 'a' && error[0] <= 'z') {
718                error[0] += ('A' - 'a');
719            }
720            zend_error(E_STRICT, "%s", error);
721            efree(error);
722        }
723        zend_string_release(callable_name);
724    }
725
726    func = fci_cache->function_handler;
727    call = zend_vm_stack_push_call_frame(ZEND_CALL_TOP_FUNCTION,
728        func, fci->param_count, fci_cache->called_scope, fci_cache->object, NULL);
729    calling_scope = fci_cache->calling_scope;
730    fci->object = fci_cache->object;
731    if (fci->object &&
732        (!EG(objects_store).object_buckets ||
733         !IS_OBJ_VALID(EG(objects_store).object_buckets[fci->object->handle]))) {
734        if (EG(current_execute_data) == &dummy_execute_data) {
735            EG(current_execute_data) = dummy_execute_data.prev_execute_data;
736        }
737        return FAILURE;
738    }
739
740    if (func->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
741        if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
742            zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", func->common.scope->name->val, func->common.function_name->val);
743        }
744        if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
745            zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
746                func->common.scope ? func->common.scope->name->val : "",
747                func->common.scope ? "::" : "",
748                func->common.function_name->val);
749        }
750    }
751
752    for (i=0; i<fci->param_count; i++) {
753        zval *param;
754
755        if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
756            // TODO: Scalar values don't have reference counters anymore.
757            // They are assumed to be 1, and they may be easily passed by
758            // reference now. However, previously scalars with refcount==1
759            // might be passed and with refcount>1 might not. We can support
760            // only single behavior ???
761#if 0
762            if (Z_REFCOUNTED(fci->params[i]) &&
763                // This solution breaks the following test (omit warning message) ???
764                // Zend/tests/bug61273.phpt
765                // ext/reflection/tests/bug42976.phpt
766                // ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt
767#else
768            if (!Z_REFCOUNTED(fci->params[i]) ||
769                // This solution breaks the following test (emit warning message) ???
770                // ext/pdo_sqlite/tests/pdo_005.phpt
771#endif
772                (!Z_ISREF(fci->params[i]) && Z_REFCOUNT(fci->params[i]) > 1)) {
773
774                if (fci->no_separation &&
775                    !ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
776                    if (i) {
777                        /* hack to clean up the stack */
778                        ZEND_CALL_NUM_ARGS(call) = i;
779                        zend_vm_stack_free_args(call);
780                    }
781                    zend_vm_stack_free_call_frame(call);
782
783                    zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
784                        i+1,
785                        func->common.scope ? func->common.scope->name->val : "",
786                        func->common.scope ? "::" : "",
787                        func->common.function_name->val);
788                    if (EG(current_execute_data) == &dummy_execute_data) {
789                        EG(current_execute_data) = dummy_execute_data.prev_execute_data;
790                    }
791                    return FAILURE;
792                }
793
794                if (Z_REFCOUNTED(fci->params[i])) {
795                    Z_DELREF(fci->params[i]);
796                }
797                ZVAL_DUP(&tmp, &fci->params[i]);
798                ZVAL_NEW_REF(&fci->params[i], &tmp);
799                Z_ADDREF(fci->params[i]);
800            } else if (!Z_ISREF(fci->params[i])) {
801                ZVAL_NEW_REF(&fci->params[i], &fci->params[i]);
802                Z_ADDREF(fci->params[i]);
803            } else if (Z_REFCOUNTED(fci->params[i])) {
804                Z_ADDREF(fci->params[i]);
805            }
806            param = ZEND_CALL_ARG(call, i+1);
807            ZVAL_COPY_VALUE(param, &fci->params[i]);
808        } else if (Z_ISREF(fci->params[i]) &&
809                   /* don't separate references for __call */
810                   (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) == 0 ) {
811            param = ZEND_CALL_ARG(call, i+1);
812            ZVAL_DUP(param, Z_REFVAL(fci->params[i]));
813        } else {
814            param = ZEND_CALL_ARG(call, i+1);
815            ZVAL_COPY(param, &fci->params[i]);
816        }
817    }
818
819    EG(scope) = calling_scope;
820    if (func->common.fn_flags & ZEND_ACC_STATIC) {
821        fci->object = NULL;
822    }
823    if (!fci->object) {
824        Z_OBJ(call->This) = NULL;
825    } else {
826        Z_OBJ(call->This) = fci->object;
827        GC_REFCOUNT(fci->object)++;
828    }
829
830    if (func->type == ZEND_USER_FUNCTION) {
831        EG(scope) = func->common.scope;
832        call->symbol_table = fci->symbol_table;
833        if (EXPECTED((func->op_array.fn_flags & ZEND_ACC_GENERATOR) == 0)) {
834            zend_init_execute_data(call, &func->op_array, fci->retval);
835            zend_execute_ex(call);
836        } else {
837            zend_generator_create_zval(call, &func->op_array, fci->retval);
838        }
839    } else if (func->type == ZEND_INTERNAL_FUNCTION) {
840        int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
841        ZVAL_NULL(fci->retval);
842        if (func->common.scope) {
843            EG(scope) = func->common.scope;
844        }
845        call->prev_execute_data = EG(current_execute_data);
846        call->return_value = NULL; /* this is not a constructor call */
847        EG(current_execute_data) = call;
848        if (EXPECTED(zend_execute_internal == NULL)) {
849            /* saves one function call if zend_execute_internal is not used */
850            func->internal_function.handler(call, fci->retval);
851        } else {
852            zend_execute_internal(call, fci->retval);
853        }
854        EG(current_execute_data) = call->prev_execute_data;
855        zend_vm_stack_free_args(call);
856        zend_vm_stack_free_call_frame(call);
857
858        /*  We shouldn't fix bad extensions here,
859            because it can break proper ones (Bug #34045)
860        if (!EX(function_state).function->common.return_reference)
861        {
862            INIT_PZVAL(f->retval);
863        }*/
864        if (EG(exception)) {
865            zval_ptr_dtor(fci->retval);
866            ZVAL_UNDEF(fci->retval);
867        }
868
869        if (call_via_handler) {
870            /* We must re-initialize function again */
871            fci_cache->initialized = 0;
872        }
873    } else { /* ZEND_OVERLOADED_FUNCTION */
874        ZVAL_NULL(fci->retval);
875
876        /* Not sure what should be done here if it's a static method */
877        if (fci->object) {
878            call->prev_execute_data = EG(current_execute_data);
879            EG(current_execute_data) = call;
880            fci->object->handlers->call_method(func->common.function_name, fci->object, call, fci->retval);
881            EG(current_execute_data) = call->prev_execute_data;
882        } else {
883            zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
884        }
885
886        zend_vm_stack_free_args(call);
887        zend_vm_stack_free_call_frame(call);
888
889        if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
890            zend_string_release(func->common.function_name);
891        }
892        efree(func);
893
894        if (EG(exception)) {
895            zval_ptr_dtor(fci->retval);
896            ZVAL_UNDEF(fci->retval);
897        }
898    }
899
900    if (fci->object) {
901        OBJ_RELEASE(fci->object);
902    }
903
904    EG(scope) = orig_scope;
905    if (EG(current_execute_data) == &dummy_execute_data) {
906        EG(current_execute_data) = dummy_execute_data.prev_execute_data;
907    }
908
909    if (EG(exception)) {
910        zend_throw_exception_internal(NULL);
911    }
912    return SUCCESS;
913}
914/* }}} */
915
916ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, const zval *key, int use_autoload) /* {{{ */
917{
918    zend_class_entry *ce = NULL;
919    zval args[1];
920    zval local_retval;
921    int retval;
922    zend_string *lc_name;
923    zend_fcall_info fcall_info;
924    zend_fcall_info_cache fcall_cache;
925
926    if (key) {
927        lc_name = Z_STR_P(key);
928    } else {
929        if (name == NULL || !name->len) {
930            return NULL;
931        }
932
933        if (name->val[0] == '\\') {
934            lc_name = zend_string_alloc(name->len - 1, 0);
935            zend_str_tolower_copy(lc_name->val, name->val + 1, name->len - 1);
936        } else {
937            lc_name = zend_string_alloc(name->len, 0);
938            zend_str_tolower_copy(lc_name->val, name->val, name->len);
939        }
940    }
941
942    ce = zend_hash_find_ptr(EG(class_table), lc_name);
943    if (ce) {
944        if (!key) {
945            zend_string_free(lc_name);
946        }
947        return ce;
948    }
949
950    /* The compiler is not-reentrant. Make sure we __autoload() only during run-time
951     * (doesn't impact functionality of __autoload()
952    */
953    if (!use_autoload || zend_is_compiling()) {
954        if (!key) {
955            zend_string_free(lc_name);
956        }
957        return NULL;
958    }
959
960    if (!EG(autoload_func)) {
961        zend_function *func = zend_hash_str_find_ptr(EG(function_table), ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1);
962        if (func) {
963            EG(autoload_func) = func;
964        } else {
965            if (!key) {
966                zend_string_free(lc_name);
967            }
968            return NULL;
969        }
970
971    }
972
973    /* Verify class name before passing it to __autoload() */
974    if (strspn(name->val, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\") != name->len) {
975        if (!key) {
976            zend_string_free(lc_name);
977        }
978        return NULL;
979    }
980
981    if (EG(in_autoload) == NULL) {
982        ALLOC_HASHTABLE(EG(in_autoload));
983        zend_hash_init(EG(in_autoload), 8, NULL, NULL, 0);
984    }
985
986    if (zend_hash_add_empty_element(EG(in_autoload), lc_name) == NULL) {
987        if (!key) {
988            zend_string_free(lc_name);
989        }
990        return NULL;
991    }
992
993    ZVAL_UNDEF(&local_retval);
994
995    if (name->val[0] == '\\') {
996        ZVAL_STRINGL(&args[0], name->val + 1, name->len - 1);
997    } else {
998        ZVAL_STR_COPY(&args[0], name);
999    }
1000
1001    fcall_info.size = sizeof(fcall_info);
1002    fcall_info.function_table = EG(function_table);
1003    ZVAL_STR_COPY(&fcall_info.function_name, EG(autoload_func)->common.function_name);
1004    fcall_info.symbol_table = NULL;
1005    fcall_info.retval = &local_retval;
1006    fcall_info.param_count = 1;
1007    fcall_info.params = args;
1008    fcall_info.object = NULL;
1009    fcall_info.no_separation = 1;
1010
1011    fcall_cache.initialized = 1;
1012    fcall_cache.function_handler = EG(autoload_func);
1013    fcall_cache.calling_scope = NULL;
1014    fcall_cache.called_scope = NULL;
1015    fcall_cache.object = NULL;
1016
1017    zend_exception_save();
1018    retval = zend_call_function(&fcall_info, &fcall_cache);
1019    zend_exception_restore();
1020
1021    zval_ptr_dtor(&args[0]);
1022    zval_dtor(&fcall_info.function_name);
1023
1024    zend_hash_del(EG(in_autoload), lc_name);
1025
1026    zval_ptr_dtor(&local_retval);
1027
1028    if (retval == SUCCESS) {
1029        ce = zend_hash_find_ptr(EG(class_table), lc_name);
1030    }
1031    if (!key) {
1032        zend_string_free(lc_name);
1033    }
1034    return ce;
1035}
1036/* }}} */
1037
1038ZEND_API zend_class_entry *zend_lookup_class(zend_string *name) /* {{{ */
1039{
1040    return zend_lookup_class_ex(name, NULL, 1);
1041}
1042/* }}} */
1043
1044ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name) /* {{{ */
1045{
1046    zval pv;
1047    zend_op_array *new_op_array;
1048    uint32_t original_compiler_options;
1049    int retval;
1050
1051    if (retval_ptr) {
1052        ZVAL_NEW_STR(&pv, zend_string_alloc(str_len + sizeof("return ;")-1, 1));
1053        memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1);
1054        memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, str, str_len);
1055        Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';';
1056        Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
1057    } else {
1058        ZVAL_STRINGL(&pv, str, str_len);
1059    }
1060
1061    /*printf("Evaluating '%s'\n", pv.value.str.val);*/
1062
1063    original_compiler_options = CG(compiler_options);
1064    CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
1065    new_op_array = zend_compile_string(&pv, string_name);
1066    CG(compiler_options) = original_compiler_options;
1067
1068    if (new_op_array) {
1069        zval local_retval;
1070
1071        EG(no_extensions)=1;
1072
1073        zend_try {
1074            ZVAL_UNDEF(&local_retval);
1075            zend_execute(new_op_array, &local_retval);
1076        } zend_catch {
1077            destroy_op_array(new_op_array);
1078            efree_size(new_op_array, sizeof(zend_op_array));
1079            zend_bailout();
1080        } zend_end_try();
1081
1082        if (Z_TYPE(local_retval) != IS_UNDEF) {
1083            if (retval_ptr) {
1084                ZVAL_COPY_VALUE(retval_ptr, &local_retval);
1085            } else {
1086                zval_ptr_dtor(&local_retval);
1087            }
1088        } else {
1089            if (retval_ptr) {
1090                ZVAL_NULL(retval_ptr);
1091            }
1092        }
1093
1094        EG(no_extensions)=0;
1095        destroy_op_array(new_op_array);
1096        efree_size(new_op_array, sizeof(zend_op_array));
1097        retval = SUCCESS;
1098    } else {
1099        retval = FAILURE;
1100    }
1101    zval_dtor(&pv);
1102    return retval;
1103}
1104/* }}} */
1105
1106ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name) /* {{{ */
1107{
1108    return zend_eval_stringl(str, strlen(str), retval_ptr, string_name);
1109}
1110/* }}} */
1111
1112ZEND_API int zend_eval_stringl_ex(char *str, size_t str_len, zval *retval_ptr, char *string_name, int handle_exceptions) /* {{{ */
1113{
1114    int result;
1115
1116    result = zend_eval_stringl(str, str_len, retval_ptr, string_name);
1117    if (handle_exceptions && EG(exception)) {
1118        zend_exception_error(EG(exception), E_ERROR);
1119        result = FAILURE;
1120    }
1121    return result;
1122}
1123/* }}} */
1124
1125ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions) /* {{{ */
1126{
1127    return zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
1128}
1129/* }}} */
1130
1131ZEND_API void zend_timeout(int dummy) /* {{{ */
1132{
1133
1134    if (zend_on_timeout) {
1135#ifdef ZEND_SIGNALS
1136        /*
1137           We got here because we got a timeout signal, so we are in a signal handler
1138           at this point. However, we want to be able to timeout any user-supplied
1139           shutdown functions, so pretend we are not in a signal handler while we are
1140           calling these
1141        */
1142        SIGG(running) = 0;
1143#endif
1144        zend_on_timeout(EG(timeout_seconds));
1145    }
1146
1147    zend_error(E_ERROR, "Maximum execution time of %pd second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
1148}
1149/* }}} */
1150
1151#ifdef ZEND_WIN32
1152VOID CALLBACK tq_timer_cb(PVOID arg, BOOLEAN timed_out)
1153{
1154    zend_bool *php_timed_out;
1155
1156    /* The doc states it'll be always true, however it theoretically
1157        could be FALSE when the thread was signaled. */
1158    if (!timed_out) {
1159        return;
1160    }
1161
1162    php_timed_out = (zend_bool *)arg;
1163    *php_timed_out = 1;
1164}
1165#endif
1166
1167/* This one doesn't exists on QNX */
1168#ifndef SIGPROF
1169#define SIGPROF 27
1170#endif
1171
1172void zend_set_timeout(zend_long seconds, int reset_signals) /* {{{ */
1173{
1174
1175    EG(timeout_seconds) = seconds;
1176
1177#ifdef ZEND_WIN32
1178    if(!seconds) {
1179        return;
1180    }
1181
1182        /* Don't use ChangeTimerQueueTimer() as it will not restart an expired
1183        timer, so we could end up with just an ignored timeout. Instead
1184        delete and recreate. */
1185    if (NULL != tq_timer) {
1186        if (!DeleteTimerQueueTimer(NULL, tq_timer, NULL)) {
1187            EG(timed_out) = 0;
1188            tq_timer = NULL;
1189            zend_error(E_ERROR, "Could not delete queued timer");
1190            return;
1191        }
1192        tq_timer = NULL;
1193    }
1194
1195    /* XXX passing NULL means the default timer queue provided by the system is used */
1196    if (!CreateTimerQueueTimer(&tq_timer, NULL, (WAITORTIMERCALLBACK)tq_timer_cb, (VOID*)&EG(timed_out), seconds*1000, 0, WT_EXECUTEONLYONCE)) {
1197        EG(timed_out) = 0;
1198        tq_timer = NULL;
1199        zend_error(E_ERROR, "Could not queue new timer");
1200        return;
1201    }
1202    EG(timed_out) = 0;
1203#else
1204#   ifdef HAVE_SETITIMER
1205    {
1206        struct itimerval t_r;       /* timeout requested */
1207        int signo;
1208
1209        if(seconds) {
1210            t_r.it_value.tv_sec = seconds;
1211            t_r.it_value.tv_usec = t_r.it_interval.tv_sec = t_r.it_interval.tv_usec = 0;
1212
1213#   ifdef __CYGWIN__
1214            setitimer(ITIMER_REAL, &t_r, NULL);
1215        }
1216        signo = SIGALRM;
1217#   else
1218            setitimer(ITIMER_PROF, &t_r, NULL);
1219        }
1220        signo = SIGPROF;
1221#   endif
1222
1223        if (reset_signals) {
1224#   ifdef ZEND_SIGNALS
1225            zend_signal(signo, zend_timeout);
1226#   else
1227            sigset_t sigset;
1228
1229            signal(signo, zend_timeout);
1230            sigemptyset(&sigset);
1231            sigaddset(&sigset, signo);
1232            sigprocmask(SIG_UNBLOCK, &sigset, NULL);
1233#   endif
1234        }
1235    }
1236#   endif /* HAVE_SETITIMER */
1237#endif
1238}
1239/* }}} */
1240
1241void zend_unset_timeout(void) /* {{{ */
1242{
1243#ifdef ZEND_WIN32
1244    if (NULL != tq_timer) {
1245        if (!DeleteTimerQueueTimer(NULL, tq_timer, NULL)) {
1246            EG(timed_out) = 0;
1247            tq_timer = NULL;
1248            zend_error(E_ERROR, "Could not delete queued timer");
1249            return;
1250        }
1251        tq_timer = NULL;
1252    }
1253    EG(timed_out) = 0;
1254#else
1255#   ifdef HAVE_SETITIMER
1256    if (EG(timeout_seconds)) {
1257        struct itimerval no_timeout;
1258
1259        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;
1260
1261#ifdef __CYGWIN__
1262        setitimer(ITIMER_REAL, &no_timeout, NULL);
1263#else
1264        setitimer(ITIMER_PROF, &no_timeout, NULL);
1265#endif
1266    }
1267#   endif
1268#endif
1269}
1270/* }}} */
1271
1272zend_class_entry *zend_fetch_class(zend_string *class_name, int fetch_type) /* {{{ */
1273{
1274    zend_class_entry *ce;
1275    int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
1276    int silent       = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0;
1277
1278    fetch_type &= ZEND_FETCH_CLASS_MASK;
1279
1280check_fetch_type:
1281    switch (fetch_type) {
1282        case ZEND_FETCH_CLASS_SELF:
1283            if (!EG(scope)) {
1284                zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
1285            }
1286            return EG(scope);
1287        case ZEND_FETCH_CLASS_PARENT:
1288            if (!EG(scope)) {
1289                zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
1290            }
1291            if (!EG(scope)->parent) {
1292                zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
1293            }
1294            return EG(scope)->parent;
1295        case ZEND_FETCH_CLASS_STATIC:
1296            if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) {
1297                zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
1298            }
1299            return EG(current_execute_data)->called_scope;
1300        case ZEND_FETCH_CLASS_AUTO: {
1301                fetch_type = zend_get_class_fetch_type(class_name);
1302                if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) {
1303                    goto check_fetch_type;
1304                }
1305            }
1306            break;
1307    }
1308
1309    if ((ce = zend_lookup_class_ex(class_name, NULL, use_autoload)) == NULL) {
1310        if (use_autoload) {
1311            if (!silent && !EG(exception)) {
1312                if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
1313                    zend_error(E_ERROR, "Interface '%s' not found", class_name->val);
1314                } else if (fetch_type == ZEND_FETCH_CLASS_TRAIT) {
1315                    zend_error(E_ERROR, "Trait '%s' not found", class_name->val);
1316                } else {
1317                    zend_error(E_ERROR, "Class '%s' not found", class_name->val);
1318                }
1319            }
1320        }
1321        return NULL;
1322    }
1323    return ce;
1324}
1325/* }}} */
1326
1327zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type) /* {{{ */
1328{
1329    zend_class_entry *ce;
1330    int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
1331
1332    if ((ce = zend_lookup_class_ex(class_name, key, use_autoload)) == NULL) {
1333        if (use_autoload) {
1334            if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) {
1335                if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
1336                    zend_error(E_ERROR, "Interface '%s' not found", class_name->val);
1337                } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
1338                    zend_error(E_ERROR, "Trait '%s' not found", class_name->val);
1339                } else {
1340                    zend_error(E_ERROR, "Class '%s' not found", class_name->val);
1341                }
1342            }
1343        }
1344        return NULL;
1345    }
1346    return ce;
1347}
1348/* }}} */
1349
1350#define MAX_ABSTRACT_INFO_CNT 3
1351#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
1352#define DISPLAY_ABSTRACT_FN(idx) \
1353    ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
1354    ai.afn[idx] ? "::" : "", \
1355    ai.afn[idx] ? ai.afn[idx]->common.function_name->val : "", \
1356    ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
1357
1358typedef struct _zend_abstract_info {
1359    zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
1360    int cnt;
1361    int ctor;
1362} zend_abstract_info;
1363
1364static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */
1365{
1366    if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1367        if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
1368            ai->afn[ai->cnt] = fn;
1369        }
1370        if (fn->common.fn_flags & ZEND_ACC_CTOR) {
1371            if (!ai->ctor) {
1372                ai->cnt++;
1373                ai->ctor = 1;
1374            } else {
1375                ai->afn[ai->cnt] = NULL;
1376            }
1377        } else {
1378            ai->cnt++;
1379        }
1380    }
1381}
1382/* }}} */
1383
1384void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
1385{
1386    zend_function *func;
1387    zend_abstract_info ai;
1388
1389    if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1390        memset(&ai, 0, sizeof(ai));
1391
1392        ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
1393            zend_verify_abstract_class_function(func, &ai);
1394        } ZEND_HASH_FOREACH_END();
1395
1396        if (ai.cnt) {
1397            zend_error(E_ERROR, "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
1398                ce->name->val, ai.cnt,
1399                ai.cnt > 1 ? "s" : "",
1400                DISPLAY_ABSTRACT_FN(0),
1401                DISPLAY_ABSTRACT_FN(1),
1402                DISPLAY_ABSTRACT_FN(2)
1403                );
1404        }
1405    }
1406}
1407/* }}} */
1408
1409ZEND_API int zend_delete_global_variable(zend_string *name) /* {{{ */
1410{
1411    return zend_hash_del_ind(&EG(symbol_table).ht, name);
1412}
1413/* }}} */
1414
1415ZEND_API zend_array *zend_rebuild_symbol_table(void) /* {{{ */
1416{
1417    int i;
1418    zend_execute_data *ex;
1419    zend_array *symbol_table;
1420
1421    /* Search for last called user function */
1422    ex = EG(current_execute_data);
1423    while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->common.type))) {
1424        ex = ex->prev_execute_data;
1425    }
1426    if (!ex) {
1427        return NULL;
1428    }
1429    if (ex->symbol_table) {
1430        return ex->symbol_table;
1431    }
1432
1433    if (EG(symtable_cache_ptr) >= EG(symtable_cache)) {
1434        /*printf("Cache hit!  Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/
1435        symbol_table = ex->symbol_table = *(EG(symtable_cache_ptr)--);
1436    } else {
1437        symbol_table = ex->symbol_table = emalloc(sizeof(zend_array));
1438        GC_REFCOUNT(symbol_table) = 0;
1439        GC_TYPE_INFO(symbol_table) = IS_ARRAY;
1440        zend_hash_init(&symbol_table->ht, ex->func->op_array.last_var, NULL, ZVAL_PTR_DTOR, 0);
1441        /*printf("Cache miss!  Initialized %x\n", EG(active_symbol_table));*/
1442    }
1443    for (i = 0; i < ex->func->op_array.last_var; i++) {
1444        zval zv;
1445
1446        ZVAL_INDIRECT(&zv, ZEND_CALL_VAR_NUM(ex, i));
1447        zend_hash_add_new(&symbol_table->ht,
1448            ex->func->op_array.vars[i], &zv);
1449    }
1450    return symbol_table;
1451}
1452/* }}} */
1453
1454ZEND_API void zend_attach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1455{
1456    int i;
1457    zend_op_array *op_array = &execute_data->func->op_array;
1458    HashTable *ht = &execute_data->symbol_table->ht;
1459
1460    /* copy real values from symbol table into CV slots and create
1461       INDIRECT references to CV in symbol table  */
1462    for (i = 0; i < op_array->last_var; i++) {
1463        zval *zv = zend_hash_find(ht, op_array->vars[i]);
1464
1465        if (zv) {
1466            if (Z_TYPE_P(zv) == IS_INDIRECT) {
1467                zval *val = Z_INDIRECT_P(zv);
1468
1469                ZVAL_COPY_VALUE(EX_VAR_NUM(i), val);
1470            } else {
1471                ZVAL_COPY_VALUE(EX_VAR_NUM(i), zv);
1472            }
1473        } else {
1474            ZVAL_UNDEF(EX_VAR_NUM(i));
1475            zv = zend_hash_add_new(ht, op_array->vars[i], EX_VAR_NUM(i));
1476        }
1477        ZVAL_INDIRECT(zv, EX_VAR_NUM(i));
1478    }
1479}
1480/* }}} */
1481
1482ZEND_API void zend_detach_symbol_table(zend_execute_data *execute_data) /* {{{ */
1483{
1484    int i;
1485    zend_op_array *op_array = &execute_data->func->op_array;
1486    HashTable *ht = &execute_data->symbol_table->ht;
1487
1488    /* copy real values from CV slots into symbol table */
1489    for (i = 0; i < op_array->last_var; i++) {
1490        if (Z_TYPE_P(EX_VAR_NUM(i)) == IS_UNDEF) {
1491            zend_hash_del(ht, op_array->vars[i]);
1492        } else {
1493            zend_hash_update(ht, op_array->vars[i], EX_VAR_NUM(i));
1494            ZVAL_UNDEF(EX_VAR_NUM(i));
1495        }
1496    }
1497}
1498/* }}} */
1499
1500ZEND_API int zend_set_local_var(zend_string *name, zval *value, int force) /* {{{ */
1501{
1502    zend_execute_data *execute_data = EG(current_execute_data);
1503
1504    while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1505        execute_data = execute_data->prev_execute_data;
1506    }
1507
1508    if (execute_data) {
1509        if (!execute_data->symbol_table) {
1510            zend_ulong h = zend_string_hash_val(name);
1511            zend_op_array *op_array = &execute_data->func->op_array;
1512            int i;
1513
1514            for (i = 0; i < op_array->last_var; i++) {
1515                if (op_array->vars[i]->h == h &&
1516                    op_array->vars[i]->len == name->len &&
1517                    memcmp(op_array->vars[i]->val, name->val, name->len) == 0) {
1518                    ZVAL_COPY_VALUE(EX_VAR_NUM(i), value);
1519                    return SUCCESS;
1520                }
1521            }
1522            if (force) {
1523                zend_array *symbol_table = zend_rebuild_symbol_table();
1524                if (symbol_table) {
1525                    return zend_hash_update(&symbol_table->ht, name, value) ? SUCCESS : FAILURE;;
1526                }
1527            }
1528        } else {
1529            return (zend_hash_update_ind(&execute_data->symbol_table->ht, name, value) != NULL) ? SUCCESS : FAILURE;
1530        }
1531    }
1532    return FAILURE;
1533}
1534/* }}} */
1535
1536ZEND_API int zend_set_local_var_str(const char *name, size_t len, zval *value, int force) /* {{{ */
1537{
1538    zend_execute_data *execute_data = EG(current_execute_data);
1539
1540    while (execute_data && (!execute_data->func || !ZEND_USER_CODE(execute_data->func->common.type))) {
1541        execute_data = execute_data->prev_execute_data;
1542    }
1543
1544    if (execute_data) {
1545        if (!execute_data->symbol_table) {
1546            zend_ulong h = zend_hash_func(name, len);
1547            zend_op_array *op_array = &execute_data->func->op_array;
1548            int i;
1549
1550            for (i = 0; i < op_array->last_var; i++) {
1551                if (op_array->vars[i]->h == h &&
1552                    op_array->vars[i]->len == len &&
1553                    memcmp(op_array->vars[i]->val, name, len) == 0) {
1554                    zval_ptr_dtor(EX_VAR_NUM(i));
1555                    ZVAL_COPY_VALUE(EX_VAR_NUM(i), value);
1556                    return SUCCESS;
1557                }
1558            }
1559
1560            if (force) {
1561                zend_array *symbol_table = zend_rebuild_symbol_table();
1562                if (symbol_table) {
1563                    return zend_hash_str_update(&symbol_table->ht, name, len, value) ? SUCCESS : FAILURE;;
1564                }
1565            }
1566        } else {
1567            return (zend_hash_str_update_ind(&execute_data->symbol_table->ht, name, len, value) != NULL) ? SUCCESS : FAILURE;
1568        }
1569    }
1570    return FAILURE;
1571}
1572/* }}} */
1573
1574/*
1575 * Local variables:
1576 * tab-width: 4
1577 * c-basic-offset: 4
1578 * indent-tabs-mode: t
1579 * End:
1580 */
1581