xref: /PHP-5.5/Zend/zend_execute.c (revision 73c1be26)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    +----------------------------------------------------------------------+
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_generators.h"
39 #include "zend_vm.h"
40 #include "zend_dtrace.h"
41 
42 /* Virtual current working directory support */
43 #include "tsrm_virtual_cwd.h"
44 
45 #define _CONST_CODE  0
46 #define _TMP_CODE    1
47 #define _VAR_CODE    2
48 #define _UNUSED_CODE 3
49 #define _CV_CODE     4
50 
51 typedef int (*incdec_t)(zval *);
52 
53 #define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
54 #define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
55 #define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
56 #define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
57 
58 /* Prototypes */
59 static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
60 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
61 static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC);
62 
63 #define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
64 
65 #define EX_T(offset) (*EX_TMP_VAR(execute_data, offset))
66 #define EX_CV(var)   (*EX_CV_NUM(execute_data, var))
67 
68 #define TEMP_VAR_STACK_LIMIT 2000
69 
zend_pzval_unlock_func(zval * z,zend_free_op * should_free,int unref TSRMLS_DC)70 static zend_always_inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC)
71 {
72 	if (!Z_DELREF_P(z)) {
73 		Z_SET_REFCOUNT_P(z, 1);
74 		Z_UNSET_ISREF_P(z);
75 		should_free->var = z;
76 /*		should_free->is_var = 1; */
77 	} else {
78 		should_free->var = 0;
79 		if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
80 			Z_UNSET_ISREF_P(z);
81 		}
82 		GC_ZVAL_CHECK_POSSIBLE_ROOT(z);
83 	}
84 }
85 
zend_pzval_unlock_free_func(zval * z TSRMLS_DC)86 static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
87 {
88 	if (!Z_DELREF_P(z)) {
89 		ZEND_ASSERT(z != &EG(uninitialized_zval));
90 		GC_REMOVE_ZVAL_FROM_BUFFER(z);
91 		zval_dtor(z);
92 		efree(z);
93 	}
94 }
95 
96 #undef zval_ptr_dtor
97 #define zval_ptr_dtor(pzv) i_zval_ptr_dtor(*(pzv)  ZEND_FILE_LINE_CC)
98 
99 #define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
100 #define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
101 #define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC)
102 #define PZVAL_LOCK(z) Z_ADDREF_P((z))
103 #define SELECTIVE_PZVAL_LOCK(pzv, opline)	if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
104 
105 #define EXTRACT_ZVAL_PTR(t) do {						\
106 		temp_variable *__t = (t);					\
107 		if (__t->var.ptr_ptr) {						\
108 			__t->var.ptr = *__t->var.ptr_ptr;		\
109 			__t->var.ptr_ptr = &__t->var.ptr;		\
110 			if (!PZVAL_IS_REF(__t->var.ptr) && 		\
111 			    Z_REFCOUNT_P(__t->var.ptr) > 2) {	\
112 				SEPARATE_ZVAL(__t->var.ptr_ptr);	\
113 			}										\
114 		}											\
115 	} while (0)
116 
117 #define AI_SET_PTR(t, val) do {				\
118 		temp_variable *__t = (t);			\
119 		__t->var.ptr = (val);				\
120 		__t->var.ptr_ptr = &__t->var.ptr;	\
121 	} while (0)
122 
123 #define FREE_OP(should_free) \
124 	if (should_free.var) { \
125 		if ((zend_uintptr_t)should_free.var & 1L) { \
126 			zval_dtor((zval*)((zend_uintptr_t)should_free.var & ~1L)); \
127 		} else { \
128 			zval_ptr_dtor(&should_free.var); \
129 		} \
130 	}
131 
132 #define FREE_OP_IF_VAR(should_free) \
133 	if (should_free.var != NULL && (((zend_uintptr_t)should_free.var & 1L) == 0)) { \
134 		zval_ptr_dtor(&should_free.var); \
135 	}
136 
137 #define FREE_OP_VAR_PTR(should_free) \
138 	if (should_free.var) { \
139 		zval_ptr_dtor(&should_free.var); \
140 	}
141 
142 #define TMP_FREE(z) (zval*)(((zend_uintptr_t)(z)) | 1L)
143 
144 #define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
145 
146 #define MAKE_REAL_ZVAL_PTR(val) \
147 	do { \
148 		zval *_tmp; \
149 		ALLOC_ZVAL(_tmp); \
150 		INIT_PZVAL_COPY(_tmp, (val)); \
151 		(val) = _tmp; \
152 	} while (0)
153 
154 /* End of zend_execute_locks.h */
155 
156 #define CV_DEF_OF(i) (EG(active_op_array)->vars[i])
157 
158 #define CTOR_CALL_BIT    0x1
159 #define CTOR_USED_BIT    0x2
160 
161 #define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
162 #define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
163 
164 #define ENCODE_CTOR(ce, used) \
165 	((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
166 #define DECODE_CTOR(ce) \
167 	((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
168 
169 #undef EX
170 #define EX(element) execute_data->element
171 
zend_get_compiled_variable_value(const zend_execute_data * execute_data,zend_uint var)172 ZEND_API zval** zend_get_compiled_variable_value(const zend_execute_data *execute_data, zend_uint var)
173 {
174 	return EX_CV(var);
175 }
176 
_get_zval_ptr_tmp(zend_uint var,const zend_execute_data * execute_data,zend_free_op * should_free TSRMLS_DC)177 static zend_always_inline zval *_get_zval_ptr_tmp(zend_uint var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
178 {
179 	return should_free->var = &EX_T(var).tmp_var;
180 }
181 
_get_zval_ptr_var(zend_uint var,const zend_execute_data * execute_data,zend_free_op * should_free TSRMLS_DC)182 static zend_always_inline zval *_get_zval_ptr_var(zend_uint var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
183 {
184 	zval *ptr = EX_T(var).var.ptr;
185 
186 	PZVAL_UNLOCK(ptr, should_free);
187 	return ptr;
188 }
189 
_get_zval_cv_lookup(zval *** ptr,zend_uint var,int type TSRMLS_DC)190 static zend_never_inline zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC)
191 {
192 	zend_compiled_variable *cv = &CV_DEF_OF(var);
193 
194 	if (!EG(active_symbol_table) ||
195 	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
196 		switch (type) {
197 			case BP_VAR_R:
198 			case BP_VAR_UNSET:
199 				zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
200 				/* break missing intentionally */
201 			case BP_VAR_IS:
202 				return &EG(uninitialized_zval_ptr);
203 				break;
204 			case BP_VAR_RW:
205 				zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
206 				/* break missing intentionally */
207 			case BP_VAR_W:
208 				Z_ADDREF(EG(uninitialized_zval));
209 				if (!EG(active_symbol_table)) {
210 					*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
211 					**ptr = &EG(uninitialized_zval);
212 				} else {
213 					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);
214 				}
215 				break;
216 		}
217 	}
218 	return *ptr;
219 }
220 
_get_zval_cv_lookup_BP_VAR_R(zval *** ptr,zend_uint var TSRMLS_DC)221 static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_R(zval ***ptr, zend_uint var TSRMLS_DC)
222 {
223 	zend_compiled_variable *cv = &CV_DEF_OF(var);
224 
225 	if (!EG(active_symbol_table) ||
226 	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
227 		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
228 		return &EG(uninitialized_zval_ptr);
229 	}
230 	return *ptr;
231 }
232 
_get_zval_cv_lookup_BP_VAR_UNSET(zval *** ptr,zend_uint var TSRMLS_DC)233 static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_UNSET(zval ***ptr, zend_uint var TSRMLS_DC)
234 {
235 	zend_compiled_variable *cv = &CV_DEF_OF(var);
236 
237 	if (!EG(active_symbol_table) ||
238 	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
239 		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
240 		return &EG(uninitialized_zval_ptr);
241 	}
242 	return *ptr;
243 }
244 
_get_zval_cv_lookup_BP_VAR_IS(zval *** ptr,zend_uint var TSRMLS_DC)245 static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_IS(zval ***ptr, zend_uint var TSRMLS_DC)
246 {
247 	zend_compiled_variable *cv = &CV_DEF_OF(var);
248 
249 	if (!EG(active_symbol_table) ||
250 	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
251 		return &EG(uninitialized_zval_ptr);
252 	}
253 	return *ptr;
254 }
255 
_get_zval_cv_lookup_BP_VAR_RW(zval *** ptr,zend_uint var TSRMLS_DC)256 static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_RW(zval ***ptr, zend_uint var TSRMLS_DC)
257 {
258 	zend_compiled_variable *cv = &CV_DEF_OF(var);
259 
260 	if (!EG(active_symbol_table)) {
261 		Z_ADDREF(EG(uninitialized_zval));
262 		*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
263 		**ptr = &EG(uninitialized_zval);
264 		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
265 	} else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
266 		Z_ADDREF(EG(uninitialized_zval));
267 		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);
268 		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
269 	}
270 	return *ptr;
271 }
272 
_get_zval_cv_lookup_BP_VAR_W(zval *** ptr,zend_uint var TSRMLS_DC)273 static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zval ***ptr, zend_uint var TSRMLS_DC)
274 {
275 	zend_compiled_variable *cv = &CV_DEF_OF(var);
276 
277 	if (!EG(active_symbol_table)) {
278 		Z_ADDREF(EG(uninitialized_zval));
279 		*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
280 		**ptr = &EG(uninitialized_zval);
281 	} else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
282 		Z_ADDREF(EG(uninitialized_zval));
283 		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);
284 	}
285 	return *ptr;
286 }
287 
_get_zval_ptr_cv(zend_uint var,int type TSRMLS_DC)288 static zend_always_inline zval *_get_zval_ptr_cv(zend_uint var, int type TSRMLS_DC)
289 {
290 	zval ***ptr = EX_CV_NUM(EG(current_execute_data), var);
291 
292 	if (UNEXPECTED(*ptr == NULL)) {
293 		return *_get_zval_cv_lookup(ptr, var, type TSRMLS_CC);
294 	}
295 	return **ptr;
296 }
297 
_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)298 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
299 {
300 	zval ***ptr = EX_CV_NUM(execute_data, var);
301 
302 	if (UNEXPECTED(*ptr == NULL)) {
303 		return *_get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
304 	}
305 	return **ptr;
306 }
307 
_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)308 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
309 {
310 	zval ***ptr = EX_CV_NUM(execute_data, var);
311 
312 	if (UNEXPECTED(*ptr == NULL)) {
313 		return *_get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
314 	}
315 	return **ptr;
316 }
317 
_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)318 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
319 {
320 	zval ***ptr = EX_CV_NUM(execute_data, var);
321 
322 	if (UNEXPECTED(*ptr == NULL)) {
323 		return *_get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
324 	}
325 	return **ptr;
326 }
327 
_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)328 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
329 {
330 	zval ***ptr = EX_CV_NUM(execute_data, var);
331 
332 	if (UNEXPECTED(*ptr == NULL)) {
333 		return *_get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
334 	}
335 	return **ptr;
336 }
337 
_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)338 static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
339 {
340 	zval ***ptr = EX_CV_NUM(execute_data, var);
341 
342 	if (UNEXPECTED(*ptr == NULL)) {
343 		return *_get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
344 	}
345 	return **ptr;
346 }
347 
_get_zval_ptr(int op_type,const znode_op * node,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)348 static inline zval *_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
349 {
350 /*	should_free->is_var = 0; */
351 	switch (op_type) {
352 		case IS_CONST:
353 			should_free->var = 0;
354 			return node->zv;
355 			break;
356 		case IS_TMP_VAR:
357 			should_free->var = TMP_FREE(&EX_T(node->var).tmp_var);
358 			return &EX_T(node->var).tmp_var;
359 			break;
360 		case IS_VAR:
361 			return _get_zval_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
362 			break;
363 		case IS_UNUSED:
364 			should_free->var = 0;
365 			return NULL;
366 			break;
367 		case IS_CV:
368 			should_free->var = 0;
369 			return _get_zval_ptr_cv(node->var, type TSRMLS_CC);
370 			break;
371 		EMPTY_SWITCH_DEFAULT_CASE()
372 	}
373 	return NULL;
374 }
375 
_get_zval_ptr_ptr_var(zend_uint var,const zend_execute_data * execute_data,zend_free_op * should_free TSRMLS_DC)376 static zend_always_inline zval **_get_zval_ptr_ptr_var(zend_uint var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
377 {
378 	zval** ptr_ptr = EX_T(var).var.ptr_ptr;
379 
380 	if (EXPECTED(ptr_ptr != NULL)) {
381 		PZVAL_UNLOCK(*ptr_ptr, should_free);
382 	} else {
383 		/* string offset */
384 		PZVAL_UNLOCK(EX_T(var).str_offset.str, should_free);
385 	}
386 	return ptr_ptr;
387 }
388 
_get_zval_ptr_ptr_cv(zend_uint var,int type TSRMLS_DC)389 static zend_always_inline zval **_get_zval_ptr_ptr_cv(zend_uint var, int type TSRMLS_DC)
390 {
391 	zval ***ptr = EX_CV_NUM(EG(current_execute_data), var);
392 
393 	if (UNEXPECTED(*ptr == NULL)) {
394 		return _get_zval_cv_lookup(ptr, var, type TSRMLS_CC);
395 	}
396 	return *ptr;
397 }
398 
_get_zval_ptr_ptr_cv_BP_VAR_R(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)399 static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
400 {
401 	zval ***ptr = EX_CV_NUM(execute_data, var);
402 
403 	if (UNEXPECTED(*ptr == NULL)) {
404 		return _get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
405 	}
406 	return *ptr;
407 }
408 
_get_zval_ptr_ptr_cv_BP_VAR_UNSET(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)409 static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
410 {
411 	zval ***ptr = EX_CV_NUM(execute_data, var);
412 
413 	if (UNEXPECTED(*ptr == NULL)) {
414 		return _get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
415 	}
416 	return *ptr;
417 }
418 
_get_zval_ptr_ptr_cv_BP_VAR_IS(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)419 static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
420 {
421 	zval ***ptr = EX_CV_NUM(execute_data, var);
422 
423 	if (UNEXPECTED(*ptr == NULL)) {
424 		return _get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
425 	}
426 	return *ptr;
427 }
428 
_get_zval_ptr_ptr_cv_BP_VAR_RW(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)429 static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
430 {
431 	zval ***ptr = EX_CV_NUM(execute_data, var);
432 
433 	if (UNEXPECTED(*ptr == NULL)) {
434 		return _get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
435 	}
436 	return *ptr;
437 }
438 
_get_zval_ptr_ptr_cv_BP_VAR_W(const zend_execute_data * execute_data,zend_uint var TSRMLS_DC)439 static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
440 {
441 	zval ***ptr = EX_CV_NUM(execute_data, var);
442 
443 	if (UNEXPECTED(*ptr == NULL)) {
444 		return _get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
445 	}
446 	return *ptr;
447 }
448 
_get_zval_ptr_ptr(int op_type,const znode_op * node,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)449 static inline zval **_get_zval_ptr_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
450 {
451 	if (op_type == IS_CV) {
452 		should_free->var = 0;
453 		return _get_zval_ptr_ptr_cv(node->var, type TSRMLS_CC);
454 	} else if (op_type == IS_VAR) {
455 		return _get_zval_ptr_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
456 	} else {
457 		should_free->var = 0;
458 		return NULL;
459 	}
460 }
461 
_get_obj_zval_ptr_unused(TSRMLS_D)462 static zend_always_inline zval *_get_obj_zval_ptr_unused(TSRMLS_D)
463 {
464 	if (EXPECTED(EG(This) != NULL)) {
465 		return EG(This);
466 	} else {
467 		zend_error_noreturn(E_ERROR, "Using $this when not in object context");
468 		return NULL;
469 	}
470 }
471 
_get_obj_zval_ptr_ptr(int op_type,const znode_op * op,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)472 static inline zval **_get_obj_zval_ptr_ptr(int op_type, const znode_op *op, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
473 {
474 	if (op_type == IS_UNUSED) {
475 		if (EXPECTED(EG(This) != NULL)) {
476 			/* this should actually never be modified, _ptr_ptr is modified only when
477 			   the object is empty */
478 			should_free->var = 0;
479 			return &EG(This);
480 		} else {
481 			zend_error_noreturn(E_ERROR, "Using $this when not in object context");
482 		}
483 	}
484 	return get_zval_ptr_ptr(op_type, op, execute_data, should_free, type);
485 }
486 
_get_obj_zval_ptr_ptr_unused(TSRMLS_D)487 static zend_always_inline zval **_get_obj_zval_ptr_ptr_unused(TSRMLS_D)
488 {
489 	if (EXPECTED(EG(This) != NULL)) {
490 		return &EG(This);
491 	} else {
492 		zend_error_noreturn(E_ERROR, "Using $this when not in object context");
493 		return NULL;
494 	}
495 }
496 
_get_obj_zval_ptr(int op_type,znode_op * op,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)497 static inline zval *_get_obj_zval_ptr(int op_type, znode_op *op, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
498 {
499 	if (op_type == IS_UNUSED) {
500 		if (EXPECTED(EG(This) != NULL)) {
501 			should_free->var = 0;
502 			return EG(This);
503 		} else {
504 			zend_error_noreturn(E_ERROR, "Using $this when not in object context");
505 		}
506 	}
507 	return get_zval_ptr(op_type, op, execute_data, should_free, type);
508 }
509 
zend_assign_to_variable_reference(zval ** variable_ptr_ptr,zval ** value_ptr_ptr TSRMLS_DC)510 static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)
511 {
512 	zval *variable_ptr = *variable_ptr_ptr;
513 	zval *value_ptr = *value_ptr_ptr;
514 
515 	if (variable_ptr == &EG(error_zval) || value_ptr == &EG(error_zval)) {
516 		variable_ptr_ptr = &EG(uninitialized_zval_ptr);
517 	} else if (variable_ptr != value_ptr) {
518 		if (!PZVAL_IS_REF(value_ptr)) {
519 			/* break it away */
520 			Z_DELREF_P(value_ptr);
521 			if (Z_REFCOUNT_P(value_ptr)>0) {
522 				ALLOC_ZVAL(*value_ptr_ptr);
523 				ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr);
524 				value_ptr = *value_ptr_ptr;
525 				zendi_zval_copy_ctor(*value_ptr);
526 			}
527 			Z_SET_REFCOUNT_P(value_ptr, 1);
528 			Z_SET_ISREF_P(value_ptr);
529 		}
530 
531 		*variable_ptr_ptr = value_ptr;
532 		Z_ADDREF_P(value_ptr);
533 
534 		zval_ptr_dtor(&variable_ptr);
535 	} else if (!Z_ISREF_P(variable_ptr)) {
536 		if (variable_ptr_ptr == value_ptr_ptr) {
537 			SEPARATE_ZVAL(variable_ptr_ptr);
538 		} else if (variable_ptr==&EG(uninitialized_zval)
539 			|| Z_REFCOUNT_P(variable_ptr)>2) {
540 			/* we need to separate */
541 			Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2);
542 			ALLOC_ZVAL(*variable_ptr_ptr);
543 			ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr);
544 			zval_copy_ctor(*variable_ptr_ptr);
545 			*value_ptr_ptr = *variable_ptr_ptr;
546 			Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2);
547 		}
548 		Z_SET_ISREF_PP(variable_ptr_ptr);
549 	}
550 }
551 
552 /* this should modify object only if it's empty */
make_real_object(zval ** object_ptr TSRMLS_DC)553 static inline void make_real_object(zval **object_ptr TSRMLS_DC)
554 {
555 	if (Z_TYPE_PP(object_ptr) == IS_NULL
556 		|| (Z_TYPE_PP(object_ptr) == IS_BOOL && Z_LVAL_PP(object_ptr) == 0)
557 		|| (Z_TYPE_PP(object_ptr) == IS_STRING && Z_STRLEN_PP(object_ptr) == 0)
558 	) {
559 		SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
560 		zval_dtor(*object_ptr);
561 		object_init(*object_ptr);
562 		zend_error(E_WARNING, "Creating default object from empty value");
563 	}
564 }
565 
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)566 ZEND_API 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)
567 {
568 	*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);
569 
570 	*class_name = (*pce) ? (*pce)->name: cur_arg_info->class_name;
571 	if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
572 		return "implement interface ";
573 	} else {
574 		return "be an instance of ";
575 	}
576 }
577 
zend_verify_arg_error(int error_type,const zend_function * zf,zend_uint arg_num,const char * need_msg,const char * need_kind,const char * given_msg,const char * given_kind TSRMLS_DC)578 ZEND_API int zend_verify_arg_error(int error_type, const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind TSRMLS_DC)
579 {
580 	zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
581 	const char *fname = zf->common.function_name;
582 	char *fsep;
583 	const char *fclass;
584 
585 	if (zf->common.scope) {
586 		fsep =  "::";
587 		fclass = zf->common.scope->name;
588 	} else {
589 		fsep =  "";
590 		fclass = "";
591 	}
592 
593 	if (ptr && ptr->op_array) {
594 		zend_error(error_type, "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);
595 	} else {
596 		zend_error(error_type, "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);
597 	}
598 	return 0;
599 }
600 
zend_verify_arg_type(zend_function * zf,zend_uint arg_num,zval * arg,ulong fetch_type TSRMLS_DC)601 static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
602 {
603 	zend_arg_info *cur_arg_info;
604 	char *need_msg;
605 	zend_class_entry *ce;
606 
607 	if (!zf->common.arg_info
608 		|| arg_num>zf->common.num_args) {
609 		return 1;
610 	}
611 
612 	cur_arg_info = &zf->common.arg_info[arg_num-1];
613 
614 	if (cur_arg_info->class_name) {
615 		const char *class_name;
616 
617 		if (!arg) {
618 			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
619 			return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC);
620 		}
621 		if (Z_TYPE_P(arg) == IS_OBJECT) {
622 			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
623 			if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
624 				return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
625 			}
626 		} else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
627 			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
628 			return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
629 		}
630 	} else if (cur_arg_info->type_hint) {
631 		switch(cur_arg_info->type_hint) {
632 			case IS_ARRAY:
633 				if (!arg) {
634 					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
635 				}
636 
637 				if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
638 					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
639 				}
640 				break;
641 
642 			case IS_CALLABLE:
643 				if (!arg) {
644 					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
645 				}
646 				if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
647 					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
648 				}
649 				break;
650 
651 			default:
652 				zend_error(E_ERROR, "Unknown typehint");
653 		}
654 	}
655 	return 1;
656 }
657 
zend_assign_to_object(zval ** retval,zval ** object_ptr,zval * property_name,int value_type,znode_op * value_op,const zend_execute_data * execute_data,int opcode,const zend_literal * key TSRMLS_DC)658 static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval *property_name, int value_type, znode_op *value_op, const zend_execute_data *execute_data, int opcode, const zend_literal *key TSRMLS_DC)
659 {
660 	zval *object = *object_ptr;
661 	zend_free_op free_value;
662  	zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
663 
664 	if (Z_TYPE_P(object) != IS_OBJECT) {
665 		if (object == &EG(error_zval)) {
666  			if (retval) {
667 				*retval = &EG(uninitialized_zval);
668 				PZVAL_LOCK(*retval);
669 			}
670 			FREE_OP(free_value);
671 			return;
672 		}
673 		if (Z_TYPE_P(object) == IS_NULL ||
674 		    (Z_TYPE_P(object) == IS_BOOL && Z_LVAL_P(object) == 0) ||
675 		    (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
676 			SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
677 			object = *object_ptr;
678 			Z_ADDREF_P(object);
679 			zend_error(E_WARNING, "Creating default object from empty value");
680 			if (Z_REFCOUNT_P(object) == 1) {
681 				/* object was removed by error handler, nothing to assign to */
682 				zval_ptr_dtor(&object);
683 				if (retval) {
684 					*retval = &EG(uninitialized_zval);
685 					PZVAL_LOCK(*retval);
686 				}
687 				FREE_OP(free_value);
688 				return;
689 			}
690 			Z_DELREF_P(object);
691 			zval_dtor(object);
692 			object_init(object);
693 		} else {
694 			zend_error(E_WARNING, "Attempt to assign property of non-object");
695 			if (retval) {
696 				*retval = &EG(uninitialized_zval);
697 				PZVAL_LOCK(*retval);
698 			}
699 			FREE_OP(free_value);
700 			return;
701 		}
702 	}
703 
704 	/* separate our value if necessary */
705 	if (value_type == IS_TMP_VAR) {
706 		zval *orig_value = value;
707 
708 		ALLOC_ZVAL(value);
709 		ZVAL_COPY_VALUE(value, orig_value);
710 		Z_UNSET_ISREF_P(value);
711 		Z_SET_REFCOUNT_P(value, 0);
712 	} else if (value_type == IS_CONST) {
713 		zval *orig_value = value;
714 
715 		ALLOC_ZVAL(value);
716 		ZVAL_COPY_VALUE(value, orig_value);
717 		Z_UNSET_ISREF_P(value);
718 		Z_SET_REFCOUNT_P(value, 0);
719 		zval_copy_ctor(value);
720 	}
721 
722 
723 	Z_ADDREF_P(value);
724 	if (opcode == ZEND_ASSIGN_OBJ) {
725 		if (!Z_OBJ_HT_P(object)->write_property) {
726 			zend_error(E_WARNING, "Attempt to assign property of non-object");
727 			if (retval) {
728 				*retval = &EG(uninitialized_zval);
729 				PZVAL_LOCK(&EG(uninitialized_zval));
730 			}
731 			if (value_type == IS_TMP_VAR) {
732 				FREE_ZVAL(value);
733 			} else if (value_type == IS_CONST) {
734 				zval_ptr_dtor(&value);
735 			}
736 			FREE_OP(free_value);
737 			return;
738 		}
739 		Z_OBJ_HT_P(object)->write_property(object, property_name, value, key TSRMLS_CC);
740 	} else {
741 		/* Note:  property_name in this case is really the array index! */
742 		if (!Z_OBJ_HT_P(object)->write_dimension) {
743 			zend_error_noreturn(E_ERROR, "Cannot use object as array");
744 		}
745 		Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC);
746 	}
747 
748 	if (retval && !EG(exception)) {
749 		*retval = value;
750 		PZVAL_LOCK(value);
751 	}
752 	zval_ptr_dtor(&value);
753 	FREE_OP_IF_VAR(free_value);
754 }
755 
zend_assign_to_string_offset(const temp_variable * T,const zval * value,int value_type TSRMLS_DC)756 static inline int zend_assign_to_string_offset(const temp_variable *T, const zval *value, int value_type TSRMLS_DC)
757 {
758 	if (Z_TYPE_P(T->str_offset.str) == IS_STRING) {
759 
760 		if (((int)T->str_offset.offset < 0)) {
761 			zend_error(E_WARNING, "Illegal string offset:  %d", T->str_offset.offset);
762 			return 0;
763 		}
764 
765 		if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) {
766 			if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) {
767 				char *tmp = (char *) emalloc(T->str_offset.offset+1+1);
768 
769 				memcpy(tmp, Z_STRVAL_P(T->str_offset.str), Z_STRLEN_P(T->str_offset.str)+1);
770 				Z_STRVAL_P(T->str_offset.str) = tmp;
771 			} else {
772 				Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1);
773 			}
774 			memset(Z_STRVAL_P(T->str_offset.str) + Z_STRLEN_P(T->str_offset.str),
775 			       ' ',
776 			       T->str_offset.offset - Z_STRLEN_P(T->str_offset.str));
777 			Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0;
778 			Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1;
779 		} else if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) {
780 			char *tmp = (char *) emalloc(Z_STRLEN_P(T->str_offset.str) + 1);
781 
782 			memcpy(tmp, Z_STRVAL_P(T->str_offset.str), Z_STRLEN_P(T->str_offset.str) + 1);
783 			Z_STRVAL_P(T->str_offset.str) = tmp;
784 		}
785 
786 		if (Z_TYPE_P(value) != IS_STRING) {
787 			zval tmp;
788 
789 			ZVAL_COPY_VALUE(&tmp, value);
790 			if (value_type != IS_TMP_VAR) {
791 				zval_copy_ctor(&tmp);
792 			}
793 			convert_to_string(&tmp);
794 			Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL(tmp)[0];
795 			STR_FREE(Z_STRVAL(tmp));
796 		} else {
797 			Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset] = Z_STRVAL_P(value)[0];
798 			if (value_type == IS_TMP_VAR) {
799 				/* we can safely free final_value here
800 				 * because separation is done only
801 				 * in case value_type == IS_VAR */
802 				STR_FREE(Z_STRVAL_P(value));
803 			}
804 		}
805 		/*
806 		 * the value of an assignment to a string offset is undefined
807 		T(result->u.var).var = &T->str_offset.str;
808 		*/
809 	}
810 	return 1;
811 }
812 
813 
zend_assign_tmp_to_variable(zval ** variable_ptr_ptr,zval * value TSRMLS_DC)814 static inline zval* zend_assign_tmp_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
815 {
816 	zval *variable_ptr = *variable_ptr_ptr;
817 	zval garbage;
818 
819 	if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
820 	    UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
821 		Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
822 		return variable_ptr;
823 	}
824 
825  	if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1) &&
826  	    EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
827  	    /* we need to split */
828 		Z_DELREF_P(variable_ptr);
829 		GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
830 		ALLOC_ZVAL(variable_ptr);
831 		INIT_PZVAL_COPY(variable_ptr, value);
832 		*variable_ptr_ptr = variable_ptr;
833 		return variable_ptr;
834 	} else {
835 		if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
836 			/* nothing to destroy */
837 			ZVAL_COPY_VALUE(variable_ptr, value);
838 		} else {
839 			ZVAL_COPY_VALUE(&garbage, variable_ptr);
840 			ZVAL_COPY_VALUE(variable_ptr, value);
841 			_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
842 		}
843 		return variable_ptr;
844 	}
845 }
846 
zend_assign_const_to_variable(zval ** variable_ptr_ptr,zval * value TSRMLS_DC)847 static inline zval* zend_assign_const_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
848 {
849 	zval *variable_ptr = *variable_ptr_ptr;
850 	zval garbage;
851 
852 	if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
853 	    UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
854 		Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
855 		return variable_ptr;
856 	}
857 
858  	if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1) &&
859  	    EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
860 		/* we need to split */
861 		Z_DELREF_P(variable_ptr);
862 		GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
863 		ALLOC_ZVAL(variable_ptr);
864 		INIT_PZVAL_COPY(variable_ptr, value);
865 		zval_copy_ctor(variable_ptr);
866 		*variable_ptr_ptr = variable_ptr;
867 		return variable_ptr;
868  	} else {
869 		if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
870 			/* nothing to destroy */
871 			ZVAL_COPY_VALUE(variable_ptr, value);
872 			zendi_zval_copy_ctor(*variable_ptr);
873 		} else {
874 			ZVAL_COPY_VALUE(&garbage, variable_ptr);
875 			ZVAL_COPY_VALUE(variable_ptr, value);
876 			zendi_zval_copy_ctor(*variable_ptr);
877 			_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
878 		}
879 		return variable_ptr;
880 	}
881 }
882 
zend_assign_to_variable(zval ** variable_ptr_ptr,zval * value TSRMLS_DC)883 static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
884 {
885 	zval *variable_ptr = *variable_ptr_ptr;
886 	zval garbage;
887 
888 	if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
889 	    UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
890 		Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
891 		return variable_ptr;
892 	}
893 
894  	if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
895 		if (Z_REFCOUNT_P(variable_ptr)==1) {
896 			if (UNEXPECTED(variable_ptr == value)) {
897 				return variable_ptr;
898 			} else if (EXPECTED(!PZVAL_IS_REF(value))) {
899 				Z_ADDREF_P(value);
900 				*variable_ptr_ptr = value;
901 				ZEND_ASSERT(variable_ptr != &EG(uninitialized_zval));
902 				GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
903 				zval_dtor(variable_ptr);
904 				efree(variable_ptr);
905 				return value;
906 			} else {
907 				goto copy_value;
908 			}
909 		} else { /* we need to split */
910 			Z_DELREF_P(variable_ptr);
911 			GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
912 			if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) {
913 				ALLOC_ZVAL(variable_ptr);
914 				*variable_ptr_ptr = variable_ptr;
915 				INIT_PZVAL_COPY(variable_ptr, value);
916 				zval_copy_ctor(variable_ptr);
917 				return variable_ptr;
918 			} else {
919 				*variable_ptr_ptr = value;
920 				Z_ADDREF_P(value);
921 				Z_UNSET_ISREF_P(value);
922 				return value;
923 			}
924 		}
925  	} else {
926 		if (EXPECTED(variable_ptr != value)) {
927 copy_value:
928 			if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
929 				/* nothing to destroy */
930 				ZVAL_COPY_VALUE(variable_ptr, value);
931 				zendi_zval_copy_ctor(*variable_ptr);
932 			} else {
933 				ZVAL_COPY_VALUE(&garbage, variable_ptr);
934 				ZVAL_COPY_VALUE(variable_ptr, value);
935 				zendi_zval_copy_ctor(*variable_ptr);
936 				_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
937 			}
938 		}
939 		return variable_ptr;
940 	}
941 }
942 
943 /* Utility Functions for Extensions */
zend_extension_statement_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)944 static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
945 {
946 	if (extension->statement_handler) {
947 		extension->statement_handler(op_array);
948 	}
949 }
950 
951 
zend_extension_fcall_begin_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)952 static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
953 {
954 	if (extension->fcall_begin_handler) {
955 		extension->fcall_begin_handler(op_array);
956 	}
957 }
958 
959 
zend_extension_fcall_end_handler(const zend_extension * extension,zend_op_array * op_array TSRMLS_DC)960 static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
961 {
962 	if (extension->fcall_end_handler) {
963 		extension->fcall_end_handler(op_array);
964 	}
965 }
966 
967 
zend_get_target_symbol_table(int fetch_type TSRMLS_DC)968 static inline HashTable *zend_get_target_symbol_table(int fetch_type TSRMLS_DC)
969 {
970 	switch (fetch_type) {
971 		case ZEND_FETCH_LOCAL:
972 			if (!EG(active_symbol_table)) {
973 				zend_rebuild_symbol_table(TSRMLS_C);
974 			}
975 			return EG(active_symbol_table);
976 			break;
977 		case ZEND_FETCH_GLOBAL:
978 		case ZEND_FETCH_GLOBAL_LOCK:
979 			return &EG(symbol_table);
980 			break;
981 		case ZEND_FETCH_STATIC:
982 			if (!EG(active_op_array)->static_variables) {
983 				ALLOC_HASHTABLE(EG(active_op_array)->static_variables);
984 				zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
985 			}
986 			return EG(active_op_array)->static_variables;
987 			break;
988 		EMPTY_SWITCH_DEFAULT_CASE()
989 	}
990 	return NULL;
991 }
992 
zend_fetch_dimension_address_inner(HashTable * ht,const zval * dim,int dim_type,int type TSRMLS_DC)993 static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type TSRMLS_DC)
994 {
995 	zval **retval;
996 	char *offset_key;
997 	int offset_key_length;
998 	ulong hval;
999 
1000 	switch (dim->type) {
1001 		case IS_NULL:
1002 			offset_key = "";
1003 			offset_key_length = 0;
1004 			hval = zend_inline_hash_func("", 1);
1005 			goto fetch_string_dim;
1006 
1007 		case IS_STRING:
1008 
1009 			offset_key = dim->value.str.val;
1010 			offset_key_length = dim->value.str.len;
1011 
1012 			if (dim_type == IS_CONST) {
1013 				hval = Z_HASH_P(dim);
1014 			} else {
1015 				ZEND_HANDLE_NUMERIC_EX(offset_key, offset_key_length+1, hval, goto num_index);
1016 				if (IS_INTERNED(offset_key)) {
1017 					hval = INTERNED_HASH(offset_key);
1018 				} else {
1019 					hval = zend_hash_func(offset_key, offset_key_length+1);
1020 				}
1021 			}
1022 fetch_string_dim:
1023 			if (zend_hash_quick_find(ht, offset_key, offset_key_length+1, hval, (void **) &retval) == FAILURE) {
1024 				switch (type) {
1025 					case BP_VAR_R:
1026 						zend_error(E_NOTICE, "Undefined index: %s", offset_key);
1027 						/* break missing intentionally */
1028 					case BP_VAR_UNSET:
1029 					case BP_VAR_IS:
1030 						retval = &EG(uninitialized_zval_ptr);
1031 						break;
1032 					case BP_VAR_RW:
1033 						zend_error(E_NOTICE,"Undefined index: %s", offset_key);
1034 						/* break missing intentionally */
1035 					case BP_VAR_W: {
1036 							zval *new_zval = &EG(uninitialized_zval);
1037 
1038 							Z_ADDREF_P(new_zval);
1039 							zend_hash_quick_update(ht, offset_key, offset_key_length+1, hval, &new_zval, sizeof(zval *), (void **) &retval);
1040 						}
1041 						break;
1042 				}
1043 			}
1044 			break;
1045 		case IS_DOUBLE:
1046 			hval = zend_dval_to_lval(Z_DVAL_P(dim));
1047 			goto num_index;
1048 		case IS_RESOURCE:
1049 			zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(dim), Z_LVAL_P(dim));
1050 			/* Fall Through */
1051 		case IS_BOOL:
1052 		case IS_LONG:
1053 			hval = Z_LVAL_P(dim);
1054 num_index:
1055 			if (zend_hash_index_find(ht, hval, (void **) &retval) == FAILURE) {
1056 				switch (type) {
1057 					case BP_VAR_R:
1058 						zend_error(E_NOTICE,"Undefined offset: %ld", hval);
1059 						/* break missing intentionally */
1060 					case BP_VAR_UNSET:
1061 					case BP_VAR_IS:
1062 						retval = &EG(uninitialized_zval_ptr);
1063 						break;
1064 					case BP_VAR_RW:
1065 						zend_error(E_NOTICE,"Undefined offset: %ld", hval);
1066 						/* break missing intentionally */
1067 					case BP_VAR_W: {
1068 						zval *new_zval = &EG(uninitialized_zval);
1069 
1070 						Z_ADDREF_P(new_zval);
1071 						zend_hash_index_update(ht, hval, &new_zval, sizeof(zval *), (void **) &retval);
1072 					}
1073 					break;
1074 				}
1075 			}
1076 			break;
1077 
1078 		default:
1079 			zend_error(E_WARNING, "Illegal offset type");
1080 			return (type == BP_VAR_W || type == BP_VAR_RW) ?
1081 				&EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
1082 	}
1083 	return retval;
1084 }
1085 
zend_fetch_dimension_address(temp_variable * result,zval ** container_ptr,zval * dim,int dim_type,int type TSRMLS_DC)1086 static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_type, int type TSRMLS_DC)
1087 {
1088 	zval *container = *container_ptr;
1089 	zval **retval;
1090 
1091 	switch (Z_TYPE_P(container)) {
1092 
1093 		case IS_ARRAY:
1094 			if (type != BP_VAR_UNSET && Z_REFCOUNT_P(container)>1 && !PZVAL_IS_REF(container)) {
1095 				SEPARATE_ZVAL(container_ptr);
1096 				container = *container_ptr;
1097 			}
1098 fetch_from_array:
1099 			if (dim == NULL) {
1100 				zval *new_zval = &EG(uninitialized_zval);
1101 
1102 				Z_ADDREF_P(new_zval);
1103 				if (zend_hash_next_index_insert(Z_ARRVAL_P(container), &new_zval, sizeof(zval *), (void **) &retval) == FAILURE) {
1104 					zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
1105 					retval = &EG(error_zval_ptr);
1106 					Z_DELREF_P(new_zval);
1107 				}
1108 			} else {
1109 				retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1110 			}
1111 			result->var.ptr_ptr = retval;
1112 			PZVAL_LOCK(*retval);
1113 			return;
1114 			break;
1115 
1116 		case IS_NULL:
1117 			if (container == &EG(error_zval)) {
1118 				result->var.ptr_ptr = &EG(error_zval_ptr);
1119 				PZVAL_LOCK(EG(error_zval_ptr));
1120 			} else if (type != BP_VAR_UNSET) {
1121 convert_to_array:
1122 				if (!PZVAL_IS_REF(container)) {
1123 					SEPARATE_ZVAL(container_ptr);
1124 					container = *container_ptr;
1125 				}
1126 				zval_dtor(container);
1127 				array_init(container);
1128 				goto fetch_from_array;
1129 			} else {
1130 				/* for read-mode only */
1131 				result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
1132 				PZVAL_LOCK(EG(uninitialized_zval_ptr));
1133 			}
1134 			return;
1135 			break;
1136 
1137 		case IS_STRING: {
1138 				zval tmp;
1139 
1140 				if (type != BP_VAR_UNSET && Z_STRLEN_P(container)==0) {
1141 					goto convert_to_array;
1142 				}
1143 				if (dim == NULL) {
1144 					zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
1145 				}
1146 
1147 				if (type != BP_VAR_UNSET) {
1148 					SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
1149 				}
1150 
1151 				if (Z_TYPE_P(dim) != IS_LONG) {
1152 
1153 					switch(Z_TYPE_P(dim)) {
1154 						/* case IS_LONG: */
1155 						case IS_STRING:
1156 							if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1157 								break;
1158 							}
1159 							if (type != BP_VAR_UNSET) {
1160 								zend_error(E_WARNING, "Illegal string offset '%s'", dim->value.str.val);
1161 							}
1162 
1163 							break;
1164 						case IS_DOUBLE:
1165 						case IS_NULL:
1166 						case IS_BOOL:
1167 							zend_error(E_NOTICE, "String offset cast occurred");
1168 							break;
1169 						default:
1170 							zend_error(E_WARNING, "Illegal offset type");
1171 							break;
1172 					}
1173 
1174 					tmp = *dim;
1175 					zval_copy_ctor(&tmp);
1176 					convert_to_long(&tmp);
1177 					dim = &tmp;
1178 				}
1179 				container = *container_ptr;
1180 				result->str_offset.str = container;
1181 				PZVAL_LOCK(container);
1182 				result->str_offset.offset = Z_LVAL_P(dim);
1183 				result->str_offset.ptr_ptr = NULL;
1184 				return;
1185 			}
1186 			break;
1187 
1188 		case IS_OBJECT:
1189 			if (!Z_OBJ_HT_P(container)->read_dimension) {
1190 				zend_error_noreturn(E_ERROR, "Cannot use object as array");
1191 			} else {
1192 				zval *overloaded_result;
1193 
1194 				if (dim_type == IS_TMP_VAR) {
1195 					zval *orig = dim;
1196 					MAKE_REAL_ZVAL_PTR(dim);
1197 					ZVAL_NULL(orig);
1198 				}
1199 				overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
1200 
1201 				if (overloaded_result) {
1202 					if (!Z_ISREF_P(overloaded_result)) {
1203 						if (Z_REFCOUNT_P(overloaded_result) > 0) {
1204 							zval *tmp = overloaded_result;
1205 
1206 							ALLOC_ZVAL(overloaded_result);
1207 							ZVAL_COPY_VALUE(overloaded_result, tmp);
1208 							zval_copy_ctor(overloaded_result);
1209 							Z_UNSET_ISREF_P(overloaded_result);
1210 							Z_SET_REFCOUNT_P(overloaded_result, 0);
1211 						}
1212 						if (Z_TYPE_P(overloaded_result) != IS_OBJECT) {
1213 							zend_class_entry *ce = Z_OBJCE_P(container);
1214 							zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ce->name);
1215 						}
1216 					}
1217 					retval = &overloaded_result;
1218 				} else {
1219 					retval = &EG(error_zval_ptr);
1220 				}
1221 				AI_SET_PTR(result, *retval);
1222 				PZVAL_LOCK(*retval);
1223 				if (dim_type == IS_TMP_VAR) {
1224 					zval_ptr_dtor(&dim);
1225 				}
1226 			}
1227 			return;
1228 			break;
1229 
1230 		case IS_BOOL:
1231 			if (type != BP_VAR_UNSET && Z_LVAL_P(container)==0) {
1232 				goto convert_to_array;
1233 			}
1234 			/* break missing intentionally */
1235 
1236 		default:
1237 			if (type == BP_VAR_UNSET) {
1238 				zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
1239 				AI_SET_PTR(result, &EG(uninitialized_zval));
1240 				PZVAL_LOCK(&EG(uninitialized_zval));
1241 			} else {
1242 				zend_error(E_WARNING, "Cannot use a scalar value as an array");
1243 				result->var.ptr_ptr = &EG(error_zval_ptr);
1244 				PZVAL_LOCK(EG(error_zval_ptr));
1245 			}
1246 			break;
1247 	}
1248 }
1249 
zend_fetch_dimension_address_read(temp_variable * result,zval * container,zval * dim,int dim_type,int type TSRMLS_DC)1250 static void zend_fetch_dimension_address_read(temp_variable *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC)
1251 {
1252 	zval **retval;
1253 
1254 	switch (Z_TYPE_P(container)) {
1255 
1256 		case IS_ARRAY:
1257 			retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1258 			AI_SET_PTR(result, *retval);
1259 			PZVAL_LOCK(*retval);
1260 			return;
1261 
1262 		case IS_NULL:
1263 			AI_SET_PTR(result, &EG(uninitialized_zval));
1264 			PZVAL_LOCK(&EG(uninitialized_zval));
1265 			return;
1266 
1267 		case IS_STRING: {
1268 				zval tmp;
1269 				zval *ptr;
1270 
1271 				if (Z_TYPE_P(dim) != IS_LONG) {
1272 					switch(Z_TYPE_P(dim)) {
1273 						/* case IS_LONG: */
1274 						case IS_STRING:
1275 							if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
1276 								break;
1277 							}
1278 							if (type != BP_VAR_IS) {
1279 								zend_error(E_WARNING, "Illegal string offset '%s'", dim->value.str.val);
1280 							}
1281 							break;
1282 						case IS_DOUBLE:
1283 						case IS_NULL:
1284 						case IS_BOOL:
1285 							if (type != BP_VAR_IS) {
1286 								zend_error(E_NOTICE, "String offset cast occurred");
1287 							}
1288 							break;
1289 						default:
1290 							zend_error(E_WARNING, "Illegal offset type");
1291 							break;
1292 					}
1293 
1294 					ZVAL_COPY_VALUE(&tmp, dim);
1295 					zval_copy_ctor(&tmp);
1296 					convert_to_long(&tmp);
1297 					dim = &tmp;
1298 				}
1299 
1300 				ALLOC_ZVAL(ptr);
1301 				INIT_PZVAL(ptr);
1302 				Z_TYPE_P(ptr) = IS_STRING;
1303 
1304 				if (Z_LVAL_P(dim) < 0 || Z_STRLEN_P(container) <= Z_LVAL_P(dim)) {
1305 					if (type != BP_VAR_IS) {
1306 						zend_error(E_NOTICE, "Uninitialized string offset: %ld", Z_LVAL_P(dim));
1307 					}
1308 					Z_STRVAL_P(ptr) = STR_EMPTY_ALLOC();
1309 					Z_STRLEN_P(ptr) = 0;
1310 				} else {
1311 					Z_STRVAL_P(ptr) = (char*)emalloc(2);
1312 					Z_STRVAL_P(ptr)[0] = Z_STRVAL_P(container)[Z_LVAL_P(dim)];
1313 					Z_STRVAL_P(ptr)[1] = 0;
1314 					Z_STRLEN_P(ptr) = 1;
1315 				}
1316 				AI_SET_PTR(result, ptr);
1317 				return;
1318 			}
1319 			break;
1320 
1321 		case IS_OBJECT:
1322 			if (!Z_OBJ_HT_P(container)->read_dimension) {
1323 				zend_error_noreturn(E_ERROR, "Cannot use object as array");
1324 			} else {
1325 				zval *overloaded_result;
1326 
1327 				if (dim_type == IS_TMP_VAR) {
1328 					zval *orig = dim;
1329 					MAKE_REAL_ZVAL_PTR(dim);
1330 					ZVAL_NULL(orig);
1331 				}
1332 				overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim, type TSRMLS_CC);
1333 
1334 				if (overloaded_result) {
1335 					AI_SET_PTR(result, overloaded_result);
1336 					PZVAL_LOCK(overloaded_result);
1337 				} else if (result) {
1338 					AI_SET_PTR(result, &EG(uninitialized_zval));
1339 					PZVAL_LOCK(&EG(uninitialized_zval));
1340 				}
1341 				if (dim_type == IS_TMP_VAR) {
1342 					zval_ptr_dtor(&dim);
1343 				}
1344 			}
1345 			return;
1346 
1347 		default:
1348 			AI_SET_PTR(result, &EG(uninitialized_zval));
1349 			PZVAL_LOCK(&EG(uninitialized_zval));
1350 			return;
1351 	}
1352 }
1353 
zend_fetch_property_address(temp_variable * result,zval ** container_ptr,zval * prop_ptr,const zend_literal * key,int type TSRMLS_DC)1354 static void zend_fetch_property_address(temp_variable *result, zval **container_ptr, zval *prop_ptr, const zend_literal *key, int type TSRMLS_DC)
1355 {
1356 	zval *container = *container_ptr;;
1357 
1358 	if (Z_TYPE_P(container) != IS_OBJECT) {
1359 		if (container == &EG(error_zval)) {
1360 			result->var.ptr_ptr = &EG(error_zval_ptr);
1361 			PZVAL_LOCK(EG(error_zval_ptr));
1362 			return;
1363 		}
1364 
1365 		/* this should modify object only if it's empty */
1366 		if (type != BP_VAR_UNSET &&
1367 		    ((Z_TYPE_P(container) == IS_NULL ||
1368 		     (Z_TYPE_P(container) == IS_BOOL && Z_LVAL_P(container)==0) ||
1369 		     (Z_TYPE_P(container) == IS_STRING && Z_STRLEN_P(container)==0)))) {
1370 			if (!PZVAL_IS_REF(container)) {
1371 				SEPARATE_ZVAL(container_ptr);
1372 				container = *container_ptr;
1373 			}
1374 			object_init(container);
1375 		} else {
1376 			zend_error(E_WARNING, "Attempt to modify property of non-object");
1377 			result->var.ptr_ptr = &EG(error_zval_ptr);
1378 			PZVAL_LOCK(EG(error_zval_ptr));
1379 			return;
1380 		}
1381 	}
1382 
1383 	if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) {
1384 		zval **ptr_ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, key TSRMLS_CC);
1385 		if (NULL == ptr_ptr) {
1386 			zval *ptr;
1387 
1388 			if (Z_OBJ_HT_P(container)->read_property &&
1389 				(ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC)) != NULL) {
1390 				AI_SET_PTR(result, ptr);
1391 				PZVAL_LOCK(ptr);
1392 			} else {
1393 				zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access");
1394 			}
1395 		} else {
1396 			result->var.ptr_ptr = ptr_ptr;
1397 			PZVAL_LOCK(*ptr_ptr);
1398 		}
1399 	} else if (Z_OBJ_HT_P(container)->read_property) {
1400 		zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC);
1401 
1402 		AI_SET_PTR(result, ptr);
1403 		PZVAL_LOCK(ptr);
1404 	} else {
1405 		zend_error(E_WARNING, "This object doesn't support property references");
1406 		result->var.ptr_ptr = &EG(error_zval_ptr);
1407 		PZVAL_LOCK(EG(error_zval_ptr));
1408 	}
1409 }
1410 
zend_brk_cont(int nest_levels,int array_offset,const zend_op_array * op_array,const zend_execute_data * execute_data TSRMLS_DC)1411 static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_offset, const zend_op_array *op_array, const zend_execute_data *execute_data TSRMLS_DC)
1412 {
1413 	int original_nest_levels = nest_levels;
1414 	zend_brk_cont_element *jmp_to;
1415 
1416 	do {
1417 		if (array_offset==-1) {
1418 			zend_error_noreturn(E_ERROR, "Cannot break/continue %d level%s", original_nest_levels, (original_nest_levels == 1) ? "" : "s");
1419 		}
1420 		jmp_to = &op_array->brk_cont_array[array_offset];
1421 		if (nest_levels>1) {
1422 			zend_op *brk_opline = &op_array->opcodes[jmp_to->brk];
1423 
1424 			switch (brk_opline->opcode) {
1425 				case ZEND_SWITCH_FREE:
1426 					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1427 						zval_ptr_dtor(&EX_T(brk_opline->op1.var).var.ptr);
1428 					}
1429 					break;
1430 				case ZEND_FREE:
1431 					if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
1432 						zendi_zval_dtor(EX_T(brk_opline->op1.var).tmp_var);
1433 					}
1434 					break;
1435 			}
1436 		}
1437 		array_offset = jmp_to->parent;
1438 	} while (--nest_levels > 0);
1439 	return jmp_to;
1440 }
1441 
1442 #if ZEND_INTENSIVE_DEBUGGING
1443 
1444 #define CHECK_SYMBOL_TABLES()														\
1445 	zend_hash_apply(&EG(symbol_table), (apply_func_t) zend_check_symbol TSRMLS_CC);	\
1446 	if (&EG(symbol_table)!=EG(active_symbol_table)) {								\
1447 		zend_hash_apply(EG(active_symbol_table), (apply_func_t) zend_check_symbol TSRMLS_CC);	\
1448 	}
1449 
zend_check_symbol(zval ** pz TSRMLS_DC)1450 static int zend_check_symbol(zval **pz TSRMLS_DC)
1451 {
1452 	if (Z_TYPE_PP(pz) > 9) {
1453 		fprintf(stderr, "Warning!  %x has invalid type!\n", *pz);
1454 /* See http://support.microsoft.com/kb/190351 */
1455 #ifdef PHP_WIN32
1456 		fflush(stderr);
1457 #endif
1458 	} else if (Z_TYPE_PP(pz) == IS_ARRAY) {
1459 		zend_hash_apply(Z_ARRVAL_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
1460 	} else if (Z_TYPE_PP(pz) == IS_OBJECT) {
1461 
1462 		/* OBJ-TBI - doesn't support new object model! */
1463 		zend_hash_apply(Z_OBJPROP_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
1464 	}
1465 
1466 	return 0;
1467 }
1468 
1469 
1470 #else
1471 #define CHECK_SYMBOL_TABLES()
1472 #endif
1473 
1474 ZEND_API opcode_handler_t *zend_opcode_handlers;
1475 
execute_internal(zend_execute_data * execute_data_ptr,zend_fcall_info * fci,int return_value_used TSRMLS_DC)1476 ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, zend_fcall_info *fci, int return_value_used TSRMLS_DC)
1477 {
1478 	if(fci != NULL) {
1479 		((zend_internal_function *) execute_data_ptr->function_state.function)->handler(fci->param_count,
1480 				*fci->retval_ptr_ptr, fci->retval_ptr_ptr, fci->object_ptr, 1 TSRMLS_CC);
1481 
1482 	} else {
1483 		zval **return_value_ptr = &EX_TMP_VAR(execute_data_ptr, execute_data_ptr->opline->result.var)->var.ptr;
1484 		((zend_internal_function *) execute_data_ptr->function_state.function)->handler(execute_data_ptr->opline->extended_value, *return_value_ptr,
1485 					(execute_data_ptr->function_state.function->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)?return_value_ptr:NULL,
1486 					execute_data_ptr->object, return_value_used TSRMLS_CC);
1487 	}
1488 }
1489 
zend_clean_and_cache_symbol_table(HashTable * symbol_table TSRMLS_DC)1490 void zend_clean_and_cache_symbol_table(HashTable *symbol_table TSRMLS_DC) /* {{{ */
1491 {
1492 	if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) {
1493 		zend_hash_destroy(symbol_table);
1494 		FREE_HASHTABLE(symbol_table);
1495 	} else {
1496 		/* clean before putting into the cache, since clean
1497 		   could call dtors, which could use cached hash */
1498 		zend_hash_clean(symbol_table);
1499 		*(++EG(symtable_cache_ptr)) = symbol_table;
1500 	}
1501 }
1502 /* }}} */
1503 
i_free_compiled_variables(zend_execute_data * execute_data)1504 static zend_always_inline void i_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
1505 {
1506 	zval ***cv = EX_CV_NUM(execute_data, 0);
1507 	zval ***end = cv + EX(op_array)->last_var;
1508 	while (cv != end) {
1509 		if (*cv) {
1510 			zval_ptr_dtor(*cv);
1511 		}
1512 		cv++;
1513  	}
1514 }
1515 /* }}} */
1516 
zend_free_compiled_variables(zend_execute_data * execute_data)1517 void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
1518 {
1519 	i_free_compiled_variables(execute_data);
1520 }
1521 /* }}} */
1522 
1523 /*
1524  * Stack Frame Layout (the whole stack frame is allocated at once)
1525  * ==================
1526  *
1527  *                             +========================================+
1528  *                             | zend_execute_data                      |<---+
1529  *                             |     EX(function_state).arguments       |--+ |
1530  *                             |  ...                                   |  | |
1531  *                             | ARGUMENT [1]                           |  | |
1532  *                             | ...                                    |  | |
1533  *                             | ARGUMENT [ARGS_NUMBER]                 |  | |
1534  *                             | ARGS_NUMBER                            |<-+ |
1535  *                             +========================================+    |
1536  *                                                                           |
1537  *                             +========================================+    |
1538  *                             | TMP_VAR[op_arrat->T-1]                 |    |
1539  *                             | ...                                    |    |
1540  *     EX_TMP_VAR_NUM(0) ----> | TMP_VAR[0]                             |    |
1541  *                             +----------------------------------------+    |
1542  * EG(current_execute_data) -> | zend_execute_data                      |    |
1543  *                             |     EX(prev_execute_data)              |----+
1544  *                             +----------------------------------------+
1545  *     EX_CV_NUM(0) ---------> | CV[0]                                  |--+
1546  *                             | ...                                    |  |
1547  *                             | CV[op_array->last_var-1]               |  |
1548  *                             +----------------------------------------+  |
1549  *                             | Optional slot for CV[0] zval*          |<-+
1550  *                             | ...                                    |
1551  *                             | ...for CV [op_array->last_var-1] zval* |
1552  *                             +----------------------------------------+
1553  *           EX(call_slots) -> | CALL_SLOT[0]                           |
1554  *                             | ...                                    |
1555  *                             | CALL_SLOT[op_array->nested_calls-1]    |
1556  *                             +----------------------------------------+
1557  * zend_vm_stack_frame_base -> | ARGUMENTS STACK [0]                    |
1558  *                             | ...                                    |
1559  * zend_vm_stack_top --------> | ...                                    |
1560  *                             | ...                                    |
1561  *                             | ARGUMENTS STACK [op_array->used_stack] |
1562  *                             +----------------------------------------+
1563  */
1564 
i_create_execute_data_from_op_array(zend_op_array * op_array,zend_bool nested TSRMLS_DC)1565 static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */
1566 {
1567 	zend_execute_data *execute_data;
1568 
1569 	/*
1570 	 * When allocating the execute_data, memory for compiled variables and
1571 	 * temporary variables is also allocated before and after the actual
1572 	 * zend_execute_data struct. In addition we also allocate space to store
1573 	 * information about syntactically nested called functions and actual
1574 	 * parameters. op_array->last_var specifies the number of compiled
1575 	 * variables and op_array->T is the number of temporary variables. If there
1576 	 * is no symbol table, then twice as much memory is allocated for compiled
1577 	 * variables. In that case the first half contains zval**s and the second
1578 	 * half the actual zval*s (which would otherwise be in the symbol table).
1579 	 */
1580 	size_t execute_data_size = ZEND_MM_ALIGNED_SIZE(sizeof(zend_execute_data));
1581 	size_t CVs_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval **) * op_array->last_var * (EG(active_symbol_table) ? 1 : 2));
1582 	size_t Ts_size = ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * op_array->T;
1583 	size_t call_slots_size = ZEND_MM_ALIGNED_SIZE(sizeof(call_slot)) * op_array->nested_calls;
1584 	size_t stack_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * op_array->used_stack;
1585 	size_t total_size = execute_data_size + Ts_size + CVs_size + call_slots_size + stack_size;
1586 
1587 	/*
1588 	 * Normally the execute_data is allocated on the VM stack (because it does
1589 	 * not actually do any allocation and thus is faster). For generators
1590 	 * though this behavior would be suboptimal, because the (rather large)
1591 	 * structure would have to be copied back and forth every time execution is
1592 	 * suspended or resumed. That's why for generators the execution context
1593 	 * is allocated using a separate VM stack, thus allowing to save and
1594 	 * restore it simply by replacing a pointer. The same segment also keeps
1595 	 * a copy of previous execute_data and passed parameters.
1596 	 */
1597 	if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
1598 		/* Prepend the regular stack frame with a copy of prev_execute_data
1599 		 * and the passed arguments
1600 		 */
1601 		int args_count = zend_vm_stack_get_args_count_ex(EG(current_execute_data));
1602 		size_t args_size = ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * (args_count + 1);
1603 
1604 		total_size += args_size + execute_data_size;
1605 
1606 		EG(argument_stack) = zend_vm_stack_new_page((total_size + (sizeof(void*) - 1)) / sizeof(void*));
1607 		EG(argument_stack)->prev = NULL;
1608 		execute_data = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size + execute_data_size + Ts_size);
1609 
1610 		/* copy prev_execute_data */
1611 		EX(prev_execute_data) = (zend_execute_data*)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + args_size);
1612 		memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
1613 		EX(prev_execute_data)->function_state.function = (zend_function*)op_array;
1614 		EX(prev_execute_data)->function_state.arguments = (void**)((char*)ZEND_VM_STACK_ELEMETS(EG(argument_stack)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval*)) * args_count);
1615 
1616 		/* copy arguments */
1617 		*EX(prev_execute_data)->function_state.arguments = (void*)(zend_uintptr_t)args_count;
1618 		if (args_count > 0) {
1619 			zval **arg_src = (zval**)zend_vm_stack_get_arg_ex(EG(current_execute_data), 1);
1620 			zval **arg_dst = (zval**)zend_vm_stack_get_arg_ex(EX(prev_execute_data), 1);
1621 			int i;
1622 
1623 			for (i = 0; i < args_count; i++) {
1624 				arg_dst[i] = arg_src[i];
1625 				Z_ADDREF_P(arg_dst[i]);
1626 			}
1627 		}
1628 	} else {
1629 		execute_data = zend_vm_stack_alloc(total_size TSRMLS_CC);
1630 		execute_data = (zend_execute_data*)((char*)execute_data + Ts_size);
1631 		EX(prev_execute_data) = EG(current_execute_data);
1632 	}
1633 
1634 	memset(EX_CV_NUM(execute_data, 0), 0, sizeof(zval **) * op_array->last_var);
1635 
1636 	EX(call_slots) = (call_slot*)((char *)execute_data + execute_data_size + CVs_size);
1637 
1638 
1639 	EX(op_array) = op_array;
1640 
1641 	EG(argument_stack)->top = zend_vm_stack_frame_base(execute_data);
1642 
1643 	EX(object) = NULL;
1644 	EX(current_this) = NULL;
1645 	EX(old_error_reporting) = NULL;
1646 	EX(symbol_table) = EG(active_symbol_table);
1647 	EX(call) = NULL;
1648 	EG(current_execute_data) = execute_data;
1649 	EX(nested) = nested;
1650 
1651 	if (!op_array->run_time_cache && op_array->last_cache_slot) {
1652 		op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
1653 	}
1654 
1655 	if (op_array->this_var != -1 && EG(This)) {
1656  		Z_ADDREF_P(EG(This)); /* For $this pointer */
1657 		if (!EG(active_symbol_table)) {
1658 			EX_CV(op_array->this_var) = (zval **) EX_CV_NUM(execute_data, op_array->last_var + op_array->this_var);
1659 			*EX_CV(op_array->this_var) = EG(This);
1660 		} else {
1661 			if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void **) EX_CV_NUM(execute_data, op_array->this_var))==FAILURE) {
1662 				Z_DELREF_P(EG(This));
1663 			}
1664 		}
1665 	}
1666 
1667 	EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes;
1668 	EG(opline_ptr) = &EX(opline);
1669 
1670 	EX(function_state).function = (zend_function *) op_array;
1671 	EX(function_state).arguments = NULL;
1672 
1673 	return execute_data;
1674 }
1675 /* }}} */
1676 
zend_create_execute_data_from_op_array(zend_op_array * op_array,zend_bool nested TSRMLS_DC)1677 zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) /* {{{ */
1678 {
1679 	return i_create_execute_data_from_op_array(op_array, nested TSRMLS_CC);
1680 }
1681 /* }}} */
1682 
1683 #define ZEND_VM_NEXT_OPCODE() \
1684 	CHECK_SYMBOL_TABLES() \
1685 	ZEND_VM_INC_OPCODE(); \
1686 	ZEND_VM_CONTINUE()
1687 
1688 #define ZEND_VM_SET_OPCODE(new_op) \
1689 	CHECK_SYMBOL_TABLES() \
1690 	OPLINE = new_op
1691 
1692 #define ZEND_VM_JMP(new_op) \
1693 	if (EXPECTED(!EG(exception))) { \
1694 		ZEND_VM_SET_OPCODE(new_op); \
1695 	} else { \
1696 		LOAD_OPLINE(); \
1697 	} \
1698 	ZEND_VM_CONTINUE()
1699 
1700 #define ZEND_VM_INC_OPCODE() \
1701 	OPLINE++
1702 
1703 #ifdef __GNUC__
1704 # define ZEND_VM_GUARD(name) __asm__("#" #name)
1705 #else
1706 # define ZEND_VM_GUARD(name)
1707 #endif
1708 
1709 #include "zend_vm_execute.h"
1710 
zend_set_user_opcode_handler(zend_uchar opcode,user_opcode_handler_t handler)1711 ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
1712 {
1713 	if (opcode != ZEND_USER_OPCODE) {
1714 		if (handler == NULL) {
1715 			/* restore the original handler */
1716 			zend_user_opcodes[opcode] = opcode;
1717 		} else {
1718 			zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
1719 		}
1720 		zend_user_opcode_handlers[opcode] = handler;
1721 		return SUCCESS;
1722 	}
1723 	return FAILURE;
1724 }
1725 
zend_get_user_opcode_handler(zend_uchar opcode)1726 ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
1727 {
1728 	return zend_user_opcode_handlers[opcode];
1729 }
1730 
zend_get_zval_ptr(int op_type,const znode_op * node,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)1731 ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) {
1732 	return get_zval_ptr(op_type, node, execute_data, should_free, type);
1733 }
1734 
zend_get_zval_ptr_ptr(int op_type,const znode_op * node,const zend_execute_data * execute_data,zend_free_op * should_free,int type TSRMLS_DC)1735 ZEND_API zval **zend_get_zval_ptr_ptr(int op_type, const znode_op *node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) {
1736 	return get_zval_ptr_ptr(op_type, node, execute_data, should_free, type);
1737 }
1738 
1739 /*
1740  * Local variables:
1741  * tab-width: 4
1742  * c-basic-offset: 4
1743  * indent-tabs-mode: t
1744  * End:
1745  */
1746