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
49 typedef 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 */
57 static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
58 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
59 static 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
zend_pzval_unlock_func(zval * z,zend_free_op * should_free,int unref TSRMLS_DC)68 static 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
zend_pzval_unlock_free_func(zval * z TSRMLS_DC)84 static 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
zend_get_compiled_variable_value(const zend_execute_data * execute_data_ptr,zend_uint var)170 ZEND_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
_get_zval_ptr_tmp(const znode * node,const temp_variable * Ts,zend_free_op * should_free TSRMLS_DC)175 static 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
_get_zval_ptr_var_string_offset(const znode * node,const temp_variable * Ts,zend_free_op * should_free TSRMLS_DC)180 static 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
_get_zval_ptr_var(const znode * node,const temp_variable * Ts,zend_free_op * should_free TSRMLS_DC)207 static 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
_get_zval_cv_lookup(zval *** ptr,zend_uint var,int type TSRMLS_DC)218 static 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
_get_zval_ptr_cv(const znode * node,const temp_variable * Ts,int type TSRMLS_DC)249 static 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
_get_zval_ptr(znode * node,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)259 static 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
_get_zval_ptr_ptr_var(const znode * node,const temp_variable * Ts,zend_free_op * should_free TSRMLS_DC)287 static 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
_get_zval_ptr_ptr_cv(const znode * node,const temp_variable * Ts,int type TSRMLS_DC)300 static 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
_get_zval_ptr_ptr(const znode * node,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)310 static 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
_get_obj_zval_ptr_unused(TSRMLS_D)323 static 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
_get_obj_zval_ptr_ptr(const znode * op,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)333 static 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
_get_obj_zval_ptr_ptr_unused(TSRMLS_D)348 static 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
_get_obj_zval_ptr(znode * op,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)358 static 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
zend_switch_free(temp_variable * T,int extended_value TSRMLS_DC)371 static 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
zend_assign_to_variable_reference(zval ** variable_ptr_ptr,zval ** value_ptr_ptr TSRMLS_DC)386 static 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 */
make_real_object(zval ** object_ptr TSRMLS_DC)429 static 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
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)442 static 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
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)454 static 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
zend_verify_arg_type(zend_function * zf,zend_uint arg_num,zval * arg,ulong fetch_type TSRMLS_DC)477 static 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
zend_assign_to_object(znode * result,zval ** object_ptr,zval * property_name,znode * value_op,const temp_variable * Ts,int opcode TSRMLS_DC)517 static 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
zend_assign_to_string_offset(const temp_variable * T,const zval * value,int value_type TSRMLS_DC)617 static 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
zend_assign_to_variable(zval ** variable_ptr_ptr,zval * value,int is_tmp_var TSRMLS_DC)661 static 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 */
zend_extension_statement_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)748 static 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
zend_extension_fcall_begin_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)756 static 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
zend_extension_fcall_end_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)764 static 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
zend_get_target_symbol_table(const zend_op * opline,const temp_variable * Ts,int type,const zval * variable TSRMLS_DC)772 static 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
zend_fetch_dimension_address_inner(HashTable * ht,const zval * dim,int type TSRMLS_DC)797 static 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
815 fetch_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);
847 num_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
zend_fetch_dimension_address(temp_variable * result,zval ** container_ptr,zval * dim,int dim_is_tmp_var,int type TSRMLS_DC)879 static 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 }
891 fetch_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) {
914 convert_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
zend_fetch_dimension_address_read(temp_variable * result,zval ** container_ptr,zval * dim,int dim_is_tmp_var,int type TSRMLS_DC)1035 static 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
zend_fetch_property_address(temp_variable * result,zval ** container_ptr,zval * prop_ptr,int type TSRMLS_DC)1138 static 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
zend_brk_cont(const zval * nest_levels_zval,int array_offset,const zend_op_array * op_array,const temp_variable * Ts TSRMLS_DC)1195 static 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
zend_check_symbol(zval ** pz TSRMLS_DC)1244 static 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
1268 ZEND_API opcode_handler_t *zend_opcode_handlers;
1269
execute_internal(zend_execute_data * execute_data_ptr,int return_value_used TSRMLS_DC)1270 ZEND_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
zend_set_user_opcode_handler(zend_uchar opcode,user_opcode_handler_t handler)1297 ZEND_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
zend_get_user_opcode_handler(zend_uchar opcode)1307 ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
1308 {
1309 return zend_user_opcode_handlers[opcode];
1310 }
1311
zend_get_zval_ptr(znode * node,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)1312 ZEND_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
zend_get_zval_ptr_ptr(const znode * node,const temp_variable * Ts,zend_free_op * should_free,int type TSRMLS_DC)1316 ZEND_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