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