1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2015 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   |          Andrei Zmievski <andrei@php.net>                            |
18   +----------------------------------------------------------------------+
19*/
20
21/* $Id$ */
22
23#include "zend.h"
24#include "zend_execute.h"
25#include "zend_API.h"
26#include "zend_modules.h"
27#include "zend_constants.h"
28#include "zend_exceptions.h"
29#include "zend_closures.h"
30#include "zend_inheritance.h"
31
32#ifdef HAVE_STDARG_H
33#include <stdarg.h>
34#endif
35
36/* these variables are true statics/globals, and have to be mutex'ed on every access */
37ZEND_API HashTable module_registry;
38
39static zend_module_entry **module_request_startup_handlers;
40static zend_module_entry **module_request_shutdown_handlers;
41static zend_module_entry **module_post_deactivate_handlers;
42
43static zend_class_entry  **class_cleanup_handlers;
44
45/* this function doesn't check for too many parameters */
46ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */
47{
48    int arg_count;
49    va_list ptr;
50    zval **param, *param_ptr;
51
52    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
53    arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
54
55    if (param_count>arg_count) {
56        return FAILURE;
57    }
58
59    va_start(ptr, param_count);
60
61    while (param_count-->0) {
62        param = va_arg(ptr, zval **);
63        if (!Z_ISREF_P(param_ptr) && Z_REFCOUNT_P(param_ptr) > 1) {
64            zval new_tmp;
65
66            ZVAL_DUP(&new_tmp, param_ptr);
67            Z_DELREF_P(param_ptr);
68            ZVAL_COPY_VALUE(param_ptr, &new_tmp);
69        }
70        *param = param_ptr;
71        param_ptr++;
72    }
73    va_end(ptr);
74
75    return SUCCESS;
76}
77/* }}} */
78
79/* Zend-optimized Extended functions */
80/* this function doesn't check for too many parameters */
81ZEND_API int zend_get_parameters_ex(int param_count, ...) /* {{{ */
82{
83    int arg_count;
84    va_list ptr;
85    zval **param, *param_ptr;
86
87    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
88    arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
89
90    if (param_count>arg_count) {
91        return FAILURE;
92    }
93
94    va_start(ptr, param_count);
95    while (param_count-->0) {
96        param = va_arg(ptr, zval **);
97        *param = param_ptr;
98        param_ptr++;
99    }
100    va_end(ptr);
101
102    return SUCCESS;
103}
104/* }}} */
105
106ZEND_API int _zend_get_parameters_array_ex(int param_count, zval *argument_array) /* {{{ */
107{
108    zval *param_ptr;
109    int arg_count;
110
111    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
112    arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
113
114    if (param_count>arg_count) {
115        return FAILURE;
116    }
117
118    while (param_count-->0) {
119        ZVAL_COPY_VALUE(argument_array, param_ptr);
120        argument_array++;
121        param_ptr++;
122    }
123
124    return SUCCESS;
125}
126/* }}} */
127
128ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array) /* {{{ */
129{
130    zval *param_ptr;
131    int arg_count;
132
133    param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
134    arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
135
136    if (param_count>arg_count) {
137        return FAILURE;
138    }
139
140    while (param_count-->0) {
141        if (Z_REFCOUNTED_P(param_ptr)) {
142            Z_ADDREF_P(param_ptr);
143        }
144        zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr);
145        param_ptr++;
146    }
147
148    return SUCCESS;
149}
150/* }}} */
151
152ZEND_API void zend_wrong_param_count(void) /* {{{ */
153{
154    const char *space;
155    const char *class_name = get_active_class_name(&space);
156
157    zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name());
158}
159/* }}} */
160
161/* Argument parsing API -- andrei */
162ZEND_API char *zend_get_type_by_const(int type) /* {{{ */
163{
164    switch(type) {
165        case IS_FALSE:
166        case IS_TRUE:
167        case _IS_BOOL:
168            return "boolean";
169        case IS_LONG:
170            return "integer";
171        case IS_DOUBLE:
172            return "float";
173        case IS_STRING:
174            return "string";
175        case IS_OBJECT:
176            return "object";
177        case IS_RESOURCE:
178            return "resource";
179        case IS_NULL:
180            return "null";
181        case IS_CALLABLE:
182            return "callable";
183        case IS_ARRAY:
184            return "array";
185        default:
186            return "unknown";
187    }
188}
189/* }}} */
190
191ZEND_API char *zend_zval_type_name(const zval *arg) /* {{{ */
192{
193    ZVAL_DEREF(arg);
194    return zend_get_type_by_const(Z_TYPE_P(arg));
195}
196/* }}} */
197
198#ifdef FAST_ZPP
199ZEND_API void ZEND_FASTCALL zend_wrong_paramers_count_error(int num_args, int min_num_args, int max_num_args) /* {{{ */
200{
201    zend_function *active_function = EG(current_execute_data)->func;
202    const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
203
204    zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects %s %d parameter%s, %d given",
205        class_name, \
206        class_name[0] ? "::" : "", \
207        active_function->common.function_name->val,
208        min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
209        num_args < min_num_args ? min_num_args : max_num_args,
210        (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
211        num_args);
212}
213/* }}} */
214
215ZEND_API void ZEND_FASTCALL zend_wrong_paramer_type_error(int num, zend_expected_type expected_type, zval *arg) /* {{{ */
216{
217    const char *space;
218    const char *class_name = get_active_class_name(&space);
219    static const char * const expected_error[] = {
220        Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR)
221        NULL
222    };
223
224    zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given",
225        class_name, space, get_active_function_name(), num, expected_error[expected_type], zend_zval_type_name(arg));
226}
227/* }}} */
228
229ZEND_API void ZEND_FASTCALL zend_wrong_paramer_class_error(int num, char *name, zval *arg) /* {{{ */
230{
231    const char *space;
232    const char *class_name = get_active_class_name(&space);
233
234    zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given",
235        class_name, space, get_active_function_name(), num, name, zend_zval_type_name(arg));
236}
237/* }}} */
238
239ZEND_API void ZEND_FASTCALL zend_wrong_callback_error(int severity, int num, char *error) /* {{{ */
240{
241    const char *space;
242    const char *class_name = get_active_class_name(&space);
243
244    if (severity == E_WARNING) {
245        zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a valid callback, %s",
246            class_name, space, get_active_function_name(), num, error);
247    } else {
248        zend_error(severity, "%s%s%s() expects parameter %d to be a valid callback, %s",
249            class_name, space, get_active_function_name(), num, error);
250    }
251    efree(error);
252}
253/* }}} */
254
255ZEND_API int ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, int num, int check_null) /* {{{ */
256{
257    zend_class_entry *ce_base = *pce;
258
259    if (check_null && Z_TYPE_P(arg) == IS_NULL) {
260        *pce = NULL;
261        return 1;
262    }
263    convert_to_string_ex(arg);
264    *pce = zend_lookup_class(Z_STR_P(arg));
265    if (ce_base) {
266        if ((!*pce || !instanceof_function(*pce, ce_base))) {
267            const char *space;
268            const char *class_name = get_active_class_name(&space);
269
270            zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a class name derived from %s, '%s' given",
271                class_name, space, get_active_function_name(), num,
272                ce_base->name->val, Z_STRVAL_P(arg));
273            *pce = NULL;
274            return 0;
275        }
276    }
277    if (!*pce) {
278        const char *space;
279        const char *class_name = get_active_class_name(&space);
280
281        zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be a valid class name, '%s' given",
282            class_name, space, get_active_function_name(), num,
283            Z_STRVAL_P(arg));
284        return 0;
285    }
286    return 1;
287}
288/* }}} */
289#endif
290
291ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_weak(zval *arg, zend_bool *dest) /* {{{ */
292{
293    if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) {
294        *dest = zend_is_true(arg);
295    } else {
296        return 0;
297    }
298    return 1;
299}
300/* }}} */
301
302ZEND_API int ZEND_FASTCALL zend_parse_arg_bool_slow(zval *arg, zend_bool *dest) /* {{{ */
303{
304    if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
305        return 0;
306    }
307    return zend_parse_arg_bool_weak(arg, dest);
308}
309/* }}} */
310
311ZEND_API int ZEND_FASTCALL zend_parse_arg_long_weak(zval *arg, zend_long *dest) /* {{{ */
312{
313    if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
314        if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
315            return 0;
316        }
317        if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg)))) {
318            return 0;
319        } else {
320            *dest = zend_dval_to_lval(Z_DVAL_P(arg));
321        }
322    } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
323        double d;
324        int type;
325
326        if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) {
327            if (EXPECTED(type != 0)) {
328                if (UNEXPECTED(zend_isnan(d))) {
329                    return 0;
330                }
331                if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(d))) {
332                    return 0;
333                } else {
334                    *dest = zend_dval_to_lval(d);
335                }
336            } else {
337                return 0;
338            }
339        }
340    } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
341        *dest = 0;
342    } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
343        *dest = 1;
344    } else {
345        return 0;
346    }
347    return 1;
348}
349/* }}} */
350
351ZEND_API int ZEND_FASTCALL zend_parse_arg_long_slow(zval *arg, zend_long *dest) /* {{{ */
352{
353    if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
354        return 0;
355    }
356    return zend_parse_arg_long_weak(arg, dest);
357}
358/* }}} */
359
360ZEND_API int ZEND_FASTCALL zend_parse_arg_long_cap_weak(zval *arg, zend_long *dest) /* {{{ */
361{
362    if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
363        if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
364            return 0;
365        }
366        if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg)))) {
367            *dest = (Z_DVAL_P(arg) > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
368        } else {
369            *dest = zend_dval_to_lval(Z_DVAL_P(arg));
370        }
371    } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
372        double d;
373        int type;
374
375        if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) {
376            if (EXPECTED(type != 0)) {
377                if (UNEXPECTED(zend_isnan(d))) {
378                    return 0;
379                }
380                if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(d))) {
381                    *dest = (d > 0) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
382                } else {
383                    *dest = zend_dval_to_lval(d);
384                }
385            } else {
386                return 0;
387            }
388        }
389    } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
390        *dest = 0;
391    } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
392        *dest = 1;
393    } else {
394        return 0;
395    }
396    return 1;
397}
398/* }}} */
399
400ZEND_API int ZEND_FASTCALL zend_parse_arg_long_cap_slow(zval *arg, zend_long *dest) /* {{{ */
401{
402    if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
403        return 0;
404    }
405    return zend_parse_arg_long_cap_weak(arg, dest);
406}
407/* }}} */
408
409ZEND_API int ZEND_FASTCALL zend_parse_arg_double_weak(zval *arg, double *dest) /* {{{ */
410{
411    if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
412        *dest = (double)Z_LVAL_P(arg);
413    } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
414        zend_long l;
415        int type;
416
417        if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), &l, dest)) != IS_DOUBLE)) {
418            if (EXPECTED(type != 0)) {
419                *dest = (double)(l);
420            } else {
421                return 0;
422            }
423        }
424    } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
425        *dest = 0.0;
426    } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
427        *dest = 1.0;
428    } else {
429        return 0;
430    }
431    return 1;
432}
433/* }}} */
434
435ZEND_API int ZEND_FASTCALL zend_parse_arg_double_slow(zval *arg, double *dest) /* {{{ */
436{
437    if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
438        /* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */
439        *dest = (double)Z_LVAL_P(arg);
440    } else if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
441        return 0;
442    }
443    return zend_parse_arg_double_weak(arg, dest);
444}
445/* }}} */
446
447ZEND_API int ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest) /* {{{ */
448{
449    if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {
450        convert_to_string(arg);
451        *dest = Z_STR_P(arg);
452    } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
453        if (Z_OBJ_HANDLER_P(arg, cast_object)) {
454            zval obj;
455            if (Z_OBJ_HANDLER_P(arg, cast_object)(arg, &obj, IS_STRING) == SUCCESS) {
456                zval_ptr_dtor(arg);
457                ZVAL_COPY_VALUE(arg, &obj);
458                *dest = Z_STR_P(arg);
459                return 1;
460            }
461        }
462        /* Standard PHP objects */
463        if (Z_OBJ_HT_P(arg) == &std_object_handlers || !Z_OBJ_HANDLER_P(arg, cast_object)) {
464            SEPARATE_ZVAL_NOREF(arg);
465            if (zend_std_cast_object_tostring(arg, arg, IS_STRING) == SUCCESS) {
466                *dest = Z_STR_P(arg);
467                return 1;
468            }
469        }
470        if (!Z_OBJ_HANDLER_P(arg, cast_object) && Z_OBJ_HANDLER_P(arg, get)) {
471            zval rv;
472            zval *z = Z_OBJ_HANDLER_P(arg, get)(arg, &rv);
473
474            Z_ADDREF_P(z);
475            if (Z_TYPE_P(z) != IS_OBJECT) {
476                zval_dtor(arg);
477                ZVAL_NULL(arg);
478                if (!zend_make_printable_zval(z, arg)) {
479                    ZVAL_ZVAL(arg, z, 1, 1);
480                }
481                *dest = Z_STR_P(arg);
482                return 1;
483            }
484            zval_ptr_dtor(z);
485        }
486        return 0;
487    } else {
488        return 0;
489    }
490    return 1;
491}
492/* }}} */
493
494ZEND_API int ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest) /* {{{ */
495{
496    if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
497        return 0;
498    }
499    return zend_parse_arg_str_weak(arg, dest);
500}
501/* }}} */
502
503static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, const char **spec, char **error, int *severity) /* {{{ */
504{
505    const char *spec_walk = *spec;
506    char c = *spec_walk++;
507    int check_null = 0;
508    zval *real_arg = arg;
509
510    /* scan through modifiers */
511    ZVAL_DEREF(arg);
512    while (1) {
513        if (*spec_walk == '/') {
514            SEPARATE_ZVAL(arg);
515            real_arg = arg;
516        } else if (*spec_walk == '!') {
517            check_null = 1;
518        } else {
519            break;
520        }
521        spec_walk++;
522    }
523
524    switch (c) {
525        case 'l':
526        case 'L':
527            {
528                zend_long *p = va_arg(*va, zend_long *);
529                zend_bool *is_null = NULL;
530
531                if (check_null) {
532                    is_null = va_arg(*va, zend_bool *);
533                }
534
535                if (!zend_parse_arg_long(arg, p, is_null, check_null, c == 'L')) {
536                    return "integer";
537                }
538            }
539            break;
540
541        case 'd':
542            {
543                double *p = va_arg(*va, double *);
544                zend_bool *is_null = NULL;
545
546                if (check_null) {
547                    is_null = va_arg(*va, zend_bool *);
548                }
549
550                if (!zend_parse_arg_double(arg, p, is_null, check_null)) {
551                    return "float";
552                }
553            }
554            break;
555
556        case 's':
557            {
558                char **p = va_arg(*va, char **);
559                size_t *pl = va_arg(*va, size_t *);
560                if (!zend_parse_arg_string(arg, p, pl, check_null)) {
561                    return "string";
562                }
563            }
564            break;
565
566        case 'p':
567            {
568                char **p = va_arg(*va, char **);
569                size_t *pl = va_arg(*va, size_t *);
570                if (!zend_parse_arg_path(arg, p, pl, check_null)) {
571                    return "a valid path";
572                }
573            }
574            break;
575
576        case 'P':
577            {
578                zend_string **str = va_arg(*va, zend_string **);
579                if (!zend_parse_arg_path_str(arg, str, check_null)) {
580                    return "a valid path";
581                }
582            }
583            break;
584
585        case 'S':
586            {
587                zend_string **str = va_arg(*va, zend_string **);
588                if (!zend_parse_arg_str(arg, str, check_null)) {
589                    return "string";
590                }
591            }
592            break;
593
594        case 'b':
595            {
596                zend_bool *p = va_arg(*va, zend_bool *);
597                zend_bool *is_null = NULL;
598
599                if (check_null) {
600                    is_null = va_arg(*va, zend_bool *);
601                }
602
603                if (!zend_parse_arg_bool(arg, p, is_null, check_null)) {
604                    return "boolean";
605                }
606            }
607            break;
608
609        case 'r':
610            {
611                zval **p = va_arg(*va, zval **);
612
613                if (!zend_parse_arg_resource(arg, p, check_null)) {
614                    return "resource";
615                }
616            }
617            break;
618
619        case 'A':
620        case 'a':
621            {
622                zval **p = va_arg(*va, zval **);
623
624                if (!zend_parse_arg_array(arg, p, check_null, c == 'A')) {
625                    return "array";
626                }
627            }
628            break;
629
630        case 'H':
631        case 'h':
632            {
633                HashTable **p = va_arg(*va, HashTable **);
634
635                if (!zend_parse_arg_array_ht(arg, p, check_null, c == 'H')) {
636                    return "array";
637                }
638            }
639            break;
640
641        case 'o':
642            {
643                zval **p = va_arg(*va, zval **);
644
645                if (!zend_parse_arg_object(arg, p, NULL, check_null)) {
646                    return "object";
647                }
648            }
649            break;
650
651        case 'O':
652            {
653                zval **p = va_arg(*va, zval **);
654                zend_class_entry *ce = va_arg(*va, zend_class_entry *);
655
656                if (!zend_parse_arg_object(arg, p, ce, check_null)) {
657                    if (ce) {
658                        return ce->name->val;
659                    } else {
660                        return "object";
661                    }
662                }
663            }
664            break;
665
666        case 'C':
667            {
668                zend_class_entry *lookup, **pce = va_arg(*va, zend_class_entry **);
669                zend_class_entry *ce_base = *pce;
670
671                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
672                    *pce = NULL;
673                    break;
674                }
675                convert_to_string_ex(arg);
676                if ((lookup = zend_lookup_class(Z_STR_P(arg))) == NULL) {
677                    *pce = NULL;
678                } else {
679                    *pce = lookup;
680                }
681                if (ce_base) {
682                    if ((!*pce || !instanceof_function(*pce, ce_base))) {
683                        zend_spprintf(error, 0, "to be a class name derived from %s, '%s' given",
684                            ce_base->name->val, Z_STRVAL_P(arg));
685                        *pce = NULL;
686                        return "";
687                    }
688                }
689                if (!*pce) {
690                    zend_spprintf(error, 0, "to be a valid class name, '%s' given",
691                        Z_STRVAL_P(arg));
692                    return "";
693                }
694                break;
695
696            }
697            break;
698
699        case 'f':
700            {
701                zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
702                zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
703                char *is_callable_error = NULL;
704
705                if (check_null && Z_TYPE_P(arg) == IS_NULL) {
706                    fci->size = 0;
707                    fcc->initialized = 0;
708                    break;
709                }
710
711                if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error) == SUCCESS) {
712                    if (is_callable_error) {
713                        *severity = E_STRICT;
714                        zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
715                        efree(is_callable_error);
716                        *spec = spec_walk;
717                        return "";
718                    }
719                    break;
720                } else {
721                    if (is_callable_error) {
722                        *severity = E_EXCEPTION | E_ERROR;
723                        zend_spprintf(error, 0, "to be a valid callback, %s", is_callable_error);
724                        efree(is_callable_error);
725                        return "";
726                    } else {
727                        return "valid callback";
728                    }
729                }
730            }
731
732        case 'z':
733            {
734                zval **p = va_arg(*va, zval **);
735
736                zend_parse_arg_zval_deref(real_arg, p, check_null);
737            }
738            break;
739
740        case 'Z':
741            /* 'Z' iz not supported anymore and should be replaced with 'z' */
742            ZEND_ASSERT(c != 'Z');
743        default:
744            return "unknown";
745    }
746
747    *spec = spec_walk;
748
749    return NULL;
750}
751/* }}} */
752
753static int zend_parse_arg(int arg_num, zval *arg, va_list *va, const char **spec, int flags) /* {{{ */
754{
755    const char *expected_type = NULL;
756    char *error = NULL;
757    int severity = 0;
758
759    expected_type = zend_parse_arg_impl(arg_num, arg, va, spec, &error, &severity);
760    if (expected_type) {
761        if (!(flags & ZEND_PARSE_PARAMS_QUIET) && (*expected_type || error)) {
762            const char *space;
763            const char *class_name = get_active_class_name(&space);
764
765            if (error) {
766                zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d %s",
767                            class_name, space, get_active_function_name(), arg_num, error);
768                efree(error);
769            } else {
770                zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects parameter %d to be %s, %s given",
771                        class_name, space, get_active_function_name(), arg_num, expected_type,
772                        zend_zval_type_name(arg));
773            }
774        }
775        if (severity != E_STRICT) {
776            return FAILURE;
777        }
778    }
779
780    return SUCCESS;
781}
782/* }}} */
783
784ZEND_API int zend_parse_parameter(int flags, int arg_num, zval *arg, const char *spec, ...)
785{
786    va_list va;
787    int ret;
788
789    va_start(va, spec);
790    ret = zend_parse_arg(arg_num, arg, &va, &spec, flags);
791    va_end(va);
792
793    return ret;
794}
795
796static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags) /* {{{ */
797{
798    const  char *spec_walk;
799    int c, i;
800    int min_num_args = -1;
801    int max_num_args = 0;
802    int post_varargs = 0;
803    zval *arg;
804    int arg_count;
805    zend_bool have_varargs = 0;
806    zval **varargs = NULL;
807    int *n_varargs = NULL;
808
809    for (spec_walk = type_spec; *spec_walk; spec_walk++) {
810        c = *spec_walk;
811        switch (c) {
812            case 'l': case 'd':
813            case 's': case 'b':
814            case 'r': case 'a':
815            case 'o': case 'O':
816            case 'z': case 'Z':
817            case 'C': case 'h':
818            case 'f': case 'A':
819            case 'H': case 'p':
820            case 'S': case 'P':
821            case 'L':
822                max_num_args++;
823                break;
824
825            case '|':
826                min_num_args = max_num_args;
827                break;
828
829            case '/':
830            case '!':
831                /* Pass */
832                break;
833
834            case '*':
835            case '+':
836                if (have_varargs) {
837                    if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
838                        zend_function *active_function = EG(current_execute_data)->func;
839                        const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
840
841                        zend_error(E_WARNING, "%s%s%s(): only one varargs specifier (* or +) is permitted",
842                                class_name,
843                                class_name[0] ? "::" : "",
844                                active_function->common.function_name->val);
845                    }
846                    return FAILURE;
847                }
848                have_varargs = 1;
849                /* we expect at least one parameter in varargs */
850                if (c == '+') {
851                    max_num_args++;
852                }
853                /* mark the beginning of varargs */
854                post_varargs = max_num_args;
855                break;
856
857            default:
858                if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
859                    zend_function *active_function = EG(current_execute_data)->func;
860                    const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
861                    zend_error(E_WARNING, "%s%s%s(): bad type specifier while parsing parameters",
862                            class_name,
863                            class_name[0] ? "::" : "",
864                            active_function->common.function_name->val);
865                }
866                return FAILURE;
867        }
868    }
869
870    if (min_num_args < 0) {
871        min_num_args = max_num_args;
872    }
873
874    if (have_varargs) {
875        /* calculate how many required args are at the end of the specifier list */
876        post_varargs = max_num_args - post_varargs;
877        max_num_args = -1;
878    }
879
880    if (num_args < min_num_args || (num_args > max_num_args && max_num_args > 0)) {
881        if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
882            zend_function *active_function = EG(current_execute_data)->func;
883            const char *class_name = active_function->common.scope ? active_function->common.scope->name->val : "";
884            zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects %s %d parameter%s, %d given",
885                    class_name,
886                    class_name[0] ? "::" : "",
887                    active_function->common.function_name->val,
888                    min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
889                    num_args < min_num_args ? min_num_args : max_num_args,
890                    (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
891                    num_args);
892        }
893        return FAILURE;
894    }
895
896    arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
897
898    if (num_args > arg_count) {
899        zend_error(E_WARNING, "%s(): could not obtain parameters for parsing",
900            get_active_function_name());
901        return FAILURE;
902    }
903
904    i = 0;
905    while (num_args-- > 0) {
906        if (*type_spec == '|') {
907            type_spec++;
908        }
909
910        if (*type_spec == '*' || *type_spec == '+') {
911            int num_varargs = num_args + 1 - post_varargs;
912
913            /* eat up the passed in storage even if it won't be filled in with varargs */
914            varargs = va_arg(*va, zval **);
915            n_varargs = va_arg(*va, int *);
916            type_spec++;
917
918            if (num_varargs > 0) {
919                *n_varargs = num_varargs;
920                *varargs = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
921                /* adjust how many args we have left and restart loop */
922                num_args += 1 - num_varargs;
923                i += num_varargs;
924                continue;
925            } else {
926                *varargs = NULL;
927                *n_varargs = 0;
928            }
929        }
930
931        arg = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
932
933        if (zend_parse_arg(i+1, arg, va, &type_spec, flags) == FAILURE) {
934            /* clean up varargs array if it was used */
935            if (varargs && *varargs) {
936                *varargs = NULL;
937            }
938            return FAILURE;
939        }
940        i++;
941    }
942
943    return SUCCESS;
944}
945/* }}} */
946
947#define RETURN_IF_ZERO_ARGS(num_args, type_spec, flags) { \
948    int __num_args = (num_args); \
949    \
950    if (0 == (type_spec)[0] && 0 != __num_args && !(flags & ZEND_PARSE_PARAMS_QUIET)) { \
951        const char *__space; \
952        const char * __class_name = get_active_class_name(&__space); \
953        zend_internal_type_error(ZEND_ARG_USES_STRICT_TYPES(), "%s%s%s() expects exactly 0 parameters, %d given", \
954            __class_name, __space, \
955            get_active_function_name(), __num_args); \
956        return FAILURE; \
957    }\
958}
959
960ZEND_API int zend_parse_parameters_ex(int flags, int num_args, const char *type_spec, ...) /* {{{ */
961{
962    va_list va;
963    int retval;
964
965    RETURN_IF_ZERO_ARGS(num_args, type_spec, flags);
966
967    va_start(va, type_spec);
968    retval = zend_parse_va_args(num_args, type_spec, &va, flags);
969    va_end(va);
970
971    return retval;
972}
973/* }}} */
974
975ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /* {{{ */
976{
977    va_list va;
978    int retval;
979    int flags = 0;
980
981    RETURN_IF_ZERO_ARGS(num_args, type_spec, flags);
982
983    va_start(va, type_spec);
984    retval = zend_parse_va_args(num_args, type_spec, &va, flags);
985    va_end(va);
986
987    return retval;
988}
989/* }}} */
990
991ZEND_API int zend_parse_method_parameters(int num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */
992{
993    va_list va;
994    int retval;
995    int flags = 0;
996    const char *p = type_spec;
997    zval **object;
998    zend_class_entry *ce;
999
1000    /* Just checking this_ptr is not enough, because fcall_common_helper does not set
1001     * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL.
1002     * In that case EG(This) would still be the $this from the calling code and we'd take the
1003     * wrong branch here. */
1004    zend_bool is_method = EG(current_execute_data)->func->common.scope != NULL;
1005
1006    if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) {
1007        RETURN_IF_ZERO_ARGS(num_args, p, flags);
1008
1009        va_start(va, type_spec);
1010        retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1011        va_end(va);
1012    } else {
1013        p++;
1014        RETURN_IF_ZERO_ARGS(num_args, p, flags);
1015
1016        va_start(va, type_spec);
1017
1018        object = va_arg(va, zval **);
1019        ce = va_arg(va, zend_class_entry *);
1020        *object = this_ptr;
1021
1022        if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) {
1023            zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
1024                Z_OBJCE_P(this_ptr)->name->val, get_active_function_name(), ce->name->val, get_active_function_name());
1025        }
1026
1027        retval = zend_parse_va_args(num_args, p, &va, flags);
1028        va_end(va);
1029    }
1030    return retval;
1031}
1032/* }}} */
1033
1034ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */
1035{
1036    va_list va;
1037    int retval;
1038    const char *p = type_spec;
1039    zval **object;
1040    zend_class_entry *ce;
1041
1042    if (!this_ptr) {
1043        RETURN_IF_ZERO_ARGS(num_args, p, flags);
1044
1045        va_start(va, type_spec);
1046        retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1047        va_end(va);
1048    } else {
1049        p++;
1050        RETURN_IF_ZERO_ARGS(num_args, p, flags);
1051
1052        va_start(va, type_spec);
1053
1054        object = va_arg(va, zval **);
1055        ce = va_arg(va, zend_class_entry *);
1056        *object = this_ptr;
1057
1058        if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) {
1059            if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
1060                zend_error(E_CORE_ERROR, "%s::%s() must be derived from %s::%s",
1061                    ce->name->val, get_active_function_name(), Z_OBJCE_P(this_ptr)->name->val, get_active_function_name());
1062            }
1063            va_end(va);
1064            return FAILURE;
1065        }
1066
1067        retval = zend_parse_va_args(num_args, p, &va, flags);
1068        va_end(va);
1069    }
1070    return retval;
1071}
1072/* }}} */
1073
1074/* Argument parsing API -- andrei */
1075ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */
1076{
1077    ZVAL_NEW_ARR(arg);
1078    _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC);
1079    return SUCCESS;
1080}
1081/* }}} */
1082
1083/* This function should be called after the constructor has been called
1084 * because it may call __set from the uninitialized object otherwise. */
1085ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
1086{
1087    const zend_object_handlers *obj_ht = Z_OBJ_HT_P(obj);
1088    zend_class_entry *old_scope = EG(scope);
1089    zend_string *key;
1090    zval *value;
1091
1092    EG(scope) = Z_OBJCE_P(obj);
1093    ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, value) {
1094        if (key) {
1095            zval member;
1096
1097            ZVAL_STR(&member, key);
1098            obj_ht->write_property(obj, &member, value, NULL);
1099        }
1100    } ZEND_HASH_FOREACH_END();
1101    EG(scope) = old_scope;
1102}
1103/* }}} */
1104
1105static int zval_update_class_constant(zval *pp, int is_static, uint32_t offset) /* {{{ */
1106{
1107    ZVAL_DEREF(pp);
1108    if (Z_CONSTANT_P(pp)) {
1109        zend_class_entry **scope = EG(current_execute_data) ? &EG(scope) : &CG(active_class_entry);
1110
1111        if ((*scope)->parent) {
1112            zend_class_entry *ce = *scope;
1113            zend_property_info *prop_info;
1114
1115            do {
1116                ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
1117                    if (is_static == ((prop_info->flags & ZEND_ACC_STATIC) != 0) &&
1118                        offset == prop_info->offset) {
1119                        int ret;
1120                        zend_class_entry *old_scope = *scope;
1121                        *scope = prop_info->ce;
1122                        ret = zval_update_constant(pp, 1);
1123                        *scope = old_scope;
1124                        return ret;
1125                    }
1126                } ZEND_HASH_FOREACH_END();
1127                ce = ce->parent;
1128            } while (ce);
1129
1130        }
1131        return zval_update_constant(pp, 1);
1132    }
1133    return 0;
1134}
1135/* }}} */
1136
1137ZEND_API void zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
1138{
1139    int i;
1140
1141    /* initialize static members of internal class */
1142    if (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count) {
1143        zval *p;
1144
1145        if (class_type->parent) {
1146            zend_update_class_constants(class_type->parent);
1147        }
1148#if ZTS
1149        CG(static_members_table)[(zend_intptr_t)(class_type->static_members_table)] = emalloc(sizeof(zval) * class_type->default_static_members_count);
1150#else
1151        class_type->static_members_table = emalloc(sizeof(zval) * class_type->default_static_members_count);
1152#endif
1153        for (i = 0; i < class_type->default_static_members_count; i++) {
1154            p = &class_type->default_static_members_table[i];
1155            if (Z_ISREF_P(p) &&
1156                class_type->parent &&
1157                i < class_type->parent->default_static_members_count &&
1158                p == &class_type->parent->default_static_members_table[i] &&
1159                Z_TYPE(CE_STATIC_MEMBERS(class_type->parent)[i]) != IS_UNDEF
1160            ) {
1161                zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i];
1162
1163                ZVAL_NEW_REF(q, q);
1164                ZVAL_COPY_VALUE(&CE_STATIC_MEMBERS(class_type)[i], q);
1165                Z_ADDREF_P(q);
1166            } else {
1167                ZVAL_DUP(&CE_STATIC_MEMBERS(class_type)[i], p);
1168            }
1169        }
1170    }
1171
1172    if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0) {
1173        zend_class_entry **scope = EG(current_execute_data) ? &EG(scope) : &CG(active_class_entry);
1174        zend_class_entry *old_scope = *scope;
1175        zval *val;
1176
1177        *scope = class_type;
1178
1179        ZEND_HASH_FOREACH_VAL(&class_type->constants_table, val) {
1180            zval_update_constant(val, 1);
1181        } ZEND_HASH_FOREACH_END();
1182
1183        for (i = 0; i < class_type->default_properties_count; i++) {
1184            if (Z_TYPE(class_type->default_properties_table[i]) != IS_UNDEF) {
1185                zval_update_class_constant(&class_type->default_properties_table[i], 0, OBJ_PROP_TO_OFFSET(i));
1186            }
1187        }
1188
1189        for (i = 0; i < class_type->default_static_members_count; i++) {
1190            zval_update_class_constant(&CE_STATIC_MEMBERS(class_type)[i], 1, i);
1191        }
1192
1193        *scope = old_scope;
1194        class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
1195    }
1196}
1197/* }}} */
1198
1199ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
1200{
1201    int i;
1202
1203    if (class_type->default_properties_count) {
1204        for (i = 0; i < class_type->default_properties_count; i++) {
1205#if ZTS
1206            ZVAL_DUP(&object->properties_table[i], &class_type->default_properties_table[i]);
1207#else
1208            ZVAL_COPY(&object->properties_table[i], &class_type->default_properties_table[i]);
1209#endif
1210        }
1211        object->properties = NULL;
1212    }
1213}
1214/* }}} */
1215
1216ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties) /* {{{ */
1217{
1218    object->properties = properties;
1219    if (object->ce->default_properties_count) {
1220        zval *prop;
1221        zend_string *key;
1222        zend_property_info *property_info;
1223
1224        ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
1225            property_info = zend_get_property_info(object->ce, key, 1);
1226            if (property_info != ZEND_WRONG_PROPERTY_INFO &&
1227                property_info &&
1228                (property_info->flags & ZEND_ACC_STATIC) == 0) {
1229                zval *slot = OBJ_PROP(object, property_info->offset);
1230                ZVAL_COPY_VALUE(slot, prop);
1231                ZVAL_INDIRECT(prop, slot);
1232            }
1233        } ZEND_HASH_FOREACH_END();
1234    }
1235}
1236/* }}} */
1237
1238ZEND_API void object_properties_load(zend_object *object, HashTable *properties) /* {{{ */
1239{
1240    zval *prop, tmp;
1241    zend_string *key;
1242    zend_property_info *property_info;
1243
1244    ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
1245        property_info = zend_get_property_info(object->ce, key, 1);
1246        if (property_info != ZEND_WRONG_PROPERTY_INFO &&
1247            property_info &&
1248            (property_info->flags & ZEND_ACC_STATIC) == 0) {
1249            zval *slot = OBJ_PROP(object, property_info->offset);
1250            zval_ptr_dtor(slot);
1251            ZVAL_COPY_VALUE(slot, prop);
1252            zval_add_ref(slot);
1253            if (object->properties) {
1254                ZVAL_INDIRECT(&tmp, slot);
1255                zend_hash_update(object->properties, key, &tmp);
1256            }
1257        } else {
1258            if (!object->properties) {
1259                rebuild_object_properties(object);
1260            }
1261            prop = zend_hash_update(object->properties, key, prop);
1262            zval_add_ref(prop);
1263        }
1264    } ZEND_HASH_FOREACH_END();
1265}
1266/* }}} */
1267
1268/* This function requires 'properties' to contain all props declared in the
1269 * class and all props being public. If only a subset is given or the class
1270 * has protected members then you need to merge the properties separately by
1271 * calling zend_merge_properties(). */
1272ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC) /* {{{ */
1273{
1274    if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1275        if (class_type->ce_flags & ZEND_ACC_INTERFACE) {
1276            zend_error_noreturn(E_ERROR, "Cannot instantiate interface %s", class_type->name->val);
1277        } else if (class_type->ce_flags & ZEND_ACC_TRAIT) {
1278            zend_error_noreturn(E_ERROR, "Cannot instantiate trait %s", class_type->name->val);
1279        } else {
1280            zend_error_noreturn(E_ERROR, "Cannot instantiate abstract class %s", class_type->name->val);
1281        }
1282    }
1283
1284    zend_update_class_constants(class_type);
1285
1286    if (class_type->create_object == NULL) {
1287        ZVAL_OBJ(arg, zend_objects_new(class_type));
1288        if (properties) {
1289            object_properties_init_ex(Z_OBJ_P(arg), properties);
1290        } else {
1291            object_properties_init(Z_OBJ_P(arg), class_type);
1292        }
1293    } else {
1294        ZVAL_OBJ(arg, class_type->create_object(class_type));
1295    }
1296    return SUCCESS;
1297}
1298/* }}} */
1299
1300ZEND_API int _object_init_ex(zval *arg, zend_class_entry *class_type ZEND_FILE_LINE_DC) /* {{{ */
1301{
1302    return _object_and_properties_init(arg, class_type, 0 ZEND_FILE_LINE_RELAY_CC);
1303}
1304/* }}} */
1305
1306ZEND_API int _object_init(zval *arg ZEND_FILE_LINE_DC) /* {{{ */
1307{
1308    return _object_init_ex(arg, zend_standard_class_def ZEND_FILE_LINE_RELAY_CC);
1309}
1310/* }}} */
1311
1312ZEND_API int add_assoc_function(zval *arg, const char *key, void (*function_ptr)(INTERNAL_FUNCTION_PARAMETERS)) /* {{{ */
1313{
1314    zend_error(E_WARNING, "add_assoc_function() is no longer supported");
1315    return FAILURE;
1316}
1317/* }}} */
1318
1319ZEND_API int add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */
1320{
1321    zval *ret, tmp;
1322
1323    ZVAL_LONG(&tmp, n);
1324    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1325    return ret ? SUCCESS : FAILURE;
1326}
1327/* }}} */
1328
1329ZEND_API int add_assoc_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */
1330{
1331    zval *ret, tmp;
1332
1333    ZVAL_NULL(&tmp);
1334    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1335    return ret ? SUCCESS : FAILURE;
1336}
1337/* }}} */
1338
1339ZEND_API int add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, int b) /* {{{ */
1340{
1341    zval *ret, tmp;
1342
1343    ZVAL_BOOL(&tmp, b);
1344    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1345    return ret ? SUCCESS : FAILURE;
1346}
1347/* }}} */
1348
1349ZEND_API int add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */
1350{
1351    zval *ret, tmp;
1352
1353    ZVAL_RES(&tmp, r);
1354    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1355    return ret ? SUCCESS : FAILURE;
1356}
1357/* }}} */
1358
1359ZEND_API int add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */
1360{
1361    zval *ret, tmp;
1362
1363    ZVAL_DOUBLE(&tmp, d);
1364    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1365    return ret ? SUCCESS : FAILURE;
1366}
1367/* }}} */
1368
1369ZEND_API int add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */
1370{
1371    zval *ret, tmp;
1372
1373    ZVAL_STR(&tmp, str);
1374    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1375    return ret ? SUCCESS : FAILURE;
1376}
1377/* }}} */
1378
1379ZEND_API int add_assoc_string_ex(zval *arg, const char *key, size_t key_len, char *str) /* {{{ */
1380{
1381    zval *ret, tmp;
1382
1383    ZVAL_STRING(&tmp, str);
1384    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1385    return ret ? SUCCESS : FAILURE;
1386}
1387/* }}} */
1388
1389ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, char *str, size_t length) /* {{{ */
1390{
1391    zval *ret, tmp;
1392
1393    ZVAL_STRINGL(&tmp, str, length);
1394    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1395    return ret ? SUCCESS : FAILURE;
1396}
1397/* }}} */
1398
1399ZEND_API int add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */
1400{
1401    zval *ret;
1402
1403    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, value);
1404    return ret ? SUCCESS : FAILURE;
1405}
1406/* }}} */
1407
1408ZEND_API int add_index_long(zval *arg, zend_ulong index, zend_long n) /* {{{ */
1409{
1410    zval tmp;
1411
1412    ZVAL_LONG(&tmp, n);
1413    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1414}
1415/* }}} */
1416
1417ZEND_API int add_index_null(zval *arg, zend_ulong index) /* {{{ */
1418{
1419    zval tmp;
1420
1421    ZVAL_NULL(&tmp);
1422    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1423}
1424/* }}} */
1425
1426ZEND_API int add_index_bool(zval *arg, zend_ulong index, int b) /* {{{ */
1427{
1428    zval tmp;
1429
1430    ZVAL_BOOL(&tmp, b);
1431    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1432}
1433/* }}} */
1434
1435ZEND_API int add_index_resource(zval *arg, zend_ulong index, zend_resource *r) /* {{{ */
1436{
1437    zval tmp;
1438
1439    ZVAL_RES(&tmp, r);
1440    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1441}
1442/* }}} */
1443
1444ZEND_API int add_index_double(zval *arg, zend_ulong index, double d) /* {{{ */
1445{
1446    zval tmp;
1447
1448    ZVAL_DOUBLE(&tmp, d);
1449    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1450}
1451/* }}} */
1452
1453ZEND_API int add_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */
1454{
1455    zval tmp;
1456
1457    ZVAL_STR(&tmp, str);
1458    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1459}
1460/* }}} */
1461
1462ZEND_API int add_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */
1463{
1464    zval tmp;
1465
1466    ZVAL_STRING(&tmp, str);
1467    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1468}
1469/* }}} */
1470
1471ZEND_API int add_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */
1472{
1473    zval tmp;
1474
1475    ZVAL_STRINGL(&tmp, str, length);
1476    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp) ? SUCCESS : FAILURE;
1477}
1478/* }}} */
1479
1480ZEND_API int add_index_zval(zval *arg, zend_ulong index, zval *value) /* {{{ */
1481{
1482    return zend_hash_index_update(Z_ARRVAL_P(arg), index, value) ? SUCCESS : FAILURE;
1483}
1484/* }}} */
1485
1486ZEND_API int add_next_index_long(zval *arg, zend_long n) /* {{{ */
1487{
1488    zval tmp;
1489
1490    ZVAL_LONG(&tmp, n);
1491    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1492}
1493/* }}} */
1494
1495ZEND_API int add_next_index_null(zval *arg) /* {{{ */
1496{
1497    zval tmp;
1498
1499    ZVAL_NULL(&tmp);
1500    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1501}
1502/* }}} */
1503
1504ZEND_API int add_next_index_bool(zval *arg, int b) /* {{{ */
1505{
1506    zval tmp;
1507
1508    ZVAL_BOOL(&tmp, b);
1509    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1510}
1511/* }}} */
1512
1513ZEND_API int add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */
1514{
1515    zval tmp;
1516
1517    ZVAL_RES(&tmp, r);
1518    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1519}
1520/* }}} */
1521
1522ZEND_API int add_next_index_double(zval *arg, double d) /* {{{ */
1523{
1524    zval tmp;
1525
1526    ZVAL_DOUBLE(&tmp, d);
1527    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1528}
1529/* }}} */
1530
1531ZEND_API int add_next_index_str(zval *arg, zend_string *str) /* {{{ */
1532{
1533    zval tmp;
1534
1535    ZVAL_STR(&tmp, str);
1536    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1537}
1538/* }}} */
1539
1540ZEND_API int add_next_index_string(zval *arg, const char *str) /* {{{ */
1541{
1542    zval tmp;
1543
1544    ZVAL_STRING(&tmp, str);
1545    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1546}
1547/* }}} */
1548
1549ZEND_API int add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */
1550{
1551    zval tmp;
1552
1553    ZVAL_STRINGL(&tmp, str, length);
1554    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
1555}
1556/* }}} */
1557
1558ZEND_API int add_next_index_zval(zval *arg, zval *value) /* {{{ */
1559{
1560    return zend_hash_next_index_insert(Z_ARRVAL_P(arg), value) ? SUCCESS : FAILURE;
1561}
1562/* }}} */
1563
1564ZEND_API zval *add_get_assoc_string_ex(zval *arg, const char *key, uint key_len, const char *str) /* {{{ */
1565{
1566    zval tmp, *ret;
1567
1568    ZVAL_STRING(&tmp, str);
1569    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1570    return ret;
1571}
1572/* }}} */
1573
1574ZEND_API zval *add_get_assoc_stringl_ex(zval *arg, const char *key, uint key_len, const char *str, size_t length) /* {{{ */
1575{
1576    zval tmp, *ret;
1577
1578    ZVAL_STRINGL(&tmp, str, length);
1579    ret = zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1580    return ret;
1581}
1582/* }}} */
1583
1584ZEND_API zval *add_get_index_long(zval *arg, zend_ulong index, zend_long l) /* {{{ */
1585{
1586    zval tmp;
1587
1588    ZVAL_LONG(&tmp, l);
1589    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1590}
1591/* }}} */
1592
1593ZEND_API zval *add_get_index_double(zval *arg, zend_ulong index, double d) /* {{{ */
1594{
1595    zval tmp;
1596
1597    ZVAL_DOUBLE(&tmp, d);
1598    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1599}
1600/* }}} */
1601
1602ZEND_API zval *add_get_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */
1603{
1604    zval tmp;
1605
1606    ZVAL_STR(&tmp, str);
1607    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1608}
1609/* }}} */
1610
1611ZEND_API zval *add_get_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */
1612{
1613    zval tmp;
1614
1615    ZVAL_STRING(&tmp, str);
1616    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1617}
1618/* }}} */
1619
1620ZEND_API zval *add_get_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */
1621{
1622    zval tmp;
1623
1624    ZVAL_STRINGL(&tmp, str, length);
1625    return zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1626}
1627/* }}} */
1628
1629ZEND_API int array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */
1630{
1631    zval *result;
1632
1633    switch (Z_TYPE_P(key)) {
1634        case IS_STRING:
1635            result = zend_symtable_update(ht, Z_STR_P(key), value);
1636            break;
1637        case IS_NULL:
1638            result = zend_symtable_update(ht, STR_EMPTY_ALLOC(), value);
1639            break;
1640        case IS_RESOURCE:
1641            zend_error(E_STRICT, "Resource ID#" ZEND_LONG_FMT " used as offset, casting to integer (%pd)", Z_RES_HANDLE_P(key), Z_RES_HANDLE_P(key));
1642            result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value);
1643            break;
1644        case IS_FALSE:
1645            result = zend_hash_index_update(ht, 0, value);
1646            break;
1647        case IS_TRUE:
1648            result = zend_hash_index_update(ht, 1, value);
1649            break;
1650        case IS_LONG:
1651            result = zend_hash_index_update(ht, Z_LVAL_P(key), value);
1652            break;
1653        case IS_DOUBLE:
1654            result = zend_hash_index_update(ht, zend_dval_to_lval(Z_DVAL_P(key)), value);
1655            break;
1656        default:
1657            zend_error(E_WARNING, "Illegal offset type");
1658            result = NULL;
1659    }
1660
1661    if (result) {
1662        if (Z_REFCOUNTED_P(result)) {
1663            Z_ADDREF_P(result);
1664        }
1665        return SUCCESS;
1666    } else {
1667        return FAILURE;
1668    }
1669}
1670/* }}} */
1671
1672ZEND_API int add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */
1673{
1674    zval tmp;
1675    zval z_key;
1676
1677    ZVAL_LONG(&tmp, n);
1678    ZVAL_STRINGL(&z_key, key, key_len);
1679    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1680    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1681    zval_ptr_dtor(&z_key);
1682    return SUCCESS;
1683}
1684/* }}} */
1685
1686ZEND_API int add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b) /* {{{ */
1687{
1688    zval tmp;
1689    zval z_key;
1690
1691    ZVAL_BOOL(&tmp, b);
1692    ZVAL_STRINGL(&z_key, key, key_len);
1693    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1694    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1695    zval_ptr_dtor(&z_key);
1696    return SUCCESS;
1697}
1698/* }}} */
1699
1700ZEND_API int add_property_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */
1701{
1702    zval tmp;
1703    zval z_key;
1704
1705    ZVAL_NULL(&tmp);
1706    ZVAL_STRINGL(&z_key, key, key_len);
1707    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1708    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1709    zval_ptr_dtor(&z_key);
1710    return SUCCESS;
1711}
1712/* }}} */
1713
1714ZEND_API int add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */
1715{
1716    zval tmp;
1717    zval z_key;
1718
1719    ZVAL_RES(&tmp, r);
1720    ZVAL_STRINGL(&z_key, key, key_len);
1721    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1722    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1723    zval_ptr_dtor(&z_key);
1724    return SUCCESS;
1725}
1726/* }}} */
1727
1728ZEND_API int add_property_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */
1729{
1730    zval tmp;
1731    zval z_key;
1732
1733    ZVAL_DOUBLE(&tmp, d);
1734    ZVAL_STRINGL(&z_key, key, key_len);
1735    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1736    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1737    zval_ptr_dtor(&z_key);
1738    return SUCCESS;
1739}
1740/* }}} */
1741
1742ZEND_API int add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */
1743{
1744    zval tmp;
1745    zval z_key;
1746
1747    ZVAL_STR(&tmp, str);
1748    ZVAL_STRINGL(&z_key, key, key_len);
1749    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1750    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1751    zval_ptr_dtor(&z_key);
1752    return SUCCESS;
1753}
1754/* }}} */
1755
1756ZEND_API int add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */
1757{
1758    zval tmp;
1759    zval z_key;
1760
1761    ZVAL_STRING(&tmp, str);
1762    ZVAL_STRINGL(&z_key, key, key_len);
1763    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1764    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1765    zval_ptr_dtor(&z_key);
1766    return SUCCESS;
1767}
1768/* }}} */
1769
1770ZEND_API int add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */
1771{
1772    zval tmp;
1773    zval z_key;
1774
1775    ZVAL_STRINGL(&tmp, str, length);
1776    ZVAL_STRINGL(&z_key, key, key_len);
1777    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, &tmp, NULL);
1778    zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
1779    zval_ptr_dtor(&z_key);
1780    return SUCCESS;
1781}
1782/* }}} */
1783
1784ZEND_API int add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */
1785{
1786    zval z_key;
1787
1788    ZVAL_STRINGL(&z_key, key, key_len);
1789    Z_OBJ_HANDLER_P(arg, write_property)(arg, &z_key, value, NULL);
1790    zval_ptr_dtor(&z_key);
1791    return SUCCESS;
1792}
1793/* }}} */
1794
1795ZEND_API int zend_startup_module_ex(zend_module_entry *module) /* {{{ */
1796{
1797    size_t name_len;
1798    zend_string *lcname;
1799
1800    if (module->module_started) {
1801        return SUCCESS;
1802    }
1803    module->module_started = 1;
1804
1805    /* Check module dependencies */
1806    if (module->deps) {
1807        const zend_module_dep *dep = module->deps;
1808
1809        while (dep->name) {
1810            if (dep->type == MODULE_DEP_REQUIRED) {
1811                zend_module_entry *req_mod;
1812
1813                name_len = strlen(dep->name);
1814                lcname = zend_string_alloc(name_len, 0);
1815                zend_str_tolower_copy(lcname->val, dep->name, name_len);
1816
1817                if ((req_mod = zend_hash_find_ptr(&module_registry, lcname)) == NULL || !req_mod->module_started) {
1818                    zend_string_free(lcname);
1819                    /* TODO: Check version relationship */
1820                    zend_error(E_CORE_WARNING, "Cannot load module '%s' because required module '%s' is not loaded", module->name, dep->name);
1821                    module->module_started = 0;
1822                    return FAILURE;
1823                }
1824                zend_string_free(lcname);
1825            }
1826            ++dep;
1827        }
1828    }
1829
1830    /* Initialize module globals */
1831    if (module->globals_size) {
1832#ifdef ZTS
1833        ts_allocate_id(module->globals_id_ptr, module->globals_size, (ts_allocate_ctor) module->globals_ctor, (ts_allocate_dtor) module->globals_dtor);
1834#else
1835        if (module->globals_ctor) {
1836            module->globals_ctor(module->globals_ptr);
1837        }
1838#endif
1839    }
1840    if (module->module_startup_func) {
1841        EG(current_module) = module;
1842        if (module->module_startup_func(module->type, module->module_number)==FAILURE) {
1843            zend_error(E_CORE_ERROR,"Unable to start %s module", module->name);
1844            EG(current_module) = NULL;
1845            return FAILURE;
1846        }
1847        EG(current_module) = NULL;
1848    }
1849    return SUCCESS;
1850}
1851/* }}} */
1852
1853static int zend_startup_module_zval(zval *zv) /* {{{ */
1854{
1855    zend_module_entry *module = Z_PTR_P(zv);
1856
1857    return zend_startup_module_ex(module);
1858}
1859/* }}} */
1860
1861static void zend_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp) /* {{{ */
1862{
1863    Bucket *b1 = base;
1864    Bucket *b2;
1865    Bucket *end = b1 + count;
1866    Bucket tmp;
1867    zend_module_entry *m, *r;
1868
1869    while (b1 < end) {
1870try_again:
1871        m = (zend_module_entry*)Z_PTR(b1->val);
1872        if (!m->module_started && m->deps) {
1873            const zend_module_dep *dep = m->deps;
1874            while (dep->name) {
1875                if (dep->type == MODULE_DEP_REQUIRED || dep->type == MODULE_DEP_OPTIONAL) {
1876                    b2 = b1 + 1;
1877                    while (b2 < end) {
1878                        r = (zend_module_entry*)Z_PTR(b2->val);
1879                        if (strcasecmp(dep->name, r->name) == 0) {
1880                            tmp = *b1;
1881                            *b1 = *b2;
1882                            *b2 = tmp;
1883                            goto try_again;
1884                        }
1885                        b2++;
1886                    }
1887                }
1888                dep++;
1889            }
1890        }
1891        b1++;
1892    }
1893}
1894/* }}} */
1895
1896ZEND_API void zend_collect_module_handlers(void) /* {{{ */
1897{
1898    zend_module_entry *module;
1899    int startup_count = 0;
1900    int shutdown_count = 0;
1901    int post_deactivate_count = 0;
1902    zend_class_entry *ce;
1903    int class_count = 0;
1904
1905    /* Collect extensions with request startup/shutdown handlers */
1906    ZEND_HASH_FOREACH_PTR(&module_registry, module) {
1907        if (module->request_startup_func) {
1908            startup_count++;
1909        }
1910        if (module->request_shutdown_func) {
1911            shutdown_count++;
1912        }
1913        if (module->post_deactivate_func) {
1914            post_deactivate_count++;
1915        }
1916    } ZEND_HASH_FOREACH_END();
1917    module_request_startup_handlers = (zend_module_entry**)malloc(
1918        sizeof(zend_module_entry*) *
1919        (startup_count + 1 +
1920         shutdown_count + 1 +
1921         post_deactivate_count + 1));
1922    module_request_startup_handlers[startup_count] = NULL;
1923    module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1;
1924    module_request_shutdown_handlers[shutdown_count] = NULL;
1925    module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
1926    module_post_deactivate_handlers[post_deactivate_count] = NULL;
1927    startup_count = 0;
1928
1929    ZEND_HASH_FOREACH_PTR(&module_registry, module) {
1930        if (module->request_startup_func) {
1931            module_request_startup_handlers[startup_count++] = module;
1932        }
1933        if (module->request_shutdown_func) {
1934            module_request_shutdown_handlers[--shutdown_count] = module;
1935        }
1936        if (module->post_deactivate_func) {
1937            module_post_deactivate_handlers[--post_deactivate_count] = module;
1938        }
1939    } ZEND_HASH_FOREACH_END();
1940
1941    /* Collect internal classes with static members */
1942    ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
1943        if (ce->type == ZEND_INTERNAL_CLASS &&
1944            ce->default_static_members_count > 0) {
1945            class_count++;
1946        }
1947    } ZEND_HASH_FOREACH_END();
1948
1949    class_cleanup_handlers = (zend_class_entry**)malloc(
1950        sizeof(zend_class_entry*) *
1951        (class_count + 1));
1952    class_cleanup_handlers[class_count] = NULL;
1953
1954    if (class_count) {
1955        ZEND_HASH_FOREACH_PTR(CG(class_table), ce) {
1956            if (ce->type == ZEND_INTERNAL_CLASS &&
1957                ce->default_static_members_count > 0) {
1958                class_cleanup_handlers[--class_count] = ce;
1959            }
1960        } ZEND_HASH_FOREACH_END();
1961    }
1962}
1963/* }}} */
1964
1965ZEND_API int zend_startup_modules(void) /* {{{ */
1966{
1967    zend_hash_sort_ex(&module_registry, zend_sort_modules, NULL, 0);
1968    zend_hash_apply(&module_registry, zend_startup_module_zval);
1969    return SUCCESS;
1970}
1971/* }}} */
1972
1973ZEND_API void zend_destroy_modules(void) /* {{{ */
1974{
1975    free(class_cleanup_handlers);
1976    free(module_request_startup_handlers);
1977    zend_hash_graceful_reverse_destroy(&module_registry);
1978}
1979/* }}} */
1980
1981ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) /* {{{ */
1982{
1983    size_t name_len;
1984    zend_string *lcname;
1985    zend_module_entry *module_ptr;
1986
1987    if (!module) {
1988        return NULL;
1989    }
1990
1991#if 0
1992    zend_printf("%s: Registering module %d\n", module->name, module->module_number);
1993#endif
1994
1995    /* Check module dependencies */
1996    if (module->deps) {
1997        const zend_module_dep *dep = module->deps;
1998
1999        while (dep->name) {
2000            if (dep->type == MODULE_DEP_CONFLICTS) {
2001                name_len = strlen(dep->name);
2002                lcname = zend_string_alloc(name_len, 0);
2003                zend_str_tolower_copy(lcname->val, dep->name, name_len);
2004
2005                if (zend_hash_exists(&module_registry, lcname)) {
2006                    zend_string_free(lcname);
2007                    /* TODO: Check version relationship */
2008                    zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name);
2009                    return NULL;
2010                }
2011                zend_string_free(lcname);
2012            }
2013            ++dep;
2014        }
2015    }
2016
2017    name_len = strlen(module->name);
2018    lcname = zend_string_alloc(name_len, 1);
2019    zend_str_tolower_copy(lcname->val, module->name, name_len);
2020
2021    if ((module_ptr = zend_hash_add_mem(&module_registry, lcname, module, sizeof(zend_module_entry))) == NULL) {
2022        zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name);
2023        zend_string_release(lcname);
2024        return NULL;
2025    }
2026    zend_string_release(lcname);
2027    module = module_ptr;
2028    EG(current_module) = module;
2029
2030    if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type)==FAILURE) {
2031        EG(current_module) = NULL;
2032        zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
2033        return NULL;
2034    }
2035
2036    EG(current_module) = NULL;
2037    return module;
2038}
2039/* }}} */
2040
2041ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *module) /* {{{ */
2042{
2043    module->module_number = zend_next_free_module();
2044    module->type = MODULE_PERSISTENT;
2045    return zend_register_module_ex(module);
2046}
2047/* }}} */
2048
2049ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type) /* {{{ */
2050{
2051    char lcname[16];
2052    size_t name_len;
2053
2054    /* we don't care if the function name is longer, in fact lowercasing only
2055     * the beginning of the name speeds up the check process */
2056    name_len = fptr->common.function_name->len;
2057    zend_str_tolower_copy(lcname, fptr->common.function_name->val, MIN(name_len, sizeof(lcname)-1));
2058    lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
2059
2060    if (name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1) && fptr->common.num_args != 0) {
2061        zend_error(error_type, "Destructor %s::%s() cannot take arguments", ce->name->val, ZEND_DESTRUCTOR_FUNC_NAME);
2062    } else if (name_len == sizeof(ZEND_CLONE_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME) - 1) && fptr->common.num_args != 0) {
2063        zend_error(error_type, "Method %s::%s() cannot accept any arguments", ce->name->val, ZEND_CLONE_FUNC_NAME);
2064    } else if (name_len == sizeof(ZEND_GET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME) - 1)) {
2065        if (fptr->common.num_args != 1) {
2066            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_GET_FUNC_NAME);
2067        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2068            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_GET_FUNC_NAME);
2069        }
2070    } else if (name_len == sizeof(ZEND_SET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME) - 1)) {
2071        if (fptr->common.num_args != 2) {
2072            zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name->val, ZEND_SET_FUNC_NAME);
2073        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2074            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_SET_FUNC_NAME);
2075        }
2076    } else if (name_len == sizeof(ZEND_UNSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME) - 1)) {
2077        if (fptr->common.num_args != 1) {
2078            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_UNSET_FUNC_NAME);
2079        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2080            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_UNSET_FUNC_NAME);
2081        }
2082    } else if (name_len == sizeof(ZEND_ISSET_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) {
2083        if (fptr->common.num_args != 1) {
2084            zend_error(error_type, "Method %s::%s() must take exactly 1 argument", ce->name->val, ZEND_ISSET_FUNC_NAME);
2085        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1)) {
2086            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_ISSET_FUNC_NAME);
2087        }
2088    } else if (name_len == sizeof(ZEND_CALL_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) {
2089        if (fptr->common.num_args != 2) {
2090            zend_error(error_type, "Method %s::%s() must take exactly 2 arguments", ce->name->val, ZEND_CALL_FUNC_NAME);
2091        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2092            zend_error(error_type, "Method %s::%s() cannot take arguments by reference", ce->name->val, ZEND_CALL_FUNC_NAME);
2093        }
2094    } else if (name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1 &&
2095        !memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1)
2096    ) {
2097        if (fptr->common.num_args != 2) {
2098            zend_error(error_type, "Method %s::__callStatic() must take exactly 2 arguments", ce->name->val);
2099        } else if (ARG_SHOULD_BE_SENT_BY_REF(fptr, 1) || ARG_SHOULD_BE_SENT_BY_REF(fptr, 2)) {
2100            zend_error(error_type, "Method %s::__callStatic() cannot take arguments by reference", ce->name->val);
2101        }
2102    } else if (name_len == sizeof(ZEND_TOSTRING_FUNC_NAME) - 1 &&
2103        !memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && fptr->common.num_args != 0
2104    ) {
2105        zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name->val, ZEND_TOSTRING_FUNC_NAME);
2106    } else if (name_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1 &&
2107        !memcmp(lcname, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && fptr->common.num_args != 0) {
2108        zend_error(error_type, "Method %s::%s() cannot take arguments", ce->name->val, ZEND_DEBUGINFO_FUNC_NAME);
2109    }
2110}
2111/* }}} */
2112
2113/* registers all functions in *library_functions in the function hash */
2114ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */
2115{
2116    const zend_function_entry *ptr = functions;
2117    zend_function function, *reg_function;
2118    zend_internal_function *internal_function = (zend_internal_function *)&function;
2119    int count=0, unload=0;
2120    HashTable *target_function_table = function_table;
2121    int error_type;
2122    zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL;
2123    zend_string *lowercase_name;
2124    size_t fname_len;
2125    const char *lc_class_name = NULL;
2126    size_t class_name_len = 0;
2127
2128    if (type==MODULE_PERSISTENT) {
2129        error_type = E_CORE_WARNING;
2130    } else {
2131        error_type = E_WARNING;
2132    }
2133
2134    if (!target_function_table) {
2135        target_function_table = CG(function_table);
2136    }
2137    internal_function->type = ZEND_INTERNAL_FUNCTION;
2138    internal_function->module = EG(current_module);
2139
2140    if (scope) {
2141        class_name_len = scope->name->len;
2142        if ((lc_class_name = zend_memrchr(scope->name->val, '\\', class_name_len))) {
2143            ++lc_class_name;
2144            class_name_len -= (lc_class_name - scope->name->val);
2145            lc_class_name = zend_str_tolower_dup(lc_class_name, class_name_len);
2146        } else {
2147            lc_class_name = zend_str_tolower_dup(scope->name->val, class_name_len);
2148        }
2149    }
2150
2151    while (ptr->fname) {
2152        fname_len = strlen(ptr->fname);
2153        internal_function->handler = ptr->handler;
2154        internal_function->function_name = zend_new_interned_string(zend_string_init(ptr->fname, fname_len, 1));
2155        internal_function->scope = scope;
2156        internal_function->prototype = NULL;
2157        if (ptr->flags) {
2158            if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
2159                if (ptr->flags != ZEND_ACC_DEPRECATED || scope) {
2160                    zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2161                }
2162                internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags;
2163            } else {
2164                internal_function->fn_flags = ptr->flags;
2165            }
2166        } else {
2167            internal_function->fn_flags = ZEND_ACC_PUBLIC;
2168        }
2169        if (ptr->arg_info) {
2170            zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
2171
2172            internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1;
2173            internal_function->num_args = ptr->num_args;
2174            /* Currently you cannot denote that the function can accept less arguments than num_args */
2175            if (info->required_num_args == (zend_uintptr_t)-1) {
2176                internal_function->required_num_args = ptr->num_args;
2177            } else {
2178                internal_function->required_num_args = info->required_num_args;
2179            }
2180            if (info->return_reference) {
2181                internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
2182            }
2183            if (ptr->arg_info[ptr->num_args].is_variadic) {
2184                internal_function->fn_flags |= ZEND_ACC_VARIADIC;
2185                /* Don't count the variadic argument */
2186                internal_function->num_args--;
2187            }
2188            if (info->type_hint) {
2189                if (info->class_name) {
2190                    ZEND_ASSERT(info->type_hint == IS_OBJECT);
2191                    if (!scope && (!strcasecmp(info->class_name, "self") || !strcasecmp(info->class_name, "parent"))) {
2192                        zend_error(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", info->class_name);
2193                    }
2194                }
2195
2196                internal_function->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
2197            }
2198        } else {
2199            internal_function->arg_info = NULL;
2200            internal_function->num_args = 0;
2201            internal_function->required_num_args = 0;
2202        }
2203        if (ptr->flags & ZEND_ACC_ABSTRACT) {
2204            if (scope) {
2205                /* This is a class that must be abstract itself. Here we set the check info. */
2206                scope->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2207                if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
2208                    /* Since the class is not an interface it needs to be declared as a abstract class. */
2209                    /* Since here we are handling internal functions only we can add the keyword flag. */
2210                    /* This time we set the flag for the keyword 'abstract'. */
2211                    scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2212                }
2213            }
2214            if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
2215                zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2216            }
2217        } else {
2218            if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) {
2219                efree((char*)lc_class_name);
2220                zend_error(error_type, "Interface %s cannot contain non abstract method %s()", scope->name->val, ptr->fname);
2221                return FAILURE;
2222            }
2223            if (!internal_function->handler) {
2224                if (scope) {
2225                    efree((char*)lc_class_name);
2226                }
2227                zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2228                zend_unregister_functions(functions, count, target_function_table);
2229                return FAILURE;
2230            }
2231        }
2232        lowercase_name = zend_string_alloc(fname_len, 1);
2233        zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2234        lowercase_name = zend_new_interned_string(lowercase_name);
2235        reg_function = malloc(sizeof(zend_internal_function));
2236        memcpy(reg_function, &function, sizeof(zend_internal_function));
2237        if (zend_hash_add_ptr(target_function_table, lowercase_name, reg_function) == NULL) {
2238            unload=1;
2239            free(reg_function);
2240            zend_string_release(lowercase_name);
2241            break;
2242        }
2243
2244        /* If types of arguments have to be checked */
2245        if (reg_function->common.arg_info && reg_function->common.num_args) {
2246            uint32_t i;
2247            for (i = 0; i < reg_function->common.num_args; i++) {
2248                if (reg_function->common.arg_info[i].class_name ||
2249                    reg_function->common.arg_info[i].type_hint) {
2250                    reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
2251                    break;
2252                }
2253            }
2254        }
2255
2256        if (scope) {
2257            /* Look for ctor, dtor, clone
2258             * If it's an old-style constructor, store it only if we don't have
2259             * a constructor already.
2260             */
2261            if ((fname_len == class_name_len) && !ctor && !memcmp(lowercase_name->val, lc_class_name, class_name_len+1)) {
2262                ctor = reg_function;
2263            } else if (zend_string_equals_literal(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2264                ctor = reg_function;
2265            } else if (zend_string_equals_literal(lowercase_name, ZEND_DESTRUCTOR_FUNC_NAME)) {
2266                dtor = reg_function;
2267                if (internal_function->num_args) {
2268                    zend_error(error_type, "Destructor %s::%s() cannot take arguments", scope->name->val, ptr->fname);
2269                }
2270            } else if (zend_string_equals_literal(lowercase_name, ZEND_CLONE_FUNC_NAME)) {
2271                clone = reg_function;
2272            } else if (zend_string_equals_literal(lowercase_name, ZEND_CALL_FUNC_NAME)) {
2273                __call = reg_function;
2274            } else if (zend_string_equals_literal(lowercase_name, ZEND_CALLSTATIC_FUNC_NAME)) {
2275                __callstatic = reg_function;
2276            } else if (zend_string_equals_literal(lowercase_name, ZEND_TOSTRING_FUNC_NAME)) {
2277                __tostring = reg_function;
2278            } else if (zend_string_equals_literal(lowercase_name, ZEND_GET_FUNC_NAME)) {
2279                __get = reg_function;
2280                scope->ce_flags |= ZEND_ACC_USE_GUARDS;
2281            } else if (zend_string_equals_literal(lowercase_name, ZEND_SET_FUNC_NAME)) {
2282                __set = reg_function;
2283                scope->ce_flags |= ZEND_ACC_USE_GUARDS;
2284            } else if (zend_string_equals_literal(lowercase_name, ZEND_UNSET_FUNC_NAME)) {
2285                __unset = reg_function;
2286                scope->ce_flags |= ZEND_ACC_USE_GUARDS;
2287            } else if (zend_string_equals_literal(lowercase_name, ZEND_ISSET_FUNC_NAME)) {
2288                __isset = reg_function;
2289                scope->ce_flags |= ZEND_ACC_USE_GUARDS;
2290            } else if (zend_string_equals_literal(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME)) {
2291                __debugInfo = reg_function;
2292            } else {
2293                reg_function = NULL;
2294            }
2295            if (reg_function) {
2296                zend_check_magic_method_implementation(scope, reg_function, error_type);
2297            }
2298        }
2299        ptr++;
2300        count++;
2301        zend_string_release(lowercase_name);
2302    }
2303    if (unload) { /* before unloading, display all remaining bad function in the module */
2304        if (scope) {
2305            efree((char*)lc_class_name);
2306        }
2307        while (ptr->fname) {
2308            fname_len = strlen(ptr->fname);
2309            lowercase_name = zend_string_alloc(fname_len, 0);
2310            zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2311            if (zend_hash_exists(target_function_table, lowercase_name)) {
2312                zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name->val : "", scope ? "::" : "", ptr->fname);
2313            }
2314            zend_string_free(lowercase_name);
2315            ptr++;
2316        }
2317        zend_unregister_functions(functions, count, target_function_table);
2318        return FAILURE;
2319    }
2320    if (scope) {
2321        scope->constructor = ctor;
2322        scope->destructor = dtor;
2323        scope->clone = clone;
2324        scope->__call = __call;
2325        scope->__callstatic = __callstatic;
2326        scope->__tostring = __tostring;
2327        scope->__get = __get;
2328        scope->__set = __set;
2329        scope->__unset = __unset;
2330        scope->__isset = __isset;
2331        scope->__debugInfo = __debugInfo;
2332        if (ctor) {
2333            ctor->common.fn_flags |= ZEND_ACC_CTOR;
2334            if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
2335                zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name->val, ctor->common.function_name->val);
2336            }
2337            ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2338        }
2339        if (dtor) {
2340            dtor->common.fn_flags |= ZEND_ACC_DTOR;
2341            if (dtor->common.fn_flags & ZEND_ACC_STATIC) {
2342                zend_error(error_type, "Destructor %s::%s() cannot be static", scope->name->val, dtor->common.function_name->val);
2343            }
2344            dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2345        }
2346        if (clone) {
2347            clone->common.fn_flags |= ZEND_ACC_CLONE;
2348            if (clone->common.fn_flags & ZEND_ACC_STATIC) {
2349                zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name->val, clone->common.function_name->val);
2350            }
2351            clone->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2352        }
2353        if (__call) {
2354            if (__call->common.fn_flags & ZEND_ACC_STATIC) {
2355                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __call->common.function_name->val);
2356            }
2357            __call->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2358        }
2359        if (__callstatic) {
2360            if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) {
2361                zend_error(error_type, "Method %s::%s() must be static", scope->name->val, __callstatic->common.function_name->val);
2362            }
2363            __callstatic->common.fn_flags |= ZEND_ACC_STATIC;
2364        }
2365        if (__tostring) {
2366            if (__tostring->common.fn_flags & ZEND_ACC_STATIC) {
2367                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __tostring->common.function_name->val);
2368            }
2369            __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2370        }
2371        if (__get) {
2372            if (__get->common.fn_flags & ZEND_ACC_STATIC) {
2373                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __get->common.function_name->val);
2374            }
2375            __get->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2376        }
2377        if (__set) {
2378            if (__set->common.fn_flags & ZEND_ACC_STATIC) {
2379                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __set->common.function_name->val);
2380            }
2381            __set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2382        }
2383        if (__unset) {
2384            if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
2385                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __unset->common.function_name->val);
2386            }
2387            __unset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2388        }
2389        if (__isset) {
2390            if (__isset->common.fn_flags & ZEND_ACC_STATIC) {
2391                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __isset->common.function_name->val);
2392            }
2393            __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
2394        }
2395        if (__debugInfo) {
2396            if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) {
2397                zend_error(error_type, "Method %s::%s() cannot be static", scope->name->val, __debugInfo->common.function_name->val);
2398            }
2399        }
2400
2401        if (ctor && ctor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && ctor->common.fn_flags & ZEND_ACC_CTOR) {
2402            zend_error(E_CORE_ERROR, "Constructor %s::%s() cannot declare a return type", scope->name->val, ctor->common.function_name->val);
2403        }
2404
2405        if (dtor && dtor->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && dtor->common.fn_flags & ZEND_ACC_DTOR) {
2406            zend_error(E_CORE_ERROR, "Destructor %s::%s() cannot declare a return type", scope->name->val, dtor->common.function_name->val);
2407        }
2408
2409        if (clone && clone->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && dtor->common.fn_flags & ZEND_ACC_DTOR) {
2410            zend_error(E_CORE_ERROR, "%s::%s() cannot declare a return type", scope->name->val, clone->common.function_name->val);
2411        }
2412        efree((char*)lc_class_name);
2413    }
2414    return SUCCESS;
2415}
2416/* }}} */
2417
2418/* count=-1 means erase all functions, otherwise,
2419 * erase the first count functions
2420 */
2421ZEND_API void zend_unregister_functions(const zend_function_entry *functions, int count, HashTable *function_table) /* {{{ */
2422{
2423    const zend_function_entry *ptr = functions;
2424    int i=0;
2425    HashTable *target_function_table = function_table;
2426    zend_string *lowercase_name;
2427    size_t fname_len;
2428
2429    if (!target_function_table) {
2430        target_function_table = CG(function_table);
2431    }
2432    while (ptr->fname) {
2433        if (count!=-1 && i>=count) {
2434            break;
2435        }
2436        fname_len = strlen(ptr->fname);
2437        lowercase_name = zend_string_alloc(fname_len, 0);
2438        zend_str_tolower_copy(lowercase_name->val, ptr->fname, fname_len);
2439        zend_hash_del(target_function_table, lowercase_name);
2440        zend_string_free(lowercase_name);
2441        ptr++;
2442        i++;
2443    }
2444}
2445/* }}} */
2446
2447ZEND_API int zend_startup_module(zend_module_entry *module) /* {{{ */
2448{
2449    if ((module = zend_register_internal_module(module)) != NULL && zend_startup_module_ex(module) == SUCCESS) {
2450        return SUCCESS;
2451    }
2452    return FAILURE;
2453}
2454/* }}} */
2455
2456ZEND_API int zend_get_module_started(const char *module_name) /* {{{ */
2457{
2458    zend_module_entry *module;
2459
2460    module = zend_hash_str_find_ptr(&module_registry, module_name, strlen(module_name));
2461    return (module && module->module_started) ? SUCCESS : FAILURE;
2462}
2463/* }}} */
2464
2465static int clean_module_class(zval *el, void *arg) /* {{{ */
2466{
2467    zend_class_entry *ce = (zend_class_entry *)Z_PTR_P(el);
2468    int module_number = *(int *)arg;
2469    if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) {
2470        return ZEND_HASH_APPLY_REMOVE;
2471    } else {
2472        return ZEND_HASH_APPLY_KEEP;
2473    }
2474}
2475/* }}} */
2476
2477static void clean_module_classes(int module_number) /* {{{ */
2478{
2479    zend_hash_apply_with_argument(EG(class_table), clean_module_class, (void *) &module_number);
2480}
2481/* }}} */
2482
2483void module_destructor(zend_module_entry *module) /* {{{ */
2484{
2485
2486    if (module->type == MODULE_TEMPORARY) {
2487        zend_clean_module_rsrc_dtors(module->module_number);
2488        clean_module_constants(module->module_number);
2489        clean_module_classes(module->module_number);
2490    }
2491
2492    if (module->module_started && module->module_shutdown_func) {
2493#if 0
2494        zend_printf("%s: Module shutdown\n", module->name);
2495#endif
2496        module->module_shutdown_func(module->type, module->module_number);
2497    }
2498
2499    /* Deinitilaise module globals */
2500    if (module->globals_size) {
2501#ifdef ZTS
2502        if (*module->globals_id_ptr) {
2503            ts_free_id(*module->globals_id_ptr);
2504        }
2505#else
2506        if (module->globals_dtor) {
2507            module->globals_dtor(module->globals_ptr);
2508        }
2509#endif
2510    }
2511
2512    module->module_started=0;
2513    if (module->functions) {
2514        zend_unregister_functions(module->functions, -1, NULL);
2515    }
2516
2517#if HAVE_LIBDL
2518#if !(defined(NETWARE) && defined(APACHE_1_BUILD))
2519    if (module->handle && !getenv("ZEND_DONT_UNLOAD_MODULES")) {
2520        DL_UNLOAD(module->handle);
2521    }
2522#endif
2523#endif
2524}
2525/* }}} */
2526
2527ZEND_API void zend_activate_modules(void) /* {{{ */
2528{
2529    zend_module_entry **p = module_request_startup_handlers;
2530
2531    while (*p) {
2532        zend_module_entry *module = *p;
2533
2534        if (module->request_startup_func(module->type, module->module_number)==FAILURE) {
2535            zend_error(E_WARNING, "request_startup() for %s module failed", module->name);
2536            exit(1);
2537        }
2538        p++;
2539    }
2540}
2541/* }}} */
2542
2543/* call request shutdown for all modules */
2544static int module_registry_cleanup(zval *zv) /* {{{ */
2545{
2546    zend_module_entry *module = Z_PTR_P(zv);
2547
2548    if (module->request_shutdown_func) {
2549#if 0
2550        zend_printf("%s: Request shutdown\n", module->name);
2551#endif
2552        module->request_shutdown_func(module->type, module->module_number);
2553    }
2554    return 0;
2555}
2556/* }}} */
2557
2558ZEND_API void zend_deactivate_modules(void) /* {{{ */
2559{
2560    EG(current_execute_data) = NULL; /* we're no longer executing anything */
2561
2562    zend_try {
2563        if (EG(full_tables_cleanup)) {
2564            zend_hash_reverse_apply(&module_registry, module_registry_cleanup);
2565        } else {
2566            zend_module_entry **p = module_request_shutdown_handlers;
2567
2568            while (*p) {
2569                zend_module_entry *module = *p;
2570
2571                module->request_shutdown_func(module->type, module->module_number);
2572                p++;
2573            }
2574        }
2575    } zend_end_try();
2576}
2577/* }}} */
2578
2579ZEND_API void zend_cleanup_internal_classes(void) /* {{{ */
2580{
2581    zend_class_entry **p = class_cleanup_handlers;
2582
2583    while (*p) {
2584        zend_cleanup_internal_class_data(*p);
2585        p++;
2586    }
2587}
2588/* }}} */
2589
2590int module_registry_unload_temp(const zend_module_entry *module) /* {{{ */
2591{
2592    return (module->type == MODULE_TEMPORARY) ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_STOP;
2593}
2594/* }}} */
2595
2596static int module_registry_unload_temp_wrapper(zval *el) /* {{{ */
2597{
2598    zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el);
2599    return module_registry_unload_temp((const zend_module_entry *)module);
2600}
2601/* }}} */
2602
2603static int exec_done_cb(zval *el) /* {{{ */
2604{
2605    zend_module_entry *module = (zend_module_entry *)Z_PTR_P(el);
2606    if (module->post_deactivate_func) {
2607        module->post_deactivate_func();
2608    }
2609    return 0;
2610}
2611/* }}} */
2612
2613ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
2614{
2615    if (EG(full_tables_cleanup)) {
2616        zend_hash_apply(&module_registry, exec_done_cb);
2617        zend_hash_reverse_apply(&module_registry, module_registry_unload_temp_wrapper);
2618    } else {
2619        zend_module_entry **p = module_post_deactivate_handlers;
2620
2621        while (*p) {
2622            zend_module_entry *module = *p;
2623
2624            module->post_deactivate_func();
2625            p++;
2626        }
2627    }
2628}
2629/* }}} */
2630
2631/* return the next free module number */
2632ZEND_API int zend_next_free_module(void) /* {{{ */
2633{
2634    return zend_hash_num_elements(&module_registry) + 1;
2635}
2636/* }}} */
2637
2638static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, uint32_t ce_flags) /* {{{ */
2639{
2640    zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
2641    zend_string *lowercase_name = zend_string_alloc(orig_class_entry->name->len, 1);
2642    *class_entry = *orig_class_entry;
2643
2644    class_entry->type = ZEND_INTERNAL_CLASS;
2645    zend_initialize_class_data(class_entry, 0);
2646    class_entry->ce_flags = ce_flags | ZEND_ACC_CONSTANTS_UPDATED;
2647    class_entry->info.internal.module = EG(current_module);
2648
2649    if (class_entry->info.internal.builtin_functions) {
2650        zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT);
2651    }
2652
2653    zend_str_tolower_copy(lowercase_name->val, orig_class_entry->name->val, class_entry->name->len);
2654    lowercase_name = zend_new_interned_string(lowercase_name);
2655    zend_hash_update_ptr(CG(class_table), lowercase_name, class_entry);
2656    zend_string_release(lowercase_name);
2657    return class_entry;
2658}
2659/* }}} */
2660
2661/* If parent_ce is not NULL then it inherits from parent_ce
2662 * If parent_ce is NULL and parent_name isn't then it looks for the parent and inherits from it
2663 * If both parent_ce and parent_name are NULL it does a regular class registration
2664 * If parent_name is specified but not found NULL is returned
2665 */
2666ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce) /* {{{ */
2667{
2668    zend_class_entry *register_class;
2669
2670    register_class = zend_register_internal_class(class_entry);
2671
2672    if (parent_ce) {
2673        zend_do_inheritance(register_class, parent_ce);
2674    }
2675    return register_class;
2676}
2677/* }}} */
2678
2679ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_interfaces, ...) /* {{{ */
2680{
2681    zend_class_entry *interface_entry;
2682    va_list interface_list;
2683    va_start(interface_list, num_interfaces);
2684
2685    while (num_interfaces--) {
2686        interface_entry = va_arg(interface_list, zend_class_entry *);
2687        zend_do_implement_interface(class_entry, interface_entry);
2688    }
2689
2690    va_end(interface_list);
2691}
2692/* }}} */
2693
2694/* A class that contains at least one abstract method automatically becomes an abstract class.
2695 */
2696ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry) /* {{{ */
2697{
2698    return do_register_internal_class(orig_class_entry, 0);
2699}
2700/* }}} */
2701
2702ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry) /* {{{ */
2703{
2704    return do_register_internal_class(orig_class_entry, ZEND_ACC_INTERFACE);
2705}
2706/* }}} */
2707
2708ZEND_API int zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce) /* {{{ */
2709{
2710    zend_string *lcname;
2711
2712    if (name[0] == '\\') {
2713        lcname = zend_string_alloc(name_len-1, 1);
2714        zend_str_tolower_copy(lcname->val, name+1, name_len-1);
2715    } else {
2716        lcname = zend_string_alloc(name_len, 1);
2717        zend_str_tolower_copy(lcname->val, name, name_len);
2718    }
2719
2720    zend_assert_valid_class_name(lcname);
2721
2722    ce = zend_hash_add_ptr(CG(class_table), lcname, ce);
2723    zend_string_release(lcname);
2724    if (ce) {
2725        ce->refcount++;
2726        return SUCCESS;
2727    }
2728    return FAILURE;
2729}
2730/* }}} */
2731
2732ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...) /* {{{ */
2733{
2734    HashTable *symbol_table;
2735    va_list symbol_table_list;
2736
2737    if (num_symbol_tables <= 0) return FAILURE;
2738
2739    if (is_ref) {
2740        ZVAL_MAKE_REF(symbol);
2741    }
2742
2743    va_start(symbol_table_list, num_symbol_tables);
2744    while (num_symbol_tables-- > 0) {
2745        symbol_table = va_arg(symbol_table_list, HashTable *);
2746        zend_hash_str_update(symbol_table, name, name_length, symbol);
2747        if (Z_REFCOUNTED_P(symbol)) {
2748            Z_ADDREF_P(symbol);
2749        }
2750    }
2751    va_end(symbol_table_list);
2752    return SUCCESS;
2753}
2754/* }}} */
2755
2756/* Disabled functions support */
2757
2758/* {{{ proto void display_disabled_function(void)
2759Dummy function which displays an error when a disabled function is called. */
2760ZEND_API ZEND_FUNCTION(display_disabled_function)
2761{
2762    zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name());
2763}
2764/* }}} */
2765
2766ZEND_API int zend_disable_function(char *function_name, size_t function_name_length) /* {{{ */
2767{
2768    zend_internal_function *func;
2769    if ((func = zend_hash_str_find_ptr(CG(function_table), function_name, function_name_length))) {
2770        func->fn_flags &= ~(ZEND_ACC_VARIADIC | ZEND_ACC_HAS_TYPE_HINTS);
2771        func->num_args = 0;
2772        func->arg_info = NULL;
2773        func->handler = ZEND_FN(display_disabled_function);
2774        return SUCCESS;
2775    }
2776    return FAILURE;
2777}
2778/* }}} */
2779
2780#ifdef ZEND_WIN32
2781#pragma optimize("", off)
2782#endif
2783static zend_object *display_disabled_class(zend_class_entry *class_type) /* {{{ */
2784{
2785    zend_object *intern;
2786
2787    intern = zend_objects_new(class_type);
2788    zend_error(E_WARNING, "%s() has been disabled for security reasons", class_type->name->val);
2789    return intern;
2790}
2791#ifdef ZEND_WIN32
2792#pragma optimize("", on)
2793#endif
2794/* }}} */
2795
2796static const zend_function_entry disabled_class_new[] = {
2797    ZEND_FE_END
2798};
2799
2800ZEND_API int zend_disable_class(char *class_name, size_t class_name_length) /* {{{ */
2801{
2802    zend_class_entry *disabled_class;
2803    zend_string *key;
2804
2805    key = zend_string_alloc(class_name_length, 0);
2806    zend_str_tolower_copy(key->val, class_name, class_name_length);
2807    disabled_class = zend_hash_find_ptr(CG(class_table), key);
2808    if (!disabled_class) {
2809        return FAILURE;
2810    }
2811    INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new, NULL, NULL, NULL, NULL, NULL);
2812    disabled_class->create_object = display_disabled_class;
2813    zend_hash_clean(&disabled_class->function_table);
2814    return SUCCESS;
2815}
2816/* }}} */
2817
2818static int zend_is_callable_check_class(zend_string *name, zend_fcall_info_cache *fcc, int *strict_class, char **error) /* {{{ */
2819{
2820    int ret = 0;
2821    zend_class_entry *ce;
2822    size_t name_len = name->len;
2823    zend_string *lcname;
2824    ALLOCA_FLAG(use_heap);
2825
2826    STR_ALLOCA_ALLOC(lcname, name_len, use_heap);
2827    zend_str_tolower_copy(lcname->val, name->val, name_len);
2828
2829    *strict_class = 0;
2830    if (zend_string_equals_literal(lcname, "self")) {
2831        if (!EG(scope)) {
2832            if (error) *error = estrdup("cannot access self:: when no class scope is active");
2833        } else {
2834            fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
2835            fcc->calling_scope = EG(scope);
2836            if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) {
2837                fcc->object = Z_OBJ(EG(current_execute_data)->This);
2838            }
2839            ret = 1;
2840        }
2841    } else if (zend_string_equals_literal(lcname, "parent")) {
2842        if (!EG(scope)) {
2843            if (error) *error = estrdup("cannot access parent:: when no class scope is active");
2844        } else if (!EG(scope)->parent) {
2845            if (error) *error = estrdup("cannot access parent:: when current class scope has no parent");
2846        } else {
2847            fcc->called_scope = EG(current_execute_data) ? EG(current_execute_data)->called_scope : NULL;
2848            fcc->calling_scope = EG(scope)->parent;
2849            if (!fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This)) {
2850                fcc->object = Z_OBJ(EG(current_execute_data)->This);
2851            }
2852            *strict_class = 1;
2853            ret = 1;
2854        }
2855    } else if (zend_string_equals_literal(lcname, "static")) {
2856        if (!EG(current_execute_data) || !EG(current_execute_data)->called_scope) {
2857            if (error) *error = estrdup("cannot access static:: when no class scope is active");
2858        } else {
2859            fcc->called_scope = EG(current_execute_data)->called_scope;
2860            fcc->calling_scope = EG(current_execute_data)->called_scope;
2861            if (!fcc->object && Z_OBJ(EG(current_execute_data)->This)) {
2862                fcc->object = Z_OBJ(EG(current_execute_data)->This);
2863            }
2864            *strict_class = 1;
2865            ret = 1;
2866        }
2867    } else if ((ce = zend_lookup_class_ex(name, NULL, 1)) != NULL) {
2868        zend_class_entry *scope;
2869        zend_execute_data *ex = EG(current_execute_data);
2870
2871        while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
2872            ex = ex->prev_execute_data;
2873        }
2874        scope = ex ? ex->func->common.scope : NULL;
2875        fcc->calling_scope = ce;
2876        if (scope && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) &&
2877            instanceof_function(Z_OBJCE(EG(current_execute_data)->This), scope) &&
2878            instanceof_function(scope, fcc->calling_scope)) {
2879            fcc->object = Z_OBJ(EG(current_execute_data)->This);
2880            fcc->called_scope = Z_OBJCE(EG(current_execute_data)->This);
2881        } else {
2882            fcc->called_scope = fcc->object ? fcc->object->ce : fcc->calling_scope;
2883        }
2884        *strict_class = 1;
2885        ret = 1;
2886    } else {
2887        if (error) zend_spprintf(error, 0, "class '%.*s' not found", name_len, name->val);
2888    }
2889    STR_ALLOCA_FREE(lcname, use_heap);
2890    return ret;
2891}
2892/* }}} */
2893
2894static int zend_is_callable_check_func(int check_flags, zval *callable, zend_fcall_info_cache *fcc, int strict_class, char **error) /* {{{ */
2895{
2896    zend_class_entry *ce_org = fcc->calling_scope;
2897    int retval = 0;
2898    zend_string *mname, *cname;
2899    zend_string *lmname;
2900    const char *colon;
2901    size_t clen, mlen;
2902    zend_class_entry *last_scope;
2903    HashTable *ftable;
2904    int call_via_handler = 0;
2905    ALLOCA_FLAG(use_heap)
2906
2907    if (error) {
2908        *error = NULL;
2909    }
2910
2911    fcc->calling_scope = NULL;
2912    fcc->function_handler = NULL;
2913
2914    if (!ce_org) {
2915        zend_string *lmname;
2916
2917        /* Skip leading \ */
2918        if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
2919            STR_ALLOCA_INIT(lmname, Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1, use_heap);
2920        } else {
2921            lmname = Z_STR_P(callable);
2922        }
2923        /* Check if function with given name exists.
2924         * This may be a compound name that includes namespace name */
2925        if (EXPECTED((fcc->function_handler = zend_hash_find_ptr(EG(function_table), lmname)) != NULL)) {
2926            if (lmname != Z_STR_P(callable)) {
2927                STR_ALLOCA_FREE(lmname, use_heap);
2928            }
2929            return 1;
2930        } else {
2931            if (lmname == Z_STR_P(callable)) {
2932                STR_ALLOCA_INIT(lmname, Z_STRVAL_P(callable), Z_STRLEN_P(callable), use_heap);
2933            } else {
2934                zend_string_forget_hash_val(lmname);
2935            }
2936            zend_str_tolower(lmname->val, lmname->len);
2937            if ((fcc->function_handler = zend_hash_find_ptr(EG(function_table), lmname)) != NULL) {
2938                STR_ALLOCA_FREE(lmname, use_heap);
2939                return 1;
2940            }
2941        }
2942        if (lmname != Z_STR_P(callable)) {
2943            STR_ALLOCA_FREE(lmname, use_heap);
2944        }
2945    }
2946
2947    /* Split name into class/namespace and method/function names */
2948    if ((colon = zend_memrchr(Z_STRVAL_P(callable), ':', Z_STRLEN_P(callable))) != NULL &&
2949        colon > Z_STRVAL_P(callable) &&
2950        *(colon-1) == ':'
2951    ) {
2952        colon--;
2953        clen = colon - Z_STRVAL_P(callable);
2954        mlen = Z_STRLEN_P(callable) - clen - 2;
2955
2956        if (colon == Z_STRVAL_P(callable)) {
2957            if (error) zend_spprintf(error, 0, "invalid function name");
2958            return 0;
2959        }
2960
2961        /* This is a compound name.
2962         * Try to fetch class and then find static method. */
2963        last_scope = EG(scope);
2964        if (ce_org) {
2965            EG(scope) = ce_org;
2966        }
2967
2968        cname = zend_string_init(Z_STRVAL_P(callable), clen, 0);
2969        if (!zend_is_callable_check_class(cname, fcc, &strict_class, error)) {
2970            zend_string_release(cname);
2971            EG(scope) = last_scope;
2972            return 0;
2973        }
2974        zend_string_release(cname);
2975        EG(scope) = last_scope;
2976
2977        ftable = &fcc->calling_scope->function_table;
2978        if (ce_org && !instanceof_function(ce_org, fcc->calling_scope)) {
2979            if (error) zend_spprintf(error, 0, "class '%s' is not a subclass of '%s'", ce_org->name->val, fcc->calling_scope->name->val);
2980            return 0;
2981        }
2982        mname = zend_string_init(Z_STRVAL_P(callable) + clen + 2, mlen, 0);
2983    } else if (ce_org) {
2984        /* Try to fetch find static method of given class. */
2985        mlen = Z_STRLEN_P(callable);
2986        mname = Z_STR_P(callable);
2987        zend_string_addref(mname);
2988        ftable = &ce_org->function_table;
2989        fcc->calling_scope = ce_org;
2990    } else {
2991        /* We already checked for plain function before. */
2992        if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
2993            zend_spprintf(error, 0, "function '%s' not found or invalid function name", Z_STRVAL_P(callable));
2994        }
2995        return 0;
2996    }
2997
2998    lmname = zend_string_tolower(mname);
2999    if (strict_class &&
3000        fcc->calling_scope &&
3001        zend_string_equals_literal(lmname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
3002        fcc->function_handler = fcc->calling_scope->constructor;
3003        if (fcc->function_handler) {
3004            retval = 1;
3005        }
3006    } else if ((fcc->function_handler = zend_hash_find_ptr(ftable, lmname)) != NULL) {
3007        retval = 1;
3008        if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) &&
3009            !strict_class && EG(scope) &&
3010            instanceof_function(fcc->function_handler->common.scope, EG(scope))) {
3011            zend_function *priv_fbc;
3012
3013            if ((priv_fbc = zend_hash_find_ptr(&EG(scope)->function_table, lmname)) != NULL
3014                && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
3015                && priv_fbc->common.scope == EG(scope)) {
3016                fcc->function_handler = priv_fbc;
3017            }
3018        }
3019        if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0 &&
3020            (fcc->calling_scope &&
3021             ((fcc->object && fcc->calling_scope->__call) ||
3022              (!fcc->object && fcc->calling_scope->__callstatic)))) {
3023            if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
3024                if (!zend_check_private(fcc->function_handler, fcc->object ? fcc->object->ce : EG(scope), lmname)) {
3025                    retval = 0;
3026                    fcc->function_handler = NULL;
3027                    goto get_function_via_handler;
3028                }
3029            } else if (fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED) {
3030                if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
3031                    retval = 0;
3032                    fcc->function_handler = NULL;
3033                    goto get_function_via_handler;
3034                }
3035            }
3036        }
3037    } else {
3038get_function_via_handler:
3039        if (fcc->object && fcc->calling_scope == ce_org) {
3040            if (strict_class && ce_org->__call) {
3041                fcc->function_handler = emalloc(sizeof(zend_internal_function));
3042                fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION;
3043                fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL;
3044                fcc->function_handler->internal_function.handler = zend_std_call_user_call;
3045                fcc->function_handler->internal_function.arg_info = NULL;
3046                fcc->function_handler->internal_function.num_args = 0;
3047                fcc->function_handler->internal_function.scope = ce_org;
3048                fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
3049                fcc->function_handler->internal_function.function_name = mname;
3050                zend_string_addref(mname);
3051                call_via_handler = 1;
3052                retval = 1;
3053            } else if (fcc->object->handlers->get_method) {
3054                fcc->function_handler = fcc->object->handlers->get_method(&fcc->object, mname, NULL);
3055                if (fcc->function_handler) {
3056                    if (strict_class &&
3057                        (!fcc->function_handler->common.scope ||
3058                         !instanceof_function(ce_org, fcc->function_handler->common.scope))) {
3059                        if ((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) {
3060                            if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3061                                zend_string_release(fcc->function_handler->common.function_name);
3062                            }
3063                            efree(fcc->function_handler);
3064                        }
3065                    } else {
3066                        retval = 1;
3067                        call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
3068                    }
3069                }
3070            }
3071        } else if (fcc->calling_scope) {
3072            if (fcc->calling_scope->get_static_method) {
3073                fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname);
3074            } else {
3075                fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, NULL);
3076            }
3077            if (fcc->function_handler) {
3078                retval = 1;
3079                call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0;
3080                if (call_via_handler && !fcc->object && EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) &&
3081                    instanceof_function(Z_OBJCE(EG(current_execute_data)->This), fcc->calling_scope)) {
3082                    fcc->object = Z_OBJ(EG(current_execute_data)->This);
3083                }
3084            }
3085        }
3086    }
3087
3088    if (retval) {
3089        if (fcc->calling_scope && !call_via_handler) {
3090            if (!fcc->object && (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3091                if (error) {
3092                    zend_spprintf(error, 0, "cannot call abstract method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3093                    retval = 0;
3094                } else {
3095                    zend_error(E_ERROR, "Cannot call abstract method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3096                }
3097            } else if (!fcc->object && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
3098                int severity;
3099                char *verb;
3100                if (fcc->function_handler->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
3101                    severity = E_STRICT;
3102                    verb = "should not";
3103                } else {
3104                    /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
3105                    severity = E_ERROR;
3106                    verb = "cannot";
3107                }
3108                if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
3109                    retval = 0;
3110                }
3111                if (EG(current_execute_data) && Z_OBJ(EG(current_execute_data)->This) && instanceof_function(Z_OBJCE(EG(current_execute_data)->This), fcc->calling_scope)) {
3112                    fcc->object = Z_OBJ(EG(current_execute_data)->This);
3113                    if (error) {
3114                        zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb, Z_OBJCE(EG(current_execute_data)->This)->name->val);
3115                        if (severity == E_ERROR) {
3116                            retval = 0;
3117                        }
3118                    } else if (retval) {
3119                        zend_error(severity, "Non-static method %s::%s() %s be called statically, assuming $this from compatible context %s", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb, Z_OBJCE(EG(current_execute_data)->This)->name->val);
3120                    }
3121                } else {
3122                    if (error) {
3123                        zend_spprintf(error, 0, "non-static method %s::%s() %s be called statically", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb);
3124                        if (severity == E_ERROR) {
3125                            retval = 0;
3126                        }
3127                    } else if (retval) {
3128                        zend_error(severity, "Non-static method %s::%s() %s be called statically", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val, verb);
3129                    }
3130                }
3131            }
3132            if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
3133                if (fcc->function_handler->op_array.fn_flags & ZEND_ACC_PRIVATE) {
3134                    if (!zend_check_private(fcc->function_handler, fcc->object ? fcc->object->ce : EG(scope), lmname)) {
3135                        if (error) {
3136                            if (*error) {
3137                                efree(*error);
3138                            }
3139                            zend_spprintf(error, 0, "cannot access private method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3140                        }
3141                        retval = 0;
3142                    }
3143                } else if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PROTECTED)) {
3144                    if (!zend_check_protected(fcc->function_handler->common.scope, EG(scope))) {
3145                        if (error) {
3146                            if (*error) {
3147                                efree(*error);
3148                            }
3149                            zend_spprintf(error, 0, "cannot access protected method %s::%s()", fcc->calling_scope->name->val, fcc->function_handler->common.function_name->val);
3150                        }
3151                        retval = 0;
3152                    }
3153                }
3154            }
3155        }
3156    } else if (error && !(check_flags & IS_CALLABLE_CHECK_SILENT)) {
3157        if (fcc->calling_scope) {
3158            if (error) zend_spprintf(error, 0, "class '%s' does not have a method '%s'", fcc->calling_scope->name->val, mname->val);
3159        } else {
3160            if (error) zend_spprintf(error, 0, "function '%s' does not exist", mname->val);
3161        }
3162    }
3163    zend_string_release(lmname);
3164    zend_string_release(mname);
3165
3166    if (fcc->object) {
3167        fcc->called_scope = fcc->object->ce;
3168    }
3169    if (retval) {
3170        fcc->initialized = 1;
3171    }
3172    return retval;
3173}
3174/* }}} */
3175
3176ZEND_API zend_bool zend_is_callable_ex(zval *callable, zend_object *object, uint check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
3177{
3178    zend_bool ret;
3179    zend_fcall_info_cache fcc_local;
3180
3181    if (callable_name) {
3182        *callable_name = NULL;
3183    }
3184    if (fcc == NULL) {
3185        fcc = &fcc_local;
3186    }
3187    if (error) {
3188        *error = NULL;
3189    }
3190
3191    fcc->initialized = 0;
3192    fcc->calling_scope = NULL;
3193    fcc->called_scope = NULL;
3194    fcc->function_handler = NULL;
3195    fcc->calling_scope = NULL;
3196    fcc->object = NULL;
3197
3198    if (object &&
3199        (!EG(objects_store).object_buckets ||
3200         !IS_OBJ_VALID(EG(objects_store).object_buckets[object->handle]))) {
3201        return 0;
3202    }
3203
3204again:
3205    switch (Z_TYPE_P(callable)) {
3206        case IS_STRING:
3207            if (object) {
3208                fcc->object = object;
3209                fcc->calling_scope = object->ce;
3210                if (callable_name) {
3211                    char *ptr;
3212
3213                    *callable_name = zend_string_alloc(fcc->calling_scope->name->len + Z_STRLEN_P(callable) + sizeof("::") - 1, 0);
3214                    ptr = (*callable_name)->val;
3215                    memcpy(ptr, fcc->calling_scope->name->val, fcc->calling_scope->name->len);
3216                    ptr += fcc->calling_scope->name->len;
3217                    memcpy(ptr, "::", sizeof("::") - 1);
3218                    ptr += sizeof("::") - 1;
3219                    memcpy(ptr, Z_STRVAL_P(callable), Z_STRLEN_P(callable) + 1);
3220                }
3221            } else if (callable_name) {
3222                *callable_name = zend_string_copy(Z_STR_P(callable));
3223            }
3224            if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3225                fcc->called_scope = fcc->calling_scope;
3226                return 1;
3227            }
3228
3229            ret = zend_is_callable_check_func(check_flags, callable, fcc, 0, error);
3230            if (fcc == &fcc_local &&
3231                fcc->function_handler &&
3232                ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
3233                  (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3234                 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3235                 fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3236                if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3237                    zend_string_release(fcc->function_handler->common.function_name);
3238                }
3239                efree(fcc->function_handler);
3240            }
3241            return ret;
3242
3243        case IS_ARRAY:
3244            {
3245                zval *method = NULL;
3246                zval *obj = NULL;
3247                int strict_class = 0;
3248
3249                if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
3250                    obj = zend_hash_index_find(Z_ARRVAL_P(callable), 0);
3251                    method = zend_hash_index_find(Z_ARRVAL_P(callable), 1);
3252                }
3253
3254                do {
3255                    if (obj == NULL || method == NULL) {
3256                        break;
3257                    }
3258
3259                    ZVAL_DEREF(method);
3260                    if (Z_TYPE_P(method) != IS_STRING) {
3261                        break;
3262                    }
3263
3264                    ZVAL_DEREF(obj);
3265                    if (Z_TYPE_P(obj) == IS_STRING) {
3266                        if (callable_name) {
3267                            char *ptr;
3268
3269
3270                            *callable_name = zend_string_alloc(Z_STRLEN_P(obj) + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
3271                            ptr = (*callable_name)->val;
3272                            memcpy(ptr, Z_STRVAL_P(obj), Z_STRLEN_P(obj));
3273                            ptr += Z_STRLEN_P(obj);
3274                            memcpy(ptr, "::", sizeof("::") - 1);
3275                            ptr += sizeof("::") - 1;
3276                            memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
3277                        }
3278
3279                        if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3280                            return 1;
3281                        }
3282
3283                        if (!zend_is_callable_check_class(Z_STR_P(obj), fcc, &strict_class, error)) {
3284                            return 0;
3285                        }
3286
3287                    } else if (Z_TYPE_P(obj) == IS_OBJECT) {
3288                        if (!EG(objects_store).object_buckets ||
3289                            !IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(obj)])) {
3290                            return 0;
3291                        }
3292
3293                        fcc->calling_scope = Z_OBJCE_P(obj); /* TBFixed: what if it's overloaded? */
3294
3295                        fcc->object = Z_OBJ_P(obj);
3296
3297                        if (callable_name) {
3298                            char *ptr;
3299
3300                            *callable_name = zend_string_alloc(fcc->calling_scope->name->len + Z_STRLEN_P(method) + sizeof("::") - 1, 0);
3301                            ptr = (*callable_name)->val;
3302                            memcpy(ptr, fcc->calling_scope->name->val, fcc->calling_scope->name->len);
3303                            ptr += fcc->calling_scope->name->len;
3304                            memcpy(ptr, "::", sizeof("::") - 1);
3305                            ptr += sizeof("::") - 1;
3306                            memcpy(ptr, Z_STRVAL_P(method), Z_STRLEN_P(method) + 1);
3307                        }
3308
3309                        if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
3310                            fcc->called_scope = fcc->calling_scope;
3311                            return 1;
3312                        }
3313                    } else {
3314                        break;
3315                    }
3316
3317                    ret = zend_is_callable_check_func(check_flags, method, fcc, strict_class, error);
3318                    if (fcc == &fcc_local &&
3319                        fcc->function_handler &&
3320                        ((fcc->function_handler->type == ZEND_INTERNAL_FUNCTION &&
3321                          (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3322                         fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3323                         fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3324                        if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3325                            zend_string_release(fcc->function_handler->common.function_name);
3326                        }
3327                        efree(fcc->function_handler);
3328                    }
3329                    return ret;
3330
3331                } while (0);
3332                if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
3333                    if (!obj || (!Z_ISREF_P(obj)?
3334                                (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) :
3335                                (Z_TYPE_P(Z_REFVAL_P(obj)) != IS_STRING && Z_TYPE_P(Z_REFVAL_P(obj)) != IS_OBJECT))) {
3336                        if (error) zend_spprintf(error, 0, "first array member is not a valid class name or object");
3337                    } else {
3338                        if (error) zend_spprintf(error, 0, "second array member is not a valid method");
3339                    }
3340                } else {
3341                    if (error) zend_spprintf(error, 0, "array must have exactly two members");
3342                }
3343                if (callable_name) {
3344                    *callable_name = zend_string_init("Array", sizeof("Array")-1, 0);
3345                }
3346            }
3347            return 0;
3348        case IS_OBJECT:
3349            if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(callable, &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) {
3350                fcc->called_scope = fcc->calling_scope;
3351                if (callable_name) {
3352                    zend_class_entry *ce = Z_OBJCE_P(callable); /* TBFixed: what if it's overloaded? */
3353
3354                    *callable_name = zend_string_alloc(ce->name->len + sizeof("::__invoke") - 1, 0);
3355                    memcpy((*callable_name)->val, ce->name->val, ce->name->len);
3356                    memcpy((*callable_name)->val + ce->name->len, "::__invoke", sizeof("::__invoke"));
3357                }
3358                return 1;
3359            }
3360            if (callable_name) {
3361                *callable_name = zval_get_string(callable);
3362            }
3363            if (error) zend_spprintf(error, 0, "no array or string given");
3364            return 0;
3365        case IS_REFERENCE:
3366            callable = Z_REFVAL_P(callable);
3367            goto again;
3368        default:
3369            if (callable_name) {
3370                *callable_name = zval_get_string(callable);
3371            }
3372            if (error) zend_spprintf(error, 0, "no array or string given");
3373            return 0;
3374    }
3375}
3376/* }}} */
3377
3378ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, zend_string **callable_name) /* {{{ */
3379{
3380    return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL);
3381}
3382/* }}} */
3383
3384ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_name) /* {{{ */
3385{
3386    zend_fcall_info_cache fcc;
3387
3388    if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_STRICT, callable_name, &fcc, NULL)) {
3389        if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
3390            zval_dtor(callable);
3391            array_init(callable);
3392            add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
3393            add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
3394        }
3395        if (fcc.function_handler &&
3396            ((fcc.function_handler->type == ZEND_INTERNAL_FUNCTION &&
3397              (fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER)) ||
3398             fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
3399             fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
3400            if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
3401                zend_string_release(fcc.function_handler->common.function_name);
3402            }
3403            efree(fcc.function_handler);
3404        }
3405        return 1;
3406    }
3407    return 0;
3408}
3409/* }}} */
3410
3411ZEND_API int zend_fcall_info_init(zval *callable, uint check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */
3412{
3413    if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) {
3414        return FAILURE;
3415    }
3416
3417    fci->size = sizeof(*fci);
3418    fci->function_table = fcc->calling_scope ? &fcc->calling_scope->function_table : EG(function_table);
3419    fci->object = fcc->object;
3420    ZVAL_COPY_VALUE(&fci->function_name, callable);
3421    fci->retval = NULL;
3422    fci->param_count = 0;
3423    fci->params = NULL;
3424    fci->no_separation = 1;
3425    fci->symbol_table = NULL;
3426
3427    return SUCCESS;
3428}
3429/* }}} */
3430
3431ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, int free_mem) /* {{{ */
3432{
3433    if (fci->params) {
3434        uint32_t i;
3435
3436        for (i = 0; i < fci->param_count; i++) {
3437            zval_ptr_dtor(&fci->params[i]);
3438        }
3439        if (free_mem) {
3440            efree(fci->params);
3441            fci->params = NULL;
3442        }
3443    }
3444    fci->param_count = 0;
3445}
3446/* }}} */
3447
3448ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, int *param_count, zval **params) /* {{{ */
3449{
3450    *param_count = fci->param_count;
3451    *params = fci->params;
3452    fci->param_count = 0;
3453    fci->params = NULL;
3454}
3455/* }}} */
3456
3457ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, int param_count, zval *params) /* {{{ */
3458{
3459    zend_fcall_info_args_clear(fci, 1);
3460    fci->param_count = param_count;
3461    fci->params = params;
3462}
3463/* }}} */
3464
3465ZEND_API int zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args) /* {{{ */
3466{
3467    zval *arg, *params;
3468    uint32_t n = 1;
3469
3470    zend_fcall_info_args_clear(fci, !args);
3471
3472    if (!args) {
3473        return SUCCESS;
3474    }
3475
3476    if (Z_TYPE_P(args) != IS_ARRAY) {
3477        return FAILURE;
3478    }
3479
3480    fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args));
3481    fci->params = params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3482
3483    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), arg) {
3484        if (func && !Z_ISREF_P(arg) && ARG_SHOULD_BE_SENT_BY_REF(func, n)) {
3485            ZVAL_NEW_REF(params, arg);
3486            if (Z_REFCOUNTED_P(arg)) {
3487                Z_ADDREF_P(arg);
3488            }
3489        } else {
3490            ZVAL_COPY(params, arg);
3491        }
3492        params++;
3493        n++;
3494    } ZEND_HASH_FOREACH_END();
3495
3496    return SUCCESS;
3497}
3498/* }}} */
3499
3500ZEND_API int zend_fcall_info_args(zend_fcall_info *fci, zval *args) /* {{{ */
3501{
3502    return zend_fcall_info_args_ex(fci, NULL, args);
3503}
3504/* }}} */
3505
3506ZEND_API int zend_fcall_info_argp(zend_fcall_info *fci, int argc, zval *argv) /* {{{ */
3507{
3508    int i;
3509
3510    if (argc < 0) {
3511        return FAILURE;
3512    }
3513
3514    zend_fcall_info_args_clear(fci, !argc);
3515
3516    if (argc) {
3517        fci->param_count = argc;
3518        fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3519
3520        for (i = 0; i < argc; ++i) {
3521            ZVAL_COPY(&fci->params[i], &argv[i]);
3522        }
3523    }
3524
3525    return SUCCESS;
3526}
3527/* }}} */
3528
3529ZEND_API int zend_fcall_info_argv(zend_fcall_info *fci, int argc, va_list *argv) /* {{{ */
3530{
3531    int i;
3532    zval *arg;
3533
3534    if (argc < 0) {
3535        return FAILURE;
3536    }
3537
3538    zend_fcall_info_args_clear(fci, !argc);
3539
3540    if (argc) {
3541        fci->param_count = argc;
3542        fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
3543
3544        for (i = 0; i < argc; ++i) {
3545            arg = va_arg(*argv, zval *);
3546            ZVAL_COPY(&fci->params[i], arg);
3547        }
3548    }
3549
3550    return SUCCESS;
3551}
3552/* }}} */
3553
3554ZEND_API int zend_fcall_info_argn(zend_fcall_info *fci, int argc, ...) /* {{{ */
3555{
3556    int ret;
3557    va_list argv;
3558
3559    va_start(argv, argc);
3560    ret = zend_fcall_info_argv(fci, argc, &argv);
3561    va_end(argv);
3562
3563    return ret;
3564}
3565/* }}} */
3566
3567ZEND_API int zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval_ptr, zval *args) /* {{{ */
3568{
3569    zval retval, *org_params = NULL;
3570    int result, org_count = 0;
3571
3572    fci->retval = retval_ptr ? retval_ptr : &retval;
3573    if (args) {
3574        zend_fcall_info_args_save(fci, &org_count, &org_params);
3575        zend_fcall_info_args(fci, args);
3576    }
3577    result = zend_call_function(fci, fcc);
3578
3579    if (!retval_ptr && Z_TYPE(retval) != IS_UNDEF) {
3580        zval_ptr_dtor(&retval);
3581    }
3582    if (args) {
3583        zend_fcall_info_args_restore(fci, org_count, org_params);
3584    }
3585    return result;
3586}
3587/* }}} */
3588
3589ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */
3590{
3591    zend_string *lname;
3592    size_t name_len = strlen(module_name);
3593    zend_module_entry *module;
3594
3595    lname = zend_string_alloc(name_len, 0);
3596    zend_str_tolower_copy(lname->val, module_name, name_len);
3597    module = zend_hash_find_ptr(&module_registry, lname);
3598    zend_string_free(lname);
3599    return module ? module->version : NULL;
3600}
3601/* }}} */
3602
3603ZEND_API int zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */
3604{
3605    zend_property_info *property_info, *property_info_ptr;
3606
3607    if (ce->type == ZEND_INTERNAL_CLASS) {
3608        property_info = pemalloc(sizeof(zend_property_info), 1);
3609    } else {
3610        property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3611    }
3612
3613    if (Z_CONSTANT_P(property)) {
3614        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
3615    }
3616    if (!(access_type & ZEND_ACC_PPP_MASK)) {
3617        access_type |= ZEND_ACC_PUBLIC;
3618    }
3619    if (access_type & ZEND_ACC_STATIC) {
3620        if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
3621            (property_info_ptr->flags & ZEND_ACC_STATIC) != 0) {
3622            property_info->offset = property_info_ptr->offset;
3623            zval_ptr_dtor(&ce->default_static_members_table[property_info->offset]);
3624            zend_hash_del(&ce->properties_info, name);
3625        } else {
3626            property_info->offset = ce->default_static_members_count++;
3627            ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
3628        }
3629        ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
3630        if (ce->type == ZEND_USER_CLASS) {
3631            ce->static_members_table = ce->default_static_members_table;
3632        }
3633    } else {
3634        if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
3635            (property_info_ptr->flags & ZEND_ACC_STATIC) == 0) {
3636            property_info->offset = property_info_ptr->offset;
3637            zval_ptr_dtor(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]);
3638            zend_hash_del(&ce->properties_info, name);
3639        } else {
3640            property_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
3641            ce->default_properties_count++;
3642            ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
3643        }
3644        ZVAL_COPY_VALUE(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)], property);
3645    }
3646    if (ce->type & ZEND_INTERNAL_CLASS) {
3647        switch(Z_TYPE_P(property)) {
3648            case IS_ARRAY:
3649            case IS_OBJECT:
3650            case IS_RESOURCE:
3651                zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
3652                break;
3653            default:
3654                break;
3655        }
3656    }
3657    switch (access_type & ZEND_ACC_PPP_MASK) {
3658        case ZEND_ACC_PRIVATE: {
3659                property_info->name = zend_mangle_property_name(ce->name->val, ce->name->len, name->val, name->len, ce->type & ZEND_INTERNAL_CLASS);
3660            }
3661            break;
3662        case ZEND_ACC_PROTECTED: {
3663                property_info->name = zend_mangle_property_name("*", 1, name->val, name->len, ce->type & ZEND_INTERNAL_CLASS);
3664            }
3665            break;
3666        case ZEND_ACC_PUBLIC:
3667            property_info->name = zend_string_copy(name);
3668            break;
3669    }
3670
3671    property_info->name = zend_new_interned_string(property_info->name);
3672    property_info->flags = access_type;
3673    property_info->doc_comment = doc_comment;
3674    property_info->ce = ce;
3675    zend_hash_update_ptr(&ce->properties_info, name, property_info);
3676
3677    return SUCCESS;
3678}
3679/* }}} */
3680
3681ZEND_API int zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */
3682{
3683    zend_string *key = zend_string_init(name, name_length, ce->type & ZEND_INTERNAL_CLASS);
3684    int ret = zend_declare_property_ex(ce, key, property, access_type, NULL);
3685    zend_string_release(key);
3686    return ret;
3687}
3688/* }}} */
3689
3690ZEND_API int zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type) /* {{{ */
3691{
3692    zval property;
3693
3694    ZVAL_NULL(&property);
3695    return zend_declare_property(ce, name, name_length, &property, access_type);
3696}
3697/* }}} */
3698
3699ZEND_API int zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */
3700{
3701    zval property;
3702
3703    ZVAL_BOOL(&property, value);
3704    return zend_declare_property(ce, name, name_length, &property, access_type);
3705}
3706/* }}} */
3707
3708ZEND_API int zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */
3709{
3710    zval property;
3711
3712    ZVAL_LONG(&property, value);
3713    return zend_declare_property(ce, name, name_length, &property, access_type);
3714}
3715/* }}} */
3716
3717ZEND_API int zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type) /* {{{ */
3718{
3719    zval property;
3720
3721    ZVAL_DOUBLE(&property, value);
3722    return zend_declare_property(ce, name, name_length, &property, access_type);
3723}
3724/* }}} */
3725
3726ZEND_API int zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type) /* {{{ */
3727{
3728    zval property;
3729
3730    ZVAL_NEW_STR(&property, zend_string_init(value, strlen(value), ce->type & ZEND_INTERNAL_CLASS));
3731    return zend_declare_property(ce, name, name_length, &property, access_type);
3732}
3733/* }}} */
3734
3735ZEND_API int zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type) /* {{{ */
3736{
3737    zval property;
3738
3739    ZVAL_NEW_STR(&property, zend_string_init(value, value_len, ce->type & ZEND_INTERNAL_CLASS));
3740    return zend_declare_property(ce, name, name_length, &property, access_type);
3741}
3742/* }}} */
3743
3744ZEND_API int zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */
3745{
3746    if (Z_CONSTANT_P(value)) {
3747        ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
3748    }
3749    return zend_hash_str_update(&ce->constants_table, name, name_length, value) ?
3750        SUCCESS : FAILURE;
3751}
3752/* }}} */
3753
3754ZEND_API int zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length) /* {{{ */
3755{
3756    zval constant;
3757
3758    ZVAL_NULL(&constant);
3759    return zend_declare_class_constant(ce, name, name_length, &constant);
3760}
3761/* }}} */
3762
3763ZEND_API int zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value) /* {{{ */
3764{
3765    zval constant;
3766
3767    ZVAL_LONG(&constant, value);
3768    return zend_declare_class_constant(ce, name, name_length, &constant);
3769}
3770/* }}} */
3771
3772ZEND_API int zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_bool value) /* {{{ */
3773{
3774    zval constant;
3775
3776    ZVAL_BOOL(&constant, value);
3777    return zend_declare_class_constant(ce, name, name_length, &constant);
3778}
3779/* }}} */
3780
3781ZEND_API int zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value) /* {{{ */
3782{
3783    zval constant;
3784
3785    ZVAL_DOUBLE(&constant, value);
3786    return zend_declare_class_constant(ce, name, name_length, &constant);
3787}
3788/* }}} */
3789
3790ZEND_API int zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length) /* {{{ */
3791{
3792    zval constant;
3793
3794    ZVAL_NEW_STR(&constant, zend_string_init(value, value_length, ce->type & ZEND_INTERNAL_CLASS));
3795    return zend_declare_class_constant(ce, name, name_length, &constant);
3796}
3797/* }}} */
3798
3799ZEND_API int zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value) /* {{{ */
3800{
3801    return zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value));
3802}
3803/* }}} */
3804
3805ZEND_API void zend_update_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zval *value) /* {{{ */
3806{
3807    zval property;
3808    zend_class_entry *old_scope = EG(scope);
3809
3810    EG(scope) = scope;
3811
3812    if (!Z_OBJ_HT_P(object)->write_property) {
3813        zend_error(E_CORE_ERROR, "Property %s of class %s cannot be updated", name, Z_OBJCE_P(object)->name->val);
3814    }
3815    ZVAL_STRINGL(&property, name, name_length);
3816    Z_OBJ_HT_P(object)->write_property(object, &property, value, NULL);
3817    zval_ptr_dtor(&property);
3818
3819    EG(scope) = old_scope;
3820}
3821/* }}} */
3822
3823ZEND_API void zend_update_property_null(zend_class_entry *scope, zval *object, const char *name, size_t name_length) /* {{{ */
3824{
3825    zval tmp;
3826
3827    ZVAL_NULL(&tmp);
3828    zend_update_property(scope, object, name, name_length, &tmp);
3829}
3830/* }}} */
3831
3832ZEND_API void zend_update_property_bool(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value) /* {{{ */
3833{
3834    zval tmp;
3835
3836    ZVAL_BOOL(&tmp, value);
3837    zend_update_property(scope, object, name, name_length, &tmp);
3838}
3839/* }}} */
3840
3841ZEND_API void zend_update_property_long(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_long value) /* {{{ */
3842{
3843    zval tmp;
3844
3845    ZVAL_LONG(&tmp, value);
3846    zend_update_property(scope, object, name, name_length, &tmp);
3847}
3848/* }}} */
3849
3850ZEND_API void zend_update_property_double(zend_class_entry *scope, zval *object, const char *name, size_t name_length, double value) /* {{{ */
3851{
3852    zval tmp;
3853
3854    ZVAL_DOUBLE(&tmp, value);
3855    zend_update_property(scope, object, name, name_length, &tmp);
3856}
3857/* }}} */
3858
3859ZEND_API void zend_update_property_str(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_string *value) /* {{{ */
3860{
3861    zval tmp;
3862
3863    ZVAL_STR(&tmp, value);
3864    zend_update_property(scope, object, name, name_length, &tmp);
3865}
3866/* }}} */
3867
3868ZEND_API void zend_update_property_string(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value) /* {{{ */
3869{
3870    zval tmp;
3871
3872    ZVAL_STRING(&tmp, value);
3873    Z_SET_REFCOUNT(tmp, 0);
3874    zend_update_property(scope, object, name, name_length, &tmp);
3875}
3876/* }}} */
3877
3878ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zval *object, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */
3879{
3880    zval tmp;
3881
3882    ZVAL_STRINGL(&tmp, value, value_len);
3883    Z_SET_REFCOUNT(tmp, 0);
3884    zend_update_property(scope, object, name, name_length, &tmp);
3885}
3886/* }}} */
3887
3888ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value) /* {{{ */
3889{
3890    zval *property;
3891    zend_class_entry *old_scope = EG(scope);
3892    zend_string *key = zend_string_init(name, name_length, 0);
3893
3894    EG(scope) = scope;
3895    property = zend_std_get_static_property(scope, key, 0);
3896    EG(scope) = old_scope;
3897    zend_string_free(key);
3898    if (!property) {
3899        return FAILURE;
3900    } else {
3901        if (property != value) {
3902            if (Z_ISREF_P(property)) {
3903                zval_dtor(property);
3904                ZVAL_COPY_VALUE(property, value);
3905                if (Z_REFCOUNT_P(value) > 0) {
3906                    zval_opt_copy_ctor(property);
3907                }
3908            } else {
3909                zval garbage;
3910
3911                ZVAL_COPY_VALUE(&garbage, property);
3912                if (Z_REFCOUNTED_P(value)) {
3913                    Z_ADDREF_P(value);
3914                    if (Z_ISREF_P(value)) {
3915                        SEPARATE_ZVAL(value);
3916                    }
3917                }
3918                ZVAL_COPY_VALUE(property, value);
3919                zval_ptr_dtor(&garbage);
3920            }
3921        }
3922        return SUCCESS;
3923    }
3924}
3925/* }}} */
3926
3927ZEND_API int zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length) /* {{{ */
3928{
3929    zval tmp;
3930
3931    ZVAL_NULL(&tmp);
3932    return zend_update_static_property(scope, name, name_length, &tmp);
3933}
3934/* }}} */
3935
3936ZEND_API int zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */
3937{
3938    zval tmp;
3939
3940    ZVAL_BOOL(&tmp, value);
3941    return zend_update_static_property(scope, name, name_length, &tmp);
3942}
3943/* }}} */
3944
3945ZEND_API int zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */
3946{
3947    zval tmp;
3948
3949    ZVAL_LONG(&tmp, value);
3950    return zend_update_static_property(scope, name, name_length, &tmp);
3951}
3952/* }}} */
3953
3954ZEND_API int zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value) /* {{{ */
3955{
3956    zval tmp;
3957
3958    ZVAL_DOUBLE(&tmp, value);
3959    return zend_update_static_property(scope, name, name_length, &tmp);
3960}
3961/* }}} */
3962
3963ZEND_API int zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value) /* {{{ */
3964{
3965    zval tmp;
3966
3967    ZVAL_STRING(&tmp, value);
3968    Z_SET_REFCOUNT(tmp, 0);
3969    return zend_update_static_property(scope, name, name_length, &tmp);
3970}
3971/* }}} */
3972
3973ZEND_API int zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */
3974{
3975    zval tmp;
3976
3977    ZVAL_STRINGL(&tmp, value, value_len);
3978    Z_SET_REFCOUNT(tmp, 0);
3979    return zend_update_static_property(scope, name, name_length, &tmp);
3980}
3981/* }}} */
3982
3983ZEND_API zval *zend_read_property(zend_class_entry *scope, zval *object, const char *name, size_t name_length, zend_bool silent, zval *rv) /* {{{ */
3984{
3985    zval property, *value;
3986    zend_class_entry *old_scope = EG(scope);
3987
3988    EG(scope) = scope;
3989
3990    if (!Z_OBJ_HT_P(object)->read_property) {
3991        zend_error(E_CORE_ERROR, "Property %s of class %s cannot be read", name, Z_OBJCE_P(object)->name->val);
3992    }
3993
3994    ZVAL_STRINGL(&property, name, name_length);
3995    value = Z_OBJ_HT_P(object)->read_property(object, &property, silent?BP_VAR_IS:BP_VAR_R, NULL, rv);
3996    zval_ptr_dtor(&property);
3997
3998    EG(scope) = old_scope;
3999    return value;
4000}
4001/* }}} */
4002
4003ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, zend_bool silent) /* {{{ */
4004{
4005    zval *property;
4006    zend_class_entry *old_scope = EG(scope);
4007    zend_string *key = zend_string_init(name, name_length, 0);
4008
4009    EG(scope) = scope;
4010    property = zend_std_get_static_property(scope, key, silent);
4011    EG(scope) = old_scope;
4012    zend_string_free(key);
4013
4014    return property;
4015}
4016/* }}} */
4017
4018ZEND_API void zend_save_error_handling(zend_error_handling *current) /* {{{ */
4019{
4020    current->handling = EG(error_handling);
4021    current->exception = EG(exception_class);
4022    ZVAL_COPY(&current->user_handler, &EG(user_error_handler));
4023}
4024/* }}} */
4025
4026ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current) /* {{{ */
4027{
4028    if (current) {
4029        zend_save_error_handling(current);
4030        if (error_handling != EH_NORMAL && Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
4031            zval_ptr_dtor(&EG(user_error_handler));
4032            ZVAL_UNDEF(&EG(user_error_handler));
4033        }
4034    }
4035    EG(error_handling) = error_handling;
4036    EG(exception_class) = error_handling == EH_THROW ? exception_class : NULL;
4037}
4038/* }}} */
4039
4040static int same_zval(zval *zv1, zval *zv2)  /* {{{ */
4041{
4042    if (Z_TYPE_P(zv1) != Z_TYPE_P(zv2)) {
4043        return 0;
4044    }
4045    switch (Z_TYPE_P(zv1)) {
4046        case IS_UNDEF:
4047        case IS_NULL:
4048        case IS_FALSE:
4049        case IS_TRUE:
4050            return 1;
4051        case IS_LONG:
4052            return Z_LVAL_P(zv1) == Z_LVAL_P(zv2);
4053        case IS_DOUBLE:
4054            return Z_LVAL_P(zv1) == Z_LVAL_P(zv2);
4055        case IS_STRING:
4056        case IS_ARRAY:
4057        case IS_OBJECT:
4058        case IS_RESOURCE:
4059            return Z_COUNTED_P(zv1) == Z_COUNTED_P(zv2);
4060        default:
4061            return 0;
4062    }
4063}
4064/* }}} */
4065
4066ZEND_API void zend_restore_error_handling(zend_error_handling *saved) /* {{{ */
4067{
4068    EG(error_handling) = saved->handling;
4069    EG(exception_class) = saved->handling == EH_THROW ? saved->exception : NULL;
4070    if (Z_TYPE(saved->user_handler) != IS_UNDEF
4071        && !same_zval(&saved->user_handler, &EG(user_error_handler))) {
4072        zval_ptr_dtor(&EG(user_error_handler));
4073        ZVAL_COPY_VALUE(&EG(user_error_handler), &saved->user_handler);
4074    } else if (Z_TYPE(saved->user_handler)) {
4075        zval_ptr_dtor(&saved->user_handler);
4076    }
4077    ZVAL_UNDEF(&saved->user_handler);
4078}
4079/* }}} */
4080
4081ZEND_API zend_string* zend_find_alias_name(zend_class_entry *ce, zend_string *name) /* {{{ */
4082{
4083    zend_trait_alias *alias, **alias_ptr;
4084
4085    if ((alias_ptr = ce->trait_aliases)) {
4086        alias = *alias_ptr;
4087        while (alias) {
4088            if (alias->alias->len == name->len &&
4089                !strncasecmp(name->val, alias->alias->val, alias->alias->len)) {
4090                return alias->alias;
4091            }
4092            alias_ptr++;
4093            alias = *alias_ptr;
4094        }
4095    }
4096
4097    return name;
4098}
4099/* }}} */
4100
4101ZEND_API zend_string *zend_resolve_method_name(zend_class_entry *ce, zend_function *f) /* {{{ */
4102{
4103    zend_function *func;
4104    HashTable *function_table;
4105    zend_string *name;
4106
4107    if (f->common.type != ZEND_USER_FUNCTION ||
4108        (f->op_array.refcount && *(f->op_array.refcount) < 2) ||
4109        !f->common.scope ||
4110        !f->common.scope->trait_aliases) {
4111        return f->common.function_name;
4112    }
4113
4114    function_table = &ce->function_table;
4115    ZEND_HASH_FOREACH_STR_KEY_PTR(function_table, name, func) {
4116        if (func == f) {
4117            if (!name) {
4118                return f->common.function_name;
4119            }
4120            if (name->len == f->common.function_name->len &&
4121                !strncasecmp(name->val, f->common.function_name->val, f->common.function_name->len)) {
4122                return f->common.function_name;
4123            }
4124            return zend_find_alias_name(f->common.scope, name);
4125        }
4126    } ZEND_HASH_FOREACH_END();
4127    return f->common.function_name;
4128}
4129/* }}} */
4130
4131ZEND_API void zend_ctor_make_null(zend_execute_data *execute_data) /* {{{ */
4132{
4133    if (EX(return_value)) {
4134        Z_OBJ_P(EX(return_value)) = NULL;
4135        ZVAL_NULL(EX(return_value));
4136    }
4137}
4138/* }}} */
4139
4140ZEND_API const char *zend_get_object_type(const zend_class_entry *ce) /* {{{ */
4141{
4142    if(ce->ce_flags & ZEND_ACC_TRAIT) {
4143        return "trait";
4144    } else if (ce->ce_flags & ZEND_ACC_INTERFACE) {
4145        return "interface";
4146    } else {
4147        return "class";
4148    }
4149}
4150/* }}} */
4151
4152/*
4153 * Local variables:
4154 * tab-width: 4
4155 * c-basic-offset: 4
4156 * indent-tabs-mode: t
4157 * End:
4158 */
4159