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