1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine                                                          |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.00 of the Zend license,     |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.zend.com/license/2_00.txt.                                |
11   | If you did not receive a copy of the Zend license and are unable to  |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@zend.com so we can mail you a copy immediately.              |
14   +----------------------------------------------------------------------+
15   | Authors: Andi Gutmans <andi@zend.com>                                |
16   |          Zeev Suraski <zeev@zend.com>                                |
17   +----------------------------------------------------------------------+
18*/
19
20/* $Id$ */
21
22#define ZEND_INTENSIVE_DEBUGGING 0
23
24#include <stdio.h>
25#include <signal.h>
26
27#include "zend.h"
28#include "zend_compile.h"
29#include "zend_execute.h"
30#include "zend_API.h"
31#include "zend_ptr_stack.h"
32#include "zend_constants.h"
33#include "zend_extensions.h"
34#include "zend_ini.h"
35#include "zend_exceptions.h"
36#include "zend_interfaces.h"
37#include "zend_closures.h"
38#include "zend_vm.h"
39
40/* Virtual current working directory support */
41#include "tsrm_virtual_cwd.h"
42
43#define _CONST_CODE  0
44#define _TMP_CODE    1
45#define _VAR_CODE    2
46#define _UNUSED_CODE 3
47#define _CV_CODE     4
48
49typedef int (*incdec_t)(zval *);
50
51#define get_zval_ptr(node, Ts, should_free, type) _get_zval_ptr(node, Ts, should_free, type TSRMLS_CC)
52#define get_zval_ptr_ptr(node, Ts, should_free, type) _get_zval_ptr_ptr(node, Ts, should_free, type TSRMLS_CC)
53#define get_obj_zval_ptr(node, Ts, should_free, type) _get_obj_zval_ptr(node, Ts, should_free, type TSRMLS_CC)
54#define get_obj_zval_ptr_ptr(node, Ts, should_free, type) _get_obj_zval_ptr_ptr(node, Ts, should_free, type TSRMLS_CC)
55
56/* Prototypes */
57static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
58static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
59static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
60
61#define RETURN_VALUE_USED(opline) (!((opline)->result.u.EA.type & EXT_TYPE_UNUSED))
62
63#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
64#define T(offset) (*(temp_variable *)((char *) Ts + offset))
65
66#define TEMP_VAR_STACK_LIMIT 2000
67
68static zend_always_inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC)
69{
70    if (!Z_DELREF_P(z)) {
71        Z_SET_REFCOUNT_P(z, 1);
72        Z_UNSET_ISREF_P(z);
73        should_free->var = z;
74/*      should_free->is_var = 1; */
75    } else {
76        should_free->var = 0;
77        if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
78            Z_UNSET_ISREF_P(z);
79        }
80        GC_ZVAL_CHECK_POSSIBLE_ROOT(z);
81    }
82}
83
84static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
85{
86    if (!Z_DELREF_P(z)) {
87        if (z != &EG(uninitialized_zval)) {
88            GC_REMOVE_ZVAL_FROM_BUFFER(z);
89            zval_dtor(z);
90            efree(z);
91        }
92    }
93}
94
95#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
96#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
97#define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC)
98#define PZVAL_LOCK(z) Z_ADDREF_P((z))
99#define RETURN_VALUE_UNUSED(pzn)    (((pzn)->u.EA.type & EXT_TYPE_UNUSED))
100#define SELECTIVE_PZVAL_LOCK(pzv, pzn)  if (!RETURN_VALUE_UNUSED(pzn)) { PZVAL_LOCK(pzv); }
101
102#define AI_USE_PTR(ai) \
103    if ((ai).ptr_ptr) { \
104        (ai).ptr = *((ai).ptr_ptr); \
105        (ai).ptr_ptr = &((ai).ptr); \
106    } else { \
107        (ai).ptr = NULL; \
108    }
109
110#define AI_SET_PTR(ai, val)     \
111    (ai).ptr = (val);           \
112    (ai).ptr_ptr = &((ai).ptr);
113
114#define FREE_OP(should_free) \
115    if (should_free.var) { \
116        if ((zend_uintptr_t)should_free.var & 1L) { \
117            zval_dtor((zval*)((zend_uintptr_t)should_free.var & ~1L)); \
118        } else { \
119            zval_ptr_dtor(&should_free.var); \
120        } \
121    }
122
123#define FREE_OP_IF_VAR(should_free) \
124    if (should_free.var != NULL && (((zend_uintptr_t)should_free.var & 1L) == 0)) { \
125        zval_ptr_dtor(&should_free.var); \
126    }
127
128#define FREE_OP_VAR_PTR(should_free) \
129    if (should_free.var) { \
130        zval_ptr_dtor(&should_free.var); \
131    }
132
133#define TMP_FREE(z) (zval*)(((zend_uintptr_t)(z)) | 1L)
134
135#define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
136
137#define INIT_PZVAL_COPY(z,v) \
138    (z)->value = (v)->value; \
139    Z_TYPE_P(z) = Z_TYPE_P(v); \
140    Z_SET_REFCOUNT_P(z, 1); \
141    Z_UNSET_ISREF_P(z);
142
143#define MAKE_REAL_ZVAL_PTR(val) \
144    do { \
145        zval *_tmp; \
146        ALLOC_ZVAL(_tmp); \
147        _tmp->value = (val)->value; \
148        Z_TYPE_P(_tmp) = Z_TYPE_P(val); \
149        Z_SET_REFCOUNT_P(_tmp, 1); \
150        Z_UNSET_ISREF_P(_tmp); \
151        val = _tmp; \
152    } while (0)
153
154/* End of zend_execute_locks.h */
155
156#define CV_OF(i)     (EG(current_execute_data)->CVs[i])
157#define CV_DEF_OF(i) (EG(active_op_array)->vars[i])
158
159#define CTOR_CALL_BIT    0x1
160#define CTOR_USED_BIT    0x2
161
162#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
163#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
164
165#define ENCODE_CTOR(ce, used) \
166    ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
167#define DECODE_CTOR(ce) \
168    ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
169
170ZEND_API zval** zend_get_compiled_variable_value(const zend_execute_data *execute_data_ptr, zend_uint var)
171{
172    return execute_data_ptr->CVs[var];
173}
174
175static zend_always_inline zval *_get_zval_ptr_tmp(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC)
176{
177    return should_free->var = &T(node->u.var).tmp_var;
178}
179
180static zval *_get_zval_ptr_var_string_offset(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC)
181{
182    temp_variable *T = &T(node->u.var);
183    zval *str = T->str_offset.str;
184    zval *ptr;
185
186    /* string offset */
187    ALLOC_ZVAL(ptr);
188    T->str_offset.ptr = ptr;
189    should_free->var = ptr;
190
191    if (T->str_offset.str->type != IS_STRING
192        || ((int)T->str_offset.offset < 0)
193        || (T->str_offset.str->value.str.len <= (int)T->str_offset.offset)) {
194        ptr->value.str.val = STR_EMPTY_ALLOC();
195        ptr->value.str.len = 0;
196    } else {
197        ptr->value.str.val = estrndup(str->value.str.val + T->str_offset.offset, 1);
198        ptr->value.str.len = 1;
199    }
200    PZVAL_UNLOCK_FREE(str);
201    Z_SET_REFCOUNT_P(ptr, 1);
202    Z_SET_ISREF_P(ptr);
203    ptr->type = IS_STRING;
204    return ptr;
205}
206
207static zend_always_inline zval *_get_zval_ptr_var(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC)
208{
209    zval *ptr = T(node->u.var).var.ptr;
210    if (EXPECTED(ptr != NULL)) {
211        PZVAL_UNLOCK(ptr, should_free);
212        return ptr;
213    } else {
214        return _get_zval_ptr_var_string_offset(node, Ts, should_free TSRMLS_CC);
215    }
216}
217
218static zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC)
219{
220    zend_compiled_variable *cv = &CV_DEF_OF(var);
221
222    if (!EG(active_symbol_table) ||
223        zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
224        switch (type) {
225            case BP_VAR_R:
226            case BP_VAR_UNSET:
227                zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
228                /* break missing intentionally */
229            case BP_VAR_IS:
230                return &EG(uninitialized_zval_ptr);
231                break;
232            case BP_VAR_RW:
233                zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
234                /* break missing intentionally */
235            case BP_VAR_W:
236                Z_ADDREF(EG(uninitialized_zval));
237                if (!EG(active_symbol_table)) {
238                    *ptr = (zval**)EG(current_execute_data)->CVs + (EG(active_op_array)->last_var + var);
239                    **ptr = &EG(uninitialized_zval);
240                } else {
241                    zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
242                }
243                break;
244        }
245    }
246    return *ptr;
247}
248
249static zend_always_inline zval *_get_zval_ptr_cv(const znode *node, const temp_variable *Ts, int type TSRMLS_DC)
250{
251    zval ***ptr = &CV_OF(node->u.var);
252
253    if (UNEXPECTED(*ptr == NULL)) {
254        return *_get_zval_cv_lookup(ptr, node->u.var, type TSRMLS_CC);
255    }
256    return **ptr;
257}
258
259static inline zval *_get_zval_ptr(znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
260{
261/*  should_free->is_var = 0; */
262    switch (node->op_type) {
263        case IS_CONST:
264            should_free->var = 0;
265            return &node->u.constant;
266            break;
267        case IS_TMP_VAR:
268            should_free->var = TMP_FREE(&T(node->u.var).tmp_var);
269            return &T(node->u.var).tmp_var;
270            break;
271        case IS_VAR:
272            return _get_zval_ptr_var(node, Ts, should_free TSRMLS_CC);
273            break;
274        case IS_UNUSED:
275            should_free->var = 0;
276            return NULL;
277            break;
278        case IS_CV:
279            should_free->var = 0;
280            return _get_zval_ptr_cv(node, Ts, type TSRMLS_CC);
281            break;
282        EMPTY_SWITCH_DEFAULT_CASE()
283    }
284    return NULL;
285}
286
287static zend_always_inline zval **_get_zval_ptr_ptr_var(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC)
288{
289    zval** ptr_ptr = T(node->u.var).var.ptr_ptr;
290
291    if (EXPECTED(ptr_ptr != NULL)) {
292        PZVAL_UNLOCK(*ptr_ptr, should_free);
293    } else {
294        /* string offset */
295        PZVAL_UNLOCK(T(node->u.var).str_offset.str, should_free);
296    }
297    return ptr_ptr;
298}
299
300static zend_always_inline zval **_get_zval_ptr_ptr_cv(const znode *node, const temp_variable *Ts, int type TSRMLS_DC)
301{
302    zval ***ptr = &CV_OF(node->u.var);
303
304    if (UNEXPECTED(*ptr == NULL)) {
305        return _get_zval_cv_lookup(ptr, node->u.var, type TSRMLS_CC);
306    }
307    return *ptr;
308}
309
310static inline zval **_get_zval_ptr_ptr(const znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
311{
312    if (node->op_type == IS_CV) {
313        should_free->var = 0;
314        return _get_zval_ptr_ptr_cv(node, Ts, type TSRMLS_CC);
315    } else if (node->op_type == IS_VAR) {
316        return _get_zval_ptr_ptr_var(node, Ts, should_free TSRMLS_CC);
317    } else {
318        should_free->var = 0;
319        return NULL;
320    }
321}
322
323static zend_always_inline zval *_get_obj_zval_ptr_unused(TSRMLS_D)
324{
325    if (EXPECTED(EG(This) != NULL)) {
326        return EG(This);
327    } else {
328        zend_error_noreturn(E_ERROR, "Using $this when not in object context");
329        return NULL;
330    }
331}
332
333static inline zval **_get_obj_zval_ptr_ptr(const znode *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
334{
335    if (op->op_type == IS_UNUSED) {
336        if (EXPECTED(EG(This) != NULL)) {
337            /* this should actually never be modified, _ptr_ptr is modified only when
338               the object is empty */
339            should_free->var = 0;
340            return &EG(This);
341        } else {
342            zend_error_noreturn(E_ERROR, "Using $this when not in object context");
343        }
344    }
345    return get_zval_ptr_ptr(op, Ts, should_free, type);
346}
347
348static zend_always_inline zval **_get_obj_zval_ptr_ptr_unused(TSRMLS_D)
349{
350    if (EXPECTED(EG(This) != NULL)) {
351        return &EG(This);
352    } else {
353        zend_error_noreturn(E_ERROR, "Using $this when not in object context");
354        return NULL;
355    }
356}
357
358static inline zval *_get_obj_zval_ptr(znode *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC)
359{
360    if (op->op_type == IS_UNUSED) {
361        if (EXPECTED(EG(This) != NULL)) {
362            should_free->var = 0;
363            return EG(This);
364        } else {
365            zend_error_noreturn(E_ERROR, "Using $this when not in object context");
366        }
367    }
368    return get_zval_ptr(op, Ts, should_free, type);
369}
370
371static inline void zend_switch_free(temp_variable *T, int extended_value TSRMLS_DC)
372{
373    if (T->var.ptr) {
374        if (extended_value & ZEND_FE_RESET_VARIABLE) { /* foreach() free */
375            Z_DELREF_P(T->var.ptr);
376        }
377        zval_ptr_dtor(&T->var.ptr);
378    } else if (!T->var.ptr_ptr) {
379        /* perform the equivalent of equivalent of a
380         * quick & silent get_zval_ptr, and FREE_OP
381         */
382        PZVAL_UNLOCK_FREE(T->str_offset.str);
383    }
384}
385
386static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)
387{
388    zval *variable_ptr = *variable_ptr_ptr;
389    zval *value_ptr = *value_ptr_ptr;
390
391    if (variable_ptr == EG(error_zval_ptr) || value_ptr==EG(error_zval_ptr)) {
392        variable_ptr_ptr = &EG(uninitialized_zval_ptr);
393    } else if (variable_ptr != value_ptr) {
394        if (!PZVAL_IS_REF(value_ptr)) {
395            /* break it away */
396            Z_DELREF_P(value_ptr);
397            if (Z_REFCOUNT_P(value_ptr)>0) {
398                ALLOC_ZVAL(*value_ptr_ptr);
399                **value_ptr_ptr = *value_ptr;
400                value_ptr = *value_ptr_ptr;
401                zendi_zval_copy_ctor(*value_ptr);
402            }
403            Z_SET_REFCOUNT_P(value_ptr, 1);
404            Z_SET_ISREF_P(value_ptr);
405        }
406
407        *variable_ptr_ptr = value_ptr;
408        Z_ADDREF_P(value_ptr);
409
410        zval_ptr_dtor(&variable_ptr);
411    } else if (!Z_ISREF_P(variable_ptr)) {
412        if (variable_ptr_ptr == value_ptr_ptr) {
413            SEPARATE_ZVAL(variable_ptr_ptr);
414        } else if (variable_ptr==EG(uninitialized_zval_ptr)
415            || Z_REFCOUNT_P(variable_ptr)>2) {
416            /* we need to separate */
417            Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2);
418            ALLOC_ZVAL(*variable_ptr_ptr);
419            **variable_ptr_ptr = *variable_ptr;
420            zval_copy_ctor(*variable_ptr_ptr);
421            *value_ptr_ptr = *variable_ptr_ptr;
422            Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2);
423        }
424        Z_SET_ISREF_PP(variable_ptr_ptr);
425    }
426}
427
428/* this should modify object only if it's empty */
429static inline void make_real_object(zval **object_ptr TSRMLS_DC)
430{
431    if (Z_TYPE_PP(object_ptr) == IS_NULL
432        || (Z_TYPE_PP(object_ptr) == IS_BOOL && Z_LVAL_PP(object_ptr) == 0)
433        || (Z_TYPE_PP(object_ptr) == IS_STRING && Z_STRLEN_PP(object_ptr) == 0)
434    ) {
435        SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
436        zval_dtor(*object_ptr);
437        object_init(*object_ptr);
438        zend_error(E_STRICT, "Creating default object from empty value");
439    }
440}
441
442static inline char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, const char **class_name, zend_class_entry **pce TSRMLS_DC)
443{
444    *pce = zend_fetch_class(cur_arg_info->class_name, cur_arg_info->class_name_len, (fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
445
446    *class_name = (*pce) ? (*pce)->name: cur_arg_info->class_name;
447    if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
448        return "implement interface ";
449    } else {
450        return "be an instance of ";
451    }
452}
453
454static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const zend_arg_info *cur_arg_info, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind TSRMLS_DC)
455{
456    zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
457    char *fname = zf->common.function_name;
458    char *fsep;
459    char *fclass;
460
461    if (zf->common.scope) {
462        fsep =  "::";
463        fclass = zf->common.scope->name;
464    } else {
465        fsep =  "";
466        fclass = "";
467    }
468
469    if (ptr && ptr->op_array) {
470        zend_error(E_RECOVERABLE_ERROR, "Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind, ptr->op_array->filename, ptr->opline->lineno);
471    } else {
472        zend_error(E_RECOVERABLE_ERROR, "Argument %d passed to %s%s%s() must %s%s, %s%s given", arg_num, fclass, fsep, fname, need_msg, need_kind, given_msg, given_kind);
473    }
474    return 0;
475}
476
477static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
478{
479    zend_arg_info *cur_arg_info;
480    char *need_msg;
481    zend_class_entry *ce;
482
483    if (!zf->common.arg_info
484        || arg_num>zf->common.num_args) {
485        return 1;
486    }
487
488    cur_arg_info = &zf->common.arg_info[arg_num-1];
489
490    if (cur_arg_info->class_name) {
491        const char *class_name;
492
493        if (!arg) {
494            need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
495            return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "none", "" TSRMLS_CC);
496        }
497        if (Z_TYPE_P(arg) == IS_OBJECT) {
498            need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
499            if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
500                return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
501            }
502        } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
503            need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
504            return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
505        }
506    } else if (cur_arg_info->array_type_hint) {
507        if (!arg) {
508            return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", "none", "" TSRMLS_CC);
509        }
510        if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
511            return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
512        }
513    }
514    return 1;
515}
516
517static inline void zend_assign_to_object(znode *result, zval **object_ptr, zval *property_name, znode *value_op, const temp_variable *Ts, int opcode TSRMLS_DC)
518
519{
520    zval *object = *object_ptr;
521    zend_free_op free_value;
522    zval *value = get_zval_ptr(value_op, Ts, &free_value, BP_VAR_R);
523    zval **retval = &T(result->u.var).var.ptr;
524
525    if (Z_TYPE_P(object) != IS_OBJECT) {
526        if (object == EG(error_zval_ptr)) {
527            if (!RETURN_VALUE_UNUSED(result)) {
528                *retval = EG(uninitialized_zval_ptr);
529                PZVAL_LOCK(*retval);
530            }
531            FREE_OP(free_value);
532            return;
533        }
534        if (Z_TYPE_P(object) == IS_NULL ||
535            (Z_TYPE_P(object) == IS_BOOL && Z_LVAL_P(object) == 0) ||
536            (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
537            SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
538            object = *object_ptr;
539            Z_ADDREF_P(object);
540            zend_error(E_STRICT, "Creating default object from empty value");
541            if (Z_REFCOUNT_P(object) == 1) {
542                /* object was removed by error handler, nothing to assign to */
543                zval_ptr_dtor(&object);
544                if (retval) {
545                    *retval = &EG(uninitialized_zval);
546                    PZVAL_LOCK(*retval);
547                }
548                FREE_OP(free_value);
549                return;
550            }
551            Z_DELREF_P(object);
552            zval_dtor(object);
553            object_init(object);
554        } else {
555            zend_error(E_WARNING, "Attempt to assign property of non-object");
556            if (!RETURN_VALUE_UNUSED(result)) {
557                *retval = EG(uninitialized_zval_ptr);
558                PZVAL_LOCK(*retval);
559            }
560            FREE_OP(free_value);
561            return;
562        }
563    }
564
565    /* separate our value if necessary */
566    if (value_op->op_type == IS_TMP_VAR) {
567        zval *orig_value = value;
568
569        ALLOC_ZVAL(value);
570        *value = *orig_value;
571        Z_UNSET_ISREF_P(value);
572        Z_SET_REFCOUNT_P(value, 0);
573    } else if (value_op->op_type == IS_CONST) {
574        zval *orig_value = value;
575
576        ALLOC_ZVAL(value);
577        *value = *orig_value;
578        Z_UNSET_ISREF_P(value);
579        Z_SET_REFCOUNT_P(value, 0);
580        zval_copy_ctor(value);
581    }
582
583
584    Z_ADDREF_P(value);
585    if (opcode == ZEND_ASSIGN_OBJ) {
586        if (!Z_OBJ_HT_P(object)->write_property) {
587            zend_error(E_WARNING, "Attempt to assign property of non-object");
588            if (!RETURN_VALUE_UNUSED(result)) {
589                *retval = EG(uninitialized_zval_ptr);
590                PZVAL_LOCK(*retval);
591            }
592            if (value_op->op_type == IS_TMP_VAR) {
593                FREE_ZVAL(value);
594            } else if (value_op->op_type == IS_CONST) {
595                zval_ptr_dtor(&value);
596            }
597            FREE_OP(free_value);
598            return;
599        }
600        Z_OBJ_HT_P(object)->write_property(object, property_name, value TSRMLS_CC);
601    } else {
602        /* Note:  property_name in this case is really the array index! */
603        if (!Z_OBJ_HT_P(object)->write_dimension) {
604            zend_error_noreturn(E_ERROR, "Cannot use object as array");
605        }
606        Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC);
607    }
608
609    if (!RETURN_VALUE_UNUSED(result) && !EG(exception)) {
610        AI_SET_PTR(T(result->u.var).var, value);
611        PZVAL_LOCK(value);
612    }
613    zval_ptr_dtor(&value);
614    FREE_OP_IF_VAR(free_value);
615}
616
617static inline int zend_assign_to_string_offset(const temp_variable *T, const zval *value, int value_type TSRMLS_DC)
618{
619    if (Z_TYPE_P(T->str_offset.str) == IS_STRING) {
620
621        if (((int)T->str_offset.offset < 0)) {
622            zend_error(E_WARNING, "Illegal string offset:  %d", T->str_offset.offset);
623            return 0;
624        }
625
626        if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) {
627            Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1);
628            memset(Z_STRVAL_P(T->str_offset.str) + Z_STRLEN_P(T->str_offset.str),
629                   ' ',
630                   T->str_offset.offset - Z_STRLEN_P(T->str_offset.str));
631            Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0;
632            Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1;
633        }
634
635        if (Z_TYPE_P(value) != IS_STRING) {
636            zval tmp = *value;
637
638            if (value_type != IS_TMP_VAR) {
639                zval_copy_ctor(&tmp);
640            }
641            convert_to_string(&tmp);
642            Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL(tmp)[0];
643            STR_FREE(Z_STRVAL(tmp));
644        } else {
645            Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL_P(value)[0];
646            if (value_type == IS_TMP_VAR) {
647                /* we can safely free final_value here
648                 * because separation is done only
649                 * in case value_type == IS_VAR */
650                STR_FREE(Z_STRVAL_P(value));
651            }
652        }
653        /*
654         * the value of an assignment to a string offset is undefined
655        T(result->u.var).var = &T->str_offset.str;
656        */
657    }
658    return 1;
659}
660
661static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC)
662{
663    zval *variable_ptr = *variable_ptr_ptr;
664    zval garbage;
665
666    if (variable_ptr == EG(error_zval_ptr)) {
667        if (is_tmp_var) {
668            zval_dtor(value);
669        }
670        return EG(uninitialized_zval_ptr);
671    }
672
673    if (Z_TYPE_P(variable_ptr) == IS_OBJECT && Z_OBJ_HANDLER_P(variable_ptr, set)) {
674        Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
675        return variable_ptr;
676    }
677
678    if (PZVAL_IS_REF(variable_ptr)) {
679        if (variable_ptr!=value) {
680            zend_uint refcount = Z_REFCOUNT_P(variable_ptr);
681
682            garbage = *variable_ptr;
683            *variable_ptr = *value;
684            Z_SET_REFCOUNT_P(variable_ptr, refcount);
685            Z_SET_ISREF_P(variable_ptr);
686            if (!is_tmp_var) {
687                zendi_zval_copy_ctor(*variable_ptr);
688            }
689            zendi_zval_dtor(garbage);
690            return variable_ptr;
691        }
692    } else {
693        if (Z_DELREF_P(variable_ptr)==0) {
694            if (!is_tmp_var) {
695                if (variable_ptr==value) {
696                    Z_ADDREF_P(variable_ptr);
697                } else if (PZVAL_IS_REF(value)) {
698                    garbage = *variable_ptr;
699                    *variable_ptr = *value;
700                    INIT_PZVAL(variable_ptr);
701                    zval_copy_ctor(variable_ptr);
702                    zendi_zval_dtor(garbage);
703                    return variable_ptr;
704                } else {
705                    Z_ADDREF_P(value);
706                    *variable_ptr_ptr = value;
707                    if (variable_ptr != &EG(uninitialized_zval)) {
708                        GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
709                        zval_dtor(variable_ptr);
710                        efree(variable_ptr);
711                    }
712                    return value;
713                }
714            } else {
715                garbage = *variable_ptr;
716                *variable_ptr = *value;
717                INIT_PZVAL(variable_ptr);
718                zendi_zval_dtor(garbage);
719                return variable_ptr;
720            }
721        } else { /* we need to split */
722            GC_ZVAL_CHECK_POSSIBLE_ROOT(*variable_ptr_ptr);
723            if (!is_tmp_var) {
724                if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
725                    ALLOC_ZVAL(variable_ptr);
726                    *variable_ptr_ptr = variable_ptr;
727                    *variable_ptr = *value;
728                    Z_SET_REFCOUNT_P(variable_ptr, 1);
729                    zval_copy_ctor(variable_ptr);
730                } else {
731                    *variable_ptr_ptr = value;
732                    Z_ADDREF_P(value);
733                }
734            } else {
735                ALLOC_ZVAL(*variable_ptr_ptr);
736                Z_SET_REFCOUNT_P(value, 1);
737                **variable_ptr_ptr = *value;
738            }
739        }
740        Z_UNSET_ISREF_PP(variable_ptr_ptr);
741    }
742
743    return *variable_ptr_ptr;
744}
745
746
747/* Utility Functions for Extensions */
748static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
749{
750    if (extension->statement_handler) {
751        extension->statement_handler(op_array);
752    }
753}
754
755
756static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
757{
758    if (extension->fcall_begin_handler) {
759        extension->fcall_begin_handler(op_array);
760    }
761}
762
763
764static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
765{
766    if (extension->fcall_end_handler) {
767        extension->fcall_end_handler(op_array);
768    }
769}
770
771
772static inline HashTable *zend_get_target_symbol_table(const zend_op *opline, const temp_variable *Ts, int type, const zval *variable TSRMLS_DC)
773{
774    switch (opline->op2.u.EA.type) {
775        case ZEND_FETCH_LOCAL:
776            if (!EG(active_symbol_table)) {
777                zend_rebuild_symbol_table(TSRMLS_C);
778            }
779            return EG(active_symbol_table);
780            break;
781        case ZEND_FETCH_GLOBAL:
782        case ZEND_FETCH_GLOBAL_LOCK:
783            return &EG(symbol_table);
784            break;
785        case ZEND_FETCH_STATIC:
786            if (!EG(active_op_array)->static_variables) {
787                ALLOC_HASHTABLE(EG(active_op_array)->static_variables);
788                zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
789            }
790            return EG(active_op_array)->static_variables;
791            break;
792        EMPTY_SWITCH_DEFAULT_CASE()
793    }
794    return NULL;
795}
796
797static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int type TSRMLS_DC)
798{
799    zval **retval;
800    char *offset_key;
801    int offset_key_length;
802    long index;
803
804    switch (dim->type) {
805        case IS_NULL:
806            offset_key = "";
807            offset_key_length = 0;
808            goto fetch_string_dim;
809
810        case IS_STRING:
811
812            offset_key = dim->value.str.val;
813            offset_key_length = dim->value.str.len;
814
815fetch_string_dim:
816            if (zend_symtable_find(ht, offset_key, offset_key_length+1, (void **) &retval) == FAILURE) {
817                switch (type) {
818                    case BP_VAR_R:
819                        zend_error(E_NOTICE, "Undefined index: %s", offset_key);
820                        /* break missing intentionally */
821                    case BP_VAR_UNSET:
822                    case BP_VAR_IS:
823                        retval = &EG(uninitialized_zval_ptr);
824                        break;
825                    case BP_VAR_RW:
826                        zend_error(E_NOTICE,"Undefined index: %s", offset_key);
827                        /* break missing intentionally */
828                    case BP_VAR_W: {
829                            zval *new_zval = &EG(uninitialized_zval);
830
831                            Z_ADDREF_P(new_zval);
832                            zend_symtable_update(ht, offset_key, offset_key_length+1, &new_zval, sizeof(zval *), (void **) &retval);
833                        }
834                        break;
835                }
836            }
837            break;
838        case IS_DOUBLE:
839            index = zend_dval_to_lval(Z_DVAL_P(dim));
840            goto num_index;
841        case IS_RESOURCE:
842            zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(dim), Z_LVAL_P(dim));
843            /* Fall Through */
844        case IS_BOOL:
845        case IS_LONG:
846            index = Z_LVAL_P(dim);
847num_index:
848            if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
849                switch (type) {
850                    case BP_VAR_R:
851                        zend_error(E_NOTICE,"Undefined offset: %ld", index);
852                        /* break missing intentionally */
853                    case BP_VAR_UNSET:
854                    case BP_VAR_IS:
855                        retval = &EG(uninitialized_zval_ptr);
856                        break;
857                    case BP_VAR_RW:
858                        zend_error(E_NOTICE,"Undefined offset: %ld", index);
859                        /* break missing intentionally */
860                    case BP_VAR_W: {
861                        zval *new_zval = &EG(uninitialized_zval);
862
863                        Z_ADDREF_P(new_zval);
864                        zend_hash_index_update(ht, index, &new_zval, sizeof(zval *), (void **) &retval);
865                    }
866                    break;
867                }
868            }
869            break;
870
871        default:
872            zend_error(E_WARNING, "Illegal offset type");
873            return (type == BP_VAR_W || type == BP_VAR_RW) ?
874                &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
875    }
876    return retval;
877}
878
879static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC)
880{
881    zval *container = *container_ptr;
882    zval **retval;
883
884    switch (Z_TYPE_P(container)) {
885
886        case IS_ARRAY:
887            if (type != BP_VAR_UNSET && Z_REFCOUNT_P(container)>1 && !PZVAL_IS_REF(container)) {
888                SEPARATE_ZVAL(container_ptr);
889                container = *container_ptr;
890            }
891fetch_from_array:
892            if (dim == NULL) {
893                zval *new_zval = &EG(uninitialized_zval);
894
895                Z_ADDREF_P(new_zval);
896                if (zend_hash_next_index_insert(Z_ARRVAL_P(container), &new_zval, sizeof(zval *), (void **) &retval) == FAILURE) {
897                    zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
898                    retval = &EG(error_zval_ptr);
899                    Z_DELREF_P(new_zval);
900                }
901            } else {
902                retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, type TSRMLS_CC);
903            }
904            result->var.ptr_ptr = retval;
905            PZVAL_LOCK(*retval);
906            return;
907            break;
908
909        case IS_NULL:
910            if (container == EG(error_zval_ptr)) {
911                result->var.ptr_ptr = &EG(error_zval_ptr);
912                PZVAL_LOCK(EG(error_zval_ptr));
913            } else if (type != BP_VAR_UNSET) {
914convert_to_array:
915                if (!PZVAL_IS_REF(container)) {
916                    SEPARATE_ZVAL(container_ptr);
917                    container = *container_ptr;
918                }
919                zval_dtor(container);
920                array_init(container);
921                goto fetch_from_array;
922            } else {
923                /* for read-mode only */
924                result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
925                PZVAL_LOCK(EG(uninitialized_zval_ptr));
926            }
927            return;
928            break;
929
930        case IS_STRING: {
931                zval tmp;
932
933                if (type != BP_VAR_UNSET && Z_STRLEN_P(container)==0) {
934                    goto convert_to_array;
935                }
936                if (dim == NULL) {
937                    zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
938                }
939
940                if (type != BP_VAR_UNSET) {
941                    SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
942                }
943
944                if (Z_TYPE_P(dim) != IS_LONG) {
945                    switch(Z_TYPE_P(dim)) {
946                        /* case IS_LONG: */
947                        case IS_STRING:
948                        case IS_DOUBLE:
949                        case IS_NULL:
950                        case IS_BOOL:
951                            /* do nothing */
952                            break;
953                        default:
954                            zend_error(E_WARNING, "Illegal offset type");
955                            break;
956                    }
957
958                    tmp = *dim;
959                    zval_copy_ctor(&tmp);
960                    convert_to_long(&tmp);
961                    dim = &tmp;
962                }
963                container = *container_ptr;
964                result->str_offset.str = container;
965                PZVAL_LOCK(container);
966                result->str_offset.offset = Z_LVAL_P(dim);
967                result->var.ptr_ptr = NULL;
968                result->var.ptr = NULL;
969                return;
970            }
971            break;
972
973        case IS_OBJECT:
974            if (!Z_OBJ_HT_P(container)->read_dimension) {
975                zend_error_noreturn(E_ERROR, "Cannot use object as array");
976            } else {
977                zval *overloaded_result;
978
979                if (dim_is_tmp_var) {
980                    zval *orig = dim;
981                    MAKE_REAL_ZVAL_PTR(dim);
982                    ZVAL_NULL(orig);
983                }
984                overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
985
986                if (overloaded_result) {
987                    if (!Z_ISREF_P(overloaded_result)) {
988                        if (Z_REFCOUNT_P(overloaded_result) > 0) {
989                            zval *tmp = overloaded_result;
990
991                            ALLOC_ZVAL(overloaded_result);
992                            *overloaded_result = *tmp;
993                            zval_copy_ctor(overloaded_result);
994                            Z_UNSET_ISREF_P(overloaded_result);
995                            Z_SET_REFCOUNT_P(overloaded_result, 0);
996                        }
997                        if (Z_TYPE_P(overloaded_result) != IS_OBJECT) {
998                            zend_class_entry *ce = Z_OBJCE_P(container);
999                            zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name);
1000                        }
1001                    }
1002                    retval = &overloaded_result;
1003                } else {
1004                    retval = &EG(error_zval_ptr);
1005                }
1006                AI_SET_PTR(result->var, *retval);
1007                PZVAL_LOCK(*retval);
1008                if (dim_is_tmp_var) {
1009                    zval_ptr_dtor(&dim);
1010                }
1011            }
1012            return;
1013            break;
1014
1015        case IS_BOOL:
1016            if (type != BP_VAR_UNSET && Z_LVAL_P(container)==0) {
1017                goto convert_to_array;
1018            }
1019            /* break missing intentionally */
1020
1021        default:
1022            if (type == BP_VAR_UNSET) {
1023                zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1024                AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1025                PZVAL_LOCK(EG(uninitialized_zval_ptr));
1026            } else {
1027                zend_error(E_WARNING, "Cannot use a scalar value as an array");
1028                result->var.ptr_ptr = &EG(error_zval_ptr);
1029                PZVAL_LOCK(EG(error_zval_ptr));
1030            }
1031            break;
1032    }
1033}
1034
1035static void zend_fetch_dimension_address_read(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC)
1036{
1037    zval *container = *container_ptr;
1038    zval **retval;
1039
1040    switch (Z_TYPE_P(container)) {
1041
1042        case IS_ARRAY:
1043            retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, type TSRMLS_CC);
1044            if (result) {
1045                AI_SET_PTR(result->var, *retval);
1046                PZVAL_LOCK(*retval);
1047            }
1048            return;
1049            break;
1050
1051        case IS_NULL:
1052            if (result) {
1053                AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1054                PZVAL_LOCK(EG(uninitialized_zval_ptr));
1055            }
1056            return;
1057            break;
1058
1059        case IS_STRING: {
1060                zval tmp;
1061
1062                if (Z_TYPE_P(dim) != IS_LONG) {
1063                    switch(Z_TYPE_P(dim)) {
1064                        /* case IS_LONG: */
1065                        case IS_STRING:
1066                        case IS_DOUBLE:
1067                        case IS_NULL:
1068                        case IS_BOOL:
1069                            /* do nothing */
1070                            break;
1071                        default:
1072                            zend_error(E_WARNING, "Illegal offset type");
1073                            break;
1074                    }
1075
1076                    tmp = *dim;
1077                    zval_copy_ctor(&tmp);
1078                    convert_to_long(&tmp);
1079                    dim = &tmp;
1080                }
1081                if (result) {
1082                    if ((Z_LVAL_P(dim) < 0 || Z_STRLEN_P(container) <= Z_LVAL_P(dim)) && type != BP_VAR_IS) {
1083                        zend_error(E_NOTICE, "Uninitialized string offset: %ld", Z_LVAL_P(dim));
1084                    }
1085                    result->str_offset.str = container;
1086                    PZVAL_LOCK(container);
1087                    result->str_offset.offset = Z_LVAL_P(dim);
1088                    result->var.ptr_ptr = NULL;
1089                    result->var.ptr = NULL;
1090                }
1091                return;
1092            }
1093            break;
1094
1095        case IS_OBJECT:
1096            if (!Z_OBJ_HT_P(container)->read_dimension) {
1097                zend_error_noreturn(E_ERROR, "Cannot use object as array");
1098            } else {
1099                zval *overloaded_result;
1100
1101                if (dim_is_tmp_var) {
1102                    zval *orig = dim;
1103                    MAKE_REAL_ZVAL_PTR(dim);
1104                    ZVAL_NULL(orig);
1105                }
1106                overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
1107
1108                if (overloaded_result) {
1109                    if (result) {
1110                        AI_SET_PTR(result->var, overloaded_result);
1111                        PZVAL_LOCK(overloaded_result);
1112                    } else if (Z_REFCOUNT_P(overloaded_result) == 0) {
1113                        /* Destroy unused result from offsetGet() magic method */
1114                        Z_SET_REFCOUNT_P(overloaded_result, 1);
1115                        zval_ptr_dtor(&overloaded_result);
1116                    }
1117                } else if (result) {
1118                    AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1119                    PZVAL_LOCK(EG(uninitialized_zval_ptr));
1120                }
1121                if (dim_is_tmp_var) {
1122                    zval_ptr_dtor(&dim);
1123                }
1124            }
1125            return;
1126            break;
1127
1128        default:
1129            if (result) {
1130                AI_SET_PTR(result->var, EG(uninitialized_zval_ptr));
1131                PZVAL_LOCK(EG(uninitialized_zval_ptr));
1132            }
1133            return;
1134            break;
1135    }
1136}
1137
1138static void zend_fetch_property_address(temp_variable *result, zval **container_ptr, zval *prop_ptr, int type TSRMLS_DC)
1139{
1140    zval *container = *container_ptr;;
1141
1142    if (Z_TYPE_P(container) != IS_OBJECT) {
1143        if (container == EG(error_zval_ptr)) {
1144            result->var.ptr_ptr = &EG(error_zval_ptr);
1145            PZVAL_LOCK(*result->var.ptr_ptr);
1146            return;
1147        }
1148
1149        /* this should modify object only if it's empty */
1150        if (type != BP_VAR_UNSET &&
1151            ((Z_TYPE_P(container) == IS_NULL ||
1152             (Z_TYPE_P(container) == IS_BOOL && Z_LVAL_P(container)==0) ||
1153             (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)))) {
1154            if (!PZVAL_IS_REF(container)) {
1155                SEPARATE_ZVAL(container_ptr);
1156                container = *container_ptr;
1157            }
1158            object_init(container);
1159        } else {
1160            zend_error(E_WARNING, "Attempt to modify property of non-object");
1161            result->var.ptr_ptr = &EG(error_zval_ptr);
1162            PZVAL_LOCK(EG(error_zval_ptr));
1163            return;
1164        }
1165    }
1166
1167    if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) {
1168        zval **ptr_ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr TSRMLS_CC);
1169        if (NULL == ptr_ptr) {
1170            zval *ptr;
1171
1172            if (Z_OBJ_HT_P(container)->read_property &&
1173                (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC)) != NULL) {
1174                AI_SET_PTR(result->var, ptr);
1175                PZVAL_LOCK(ptr);
1176            } else {
1177                zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access");
1178            }
1179        } else {
1180            result->var.ptr_ptr = ptr_ptr;
1181            PZVAL_LOCK(*ptr_ptr);
1182        }
1183    } else if (Z_OBJ_HT_P(container)->read_property) {
1184        zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC);
1185
1186        AI_SET_PTR(result->var, ptr);
1187        PZVAL_LOCK(ptr);
1188    } else {
1189        zend_error(E_WARNING, "This object doesn't support property references");
1190        result->var.ptr_ptr = &EG(error_zval_ptr);
1191        PZVAL_LOCK(EG(error_zval_ptr));
1192    }
1193}
1194
1195static inline zend_brk_cont_element* zend_brk_cont(const zval *nest_levels_zval, int array_offset, const zend_op_array *op_array, const temp_variable *Ts TSRMLS_DC)
1196{
1197    zval tmp;
1198    int nest_levels, original_nest_levels;
1199    zend_brk_cont_element *jmp_to;
1200
1201    if (nest_levels_zval->type != IS_LONG) {
1202        tmp = *nest_levels_zval;
1203        zval_copy_ctor(&tmp);
1204        convert_to_long(&tmp);
1205        nest_levels = tmp.value.lval;
1206    } else {
1207        nest_levels = nest_levels_zval->value.lval;
1208    }
1209    original_nest_levels = nest_levels;
1210    do {
1211        if (array_offset==-1) {
1212            zend_error_noreturn(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
1213        }
1214        jmp_to = &op_array->brk_cont_array[array_offset];
1215        if (nest_levels>1) {
1216            zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
1217
1218            switch (brk_opline->opcode) {
1219                case ZEND_SWITCH_FREE:
1220                    if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
1221                        zend_switch_free(&T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC);
1222                    }
1223                    break;
1224                case ZEND_FREE:
1225                    if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) {
1226                        zendi_zval_dtor(T(brk_opline->op1.u.var).tmp_var);
1227                    }
1228                    break;
1229            }
1230        }
1231        array_offset = jmp_to->parent;
1232    } while (--nest_levels > 0);
1233    return jmp_to;
1234}
1235
1236#if ZEND_INTENSIVE_DEBUGGING
1237
1238#define CHECK_SYMBOL_TABLES()                                                       \
1239    zend_hash_apply(&EG(symbol_table), (apply_func_t) zend_check_symbol TSRMLS_CC); \
1240    if (&EG(symbol_table)!=EG(active_symbol_table)) {                               \
1241        zend_hash_apply(EG(active_symbol_table), (apply_func_t) zend_check_symbol TSRMLS_CC);   \
1242    }
1243
1244static int zend_check_symbol(zval **pz TSRMLS_DC)
1245{
1246    if (Z_TYPE_PP(pz) > 9) {
1247        fprintf(stderr, "Warning!  %x has invalid type!\n", *pz);
1248/* See http://support.microsoft.com/kb/190351 */
1249#ifdef PHP_WIN32
1250        fflush(stderr);
1251#endif
1252    } else if (Z_TYPE_PP(pz) == IS_ARRAY) {
1253        zend_hash_apply(Z_ARRVAL_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
1254    } else if (Z_TYPE_PP(pz) == IS_OBJECT) {
1255
1256        /* OBJ-TBI - doesn't support new object model! */
1257        zend_hash_apply(Z_OBJPROP_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
1258    }
1259
1260    return 0;
1261}
1262
1263
1264#else
1265#define CHECK_SYMBOL_TABLES()
1266#endif
1267
1268ZEND_API opcode_handler_t *zend_opcode_handlers;
1269
1270ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC)
1271{
1272    zval **return_value_ptr = &(*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.u.var)).var.ptr;
1273    ((zend_internal_function *) execute_data_ptr->function_state.function)->handler(execute_data_ptr->opline->extended_value, *return_value_ptr, execute_data_ptr->function_state.function->common.return_reference?return_value_ptr:NULL, execute_data_ptr->object, return_value_used TSRMLS_CC);
1274}
1275
1276#define ZEND_VM_NEXT_OPCODE() \
1277    CHECK_SYMBOL_TABLES() \
1278    EX(opline)++; \
1279    ZEND_VM_CONTINUE()
1280
1281#define ZEND_VM_SET_OPCODE(new_op) \
1282    CHECK_SYMBOL_TABLES() \
1283    EX(opline) = new_op
1284
1285#define ZEND_VM_JMP(new_op) \
1286    CHECK_SYMBOL_TABLES() \
1287    if (EXPECTED(!EG(exception))) { \
1288        EX(opline) = new_op; \
1289    } \
1290    ZEND_VM_CONTINUE()
1291
1292#define ZEND_VM_INC_OPCODE() \
1293    EX(opline)++
1294
1295#include "zend_vm_execute.h"
1296
1297ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
1298{
1299    if (opcode != ZEND_USER_OPCODE) {
1300        zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
1301        zend_user_opcode_handlers[opcode] = handler;
1302        return SUCCESS;
1303    }
1304    return FAILURE;
1305}
1306
1307ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
1308{
1309    return zend_user_opcode_handlers[opcode];
1310}
1311
1312ZEND_API zval *zend_get_zval_ptr(znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) {
1313    return get_zval_ptr(node, Ts, should_free, type);
1314}
1315
1316ZEND_API zval **zend_get_zval_ptr_ptr(const znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) {
1317    return get_zval_ptr_ptr(node, Ts, should_free, type);
1318}
1319
1320/*
1321 * Local variables:
1322 * tab-width: 4
1323 * c-basic-offset: 4
1324 * indent-tabs-mode: t
1325 * End:
1326 */
1327