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