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