xref: /PHP-5.3/Zend/zend_execute.c (revision c96a5bc6)
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