1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #include <zend_language_parser.h>
23 #include "zend.h"
24 #include "zend_compile.h"
25 #include "zend_constants.h"
26 #include "zend_llist.h"
27 #include "zend_API.h"
28 #include "zend_exceptions.h"
29 #include "tsrm_virtual_cwd.h"
30 #include "zend_multibyte.h"
31 #include "zend_language_scanner.h"
32
33 #define CONSTANT_EX(op_array, op) \
34 (op_array)->literals[op].constant
35
36 #define CONSTANT(op) \
37 CONSTANT_EX(CG(active_op_array), op)
38
39 #define SET_NODE(target, src) do { \
40 target ## _type = (src)->op_type; \
41 if ((src)->op_type == IS_CONST) { \
42 target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); \
43 } else { \
44 target = (src)->u.op; \
45 } \
46 } while (0)
47
48 #define GET_NODE(target, src) do { \
49 (target)->op_type = src ## _type; \
50 if ((target)->op_type == IS_CONST) { \
51 (target)->u.constant = CONSTANT(src.constant); \
52 } else { \
53 (target)->u.op = src; \
54 (target)->EA = 0; \
55 } \
56 } while (0)
57
58 #define COPY_NODE(target, src) do { \
59 target ## _type = src ## _type; \
60 target = src; \
61 } while (0)
62
63 #define CALCULATE_LITERAL_HASH(num) do { \
64 if (IS_INTERNED(Z_STRVAL(CONSTANT(num)))) { \
65 Z_HASH_P(&CONSTANT(num)) = INTERNED_HASH(Z_STRVAL(CONSTANT(num))); \
66 } else { \
67 Z_HASH_P(&CONSTANT(num)) = zend_hash_func(Z_STRVAL(CONSTANT(num)), Z_STRLEN(CONSTANT(num))+1); \
68 } \
69 } while (0)
70
71 #define GET_CACHE_SLOT(literal) do { \
72 CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot++; \
73 if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \
74 CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \
75 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \
76 } \
77 } while (0)
78
79 #define POLYMORPHIC_CACHE_SLOT_SIZE 2
80
81 #define GET_POLYMORPHIC_CACHE_SLOT(literal) do { \
82 CG(active_op_array)->literals[literal].cache_slot = CG(active_op_array)->last_cache_slot; \
83 CG(active_op_array)->last_cache_slot += POLYMORPHIC_CACHE_SLOT_SIZE; \
84 if ((CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) && CG(active_op_array)->run_time_cache) { \
85 CG(active_op_array)->run_time_cache = erealloc(CG(active_op_array)->run_time_cache, CG(active_op_array)->last_cache_slot * sizeof(void*)); \
86 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 1] = NULL; \
87 CG(active_op_array)->run_time_cache[CG(active_op_array)->last_cache_slot - 2] = NULL; \
88 } \
89 } while (0)
90
91 #define FREE_POLYMORPHIC_CACHE_SLOT(literal) do { \
92 if (CG(active_op_array)->literals[literal].cache_slot != -1 && \
93 CG(active_op_array)->literals[literal].cache_slot == \
94 CG(active_op_array)->last_cache_slot - POLYMORPHIC_CACHE_SLOT_SIZE) { \
95 CG(active_op_array)->literals[literal].cache_slot = -1; \
96 CG(active_op_array)->last_cache_slot -= POLYMORPHIC_CACHE_SLOT_SIZE; \
97 } \
98 } while (0)
99
100 ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
101 ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
102
103 #ifndef ZTS
104 ZEND_API zend_compiler_globals compiler_globals;
105 ZEND_API zend_executor_globals executor_globals;
106 #endif
107
zend_duplicate_property_info(zend_property_info * property_info)108 static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
109 {
110 if (!IS_INTERNED(property_info->name)) {
111 property_info->name = estrndup(property_info->name, property_info->name_length);
112 }
113 if (property_info->doc_comment) {
114 property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len);
115 }
116 }
117 /* }}} */
118
zend_duplicate_property_info_internal(zend_property_info * property_info)119 static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
120 {
121 if (!IS_INTERNED(property_info->name)) {
122 property_info->name = zend_strndup(property_info->name, property_info->name_length);
123 }
124 }
125 /* }}} */
126
zend_destroy_property_info(zend_property_info * property_info)127 static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ */
128 {
129 str_efree(property_info->name);
130 if (property_info->doc_comment) {
131 efree((char*)property_info->doc_comment);
132 }
133 }
134 /* }}} */
135
zend_destroy_property_info_internal(zend_property_info * property_info)136 static void zend_destroy_property_info_internal(zend_property_info *property_info) /* {{{ */
137 {
138 str_free((char*)property_info->name);
139 }
140 /* }}} */
141
build_runtime_defined_function_key(zval * result,const char * name,int name_length TSRMLS_DC)142 static void build_runtime_defined_function_key(zval *result, const char *name, int name_length TSRMLS_DC) /* {{{ */
143 {
144 char char_pos_buf[32];
145 uint char_pos_len;
146 const char *filename;
147
148 char_pos_len = zend_sprintf(char_pos_buf, "%p", LANG_SCNG(yy_text));
149 if (CG(active_op_array)->filename) {
150 filename = CG(active_op_array)->filename;
151 } else {
152 filename = "-";
153 }
154
155 /* NULL, name length, filename length, last accepting char position length */
156 result->value.str.len = 1+name_length+strlen(filename)+char_pos_len;
157
158 /* must be binary safe */
159 result->value.str.val = (char *) safe_emalloc(result->value.str.len, 1, 1);
160 result->value.str.val[0] = '\0';
161 sprintf(result->value.str.val+1, "%s%s%s", name, filename, char_pos_buf);
162
163 result->type = IS_STRING;
164 Z_SET_REFCOUNT_P(result, 1);
165 }
166 /* }}} */
167
init_compiler_declarables(TSRMLS_D)168 static void init_compiler_declarables(TSRMLS_D) /* {{{ */
169 {
170 Z_TYPE(CG(declarables).ticks) = IS_LONG;
171 Z_LVAL(CG(declarables).ticks) = 0;
172 }
173 /* }}} */
174
zend_init_compiler_context(TSRMLS_D)175 void zend_init_compiler_context(TSRMLS_D) /* {{{ */
176 {
177 CG(context).opcodes_size = (CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) ? INITIAL_INTERACTIVE_OP_ARRAY_SIZE : INITIAL_OP_ARRAY_SIZE;
178 CG(context).vars_size = 0;
179 CG(context).literals_size = 0;
180 CG(context).current_brk_cont = -1;
181 CG(context).backpatch_count = 0;
182 CG(context).nested_calls = 0;
183 CG(context).used_stack = 0;
184 CG(context).in_finally = 0;
185 CG(context).labels = NULL;
186 }
187 /* }}} */
188
zend_init_compiler_data_structures(TSRMLS_D)189 void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */
190 {
191 zend_stack_init(&CG(bp_stack));
192 zend_stack_init(&CG(function_call_stack));
193 zend_stack_init(&CG(switch_cond_stack));
194 zend_stack_init(&CG(foreach_copy_stack));
195 zend_stack_init(&CG(object_stack));
196 zend_stack_init(&CG(declare_stack));
197 CG(active_class_entry) = NULL;
198 zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
199 zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
200 zend_stack_init(&CG(list_stack));
201 CG(in_compilation) = 0;
202 CG(start_lineno) = 0;
203 CG(current_namespace) = NULL;
204 CG(in_namespace) = 0;
205 CG(has_bracketed_namespaces) = 0;
206 CG(current_import) = NULL;
207 init_compiler_declarables(TSRMLS_C);
208 zend_stack_init(&CG(context_stack));
209
210 CG(encoding_declared) = 0;
211 }
212 /* }}} */
213
file_handle_dtor(zend_file_handle * fh)214 ZEND_API void file_handle_dtor(zend_file_handle *fh) /* {{{ */
215 {
216 TSRMLS_FETCH();
217
218 zend_file_handle_dtor(fh TSRMLS_CC);
219 }
220 /* }}} */
221
init_compiler(TSRMLS_D)222 void init_compiler(TSRMLS_D) /* {{{ */
223 {
224 CG(active_op_array) = NULL;
225 memset(&CG(context), 0, sizeof(CG(context)));
226 zend_init_compiler_data_structures(TSRMLS_C);
227 zend_init_rsrc_list(TSRMLS_C);
228 zend_hash_init(&CG(filenames_table), 5, NULL, (dtor_func_t) free_estring, 0);
229 zend_llist_init(&CG(open_files), sizeof(zend_file_handle), (void (*)(void *)) file_handle_dtor, 0);
230 CG(unclean_shutdown) = 0;
231 }
232 /* }}} */
233
shutdown_compiler(TSRMLS_D)234 void shutdown_compiler(TSRMLS_D) /* {{{ */
235 {
236 zend_stack_destroy(&CG(bp_stack));
237 zend_stack_destroy(&CG(function_call_stack));
238 zend_stack_destroy(&CG(switch_cond_stack));
239 zend_stack_destroy(&CG(foreach_copy_stack));
240 zend_stack_destroy(&CG(object_stack));
241 zend_stack_destroy(&CG(declare_stack));
242 zend_stack_destroy(&CG(list_stack));
243 zend_hash_destroy(&CG(filenames_table));
244 zend_llist_destroy(&CG(open_files));
245 zend_stack_destroy(&CG(context_stack));
246 }
247 /* }}} */
248
zend_set_compiled_filename(const char * new_compiled_filename TSRMLS_DC)249 ZEND_API char *zend_set_compiled_filename(const char *new_compiled_filename TSRMLS_DC) /* {{{ */
250 {
251 char **pp, *p;
252 int length = strlen(new_compiled_filename);
253
254 if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) {
255 CG(compiled_filename) = *pp;
256 return *pp;
257 }
258 p = estrndup(new_compiled_filename, length);
259 zend_hash_update(&CG(filenames_table), new_compiled_filename, length+1, &p, sizeof(char *), (void **) &pp);
260 CG(compiled_filename) = p;
261 return p;
262 }
263 /* }}} */
264
zend_restore_compiled_filename(char * original_compiled_filename TSRMLS_DC)265 ZEND_API void zend_restore_compiled_filename(char *original_compiled_filename TSRMLS_DC) /* {{{ */
266 {
267 CG(compiled_filename) = original_compiled_filename;
268 }
269 /* }}} */
270
zend_get_compiled_filename(TSRMLS_D)271 ZEND_API char *zend_get_compiled_filename(TSRMLS_D) /* {{{ */
272 {
273 return CG(compiled_filename);
274 }
275 /* }}} */
276
zend_get_compiled_lineno(TSRMLS_D)277 ZEND_API int zend_get_compiled_lineno(TSRMLS_D) /* {{{ */
278 {
279 return CG(zend_lineno);
280 }
281 /* }}} */
282
zend_is_compiling(TSRMLS_D)283 ZEND_API zend_bool zend_is_compiling(TSRMLS_D) /* {{{ */
284 {
285 return CG(in_compilation);
286 }
287 /* }}} */
288
get_temporary_variable(zend_op_array * op_array)289 static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */
290 {
291 return (zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, (op_array->T)++);
292 }
293 /* }}} */
294
lookup_cv(zend_op_array * op_array,char * name,int name_len,ulong hash TSRMLS_DC)295 static int lookup_cv(zend_op_array *op_array, char* name, int name_len, ulong hash TSRMLS_DC) /* {{{ */
296 {
297 int i = 0;
298 ulong hash_value = hash ? hash : zend_inline_hash_func(name, name_len+1);
299
300 while (i < op_array->last_var) {
301 if (op_array->vars[i].name == name ||
302 (op_array->vars[i].hash_value == hash_value &&
303 op_array->vars[i].name_len == name_len &&
304 memcmp(op_array->vars[i].name, name, name_len) == 0)) {
305 str_efree(name);
306 return i;
307 }
308 i++;
309 }
310 i = op_array->last_var;
311 op_array->last_var++;
312 if (op_array->last_var > CG(context).vars_size) {
313 CG(context).vars_size += 16; /* FIXME */
314 op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_compiled_variable));
315 }
316 op_array->vars[i].name = zend_new_interned_string(name, name_len + 1, 1 TSRMLS_CC);
317 op_array->vars[i].name_len = name_len;
318 op_array->vars[i].hash_value = hash_value;
319 return i;
320 }
321 /* }}} */
322
zend_del_literal(zend_op_array * op_array,int n)323 void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */
324 {
325 zval_dtor(&CONSTANT_EX(op_array, n));
326 if (n + 1 == op_array->last_literal) {
327 op_array->last_literal--;
328 } else {
329 Z_TYPE(CONSTANT_EX(op_array, n)) = IS_NULL;
330 }
331 }
332 /* }}} */
333
334 /* Common part of zend_add_literal and zend_append_individual_literal */
zend_insert_literal(zend_op_array * op_array,const zval * zv,int literal_position TSRMLS_DC)335 static inline void zend_insert_literal(zend_op_array *op_array, const zval *zv, int literal_position TSRMLS_DC) /* {{{ */
336 {
337 if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) {
338 zval *z = (zval*)zv;
339 Z_STRVAL_P(z) = (char*)zend_new_interned_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1, 1 TSRMLS_CC);
340 }
341 CONSTANT_EX(op_array, literal_position) = *zv;
342 Z_SET_REFCOUNT(CONSTANT_EX(op_array, literal_position), 2);
343 Z_SET_ISREF(CONSTANT_EX(op_array, literal_position));
344 op_array->literals[literal_position].hash_value = 0;
345 op_array->literals[literal_position].cache_slot = -1;
346 }
347 /* }}} */
348
349 /* Is used while compiling a function, using the context to keep track
350 of an approximate size to avoid to relocate to often.
351 Literals are truncated to actual size in the second compiler pass (pass_two()). */
zend_add_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)352 int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
353 {
354 int i = op_array->last_literal;
355 op_array->last_literal++;
356 if (i >= CG(context).literals_size) {
357 while (i >= CG(context).literals_size) {
358 CG(context).literals_size += 16; /* FIXME */
359 }
360 op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));
361 }
362 zend_insert_literal(op_array, zv, i TSRMLS_CC);
363 return i;
364 }
365 /* }}} */
366
367 /* Is used after normal compilation to append an additional literal.
368 Allocation is done precisely here. */
zend_append_individual_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)369 int zend_append_individual_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
370 {
371 int i = op_array->last_literal;
372 op_array->last_literal++;
373 op_array->literals = (zend_literal*)erealloc(op_array->literals, (i + 1) * sizeof(zend_literal));
374 zend_insert_literal(op_array, zv, i TSRMLS_CC);
375 return i;
376 }
377 /* }}} */
378
zend_add_func_name_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)379 int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
380 {
381 int ret;
382 char *lc_name;
383 zval c;
384 int lc_literal;
385
386 if (op_array->last_literal > 0 &&
387 &op_array->literals[op_array->last_literal - 1].constant == zv &&
388 op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
389 /* we already have function name as last literal (do nothing) */
390 ret = op_array->last_literal - 1;
391 } else {
392 ret = zend_add_literal(op_array, zv TSRMLS_CC);
393 }
394
395 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
396 ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
397 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
398 CALCULATE_LITERAL_HASH(lc_literal);
399
400 return ret;
401 }
402 /* }}} */
403
zend_add_ns_func_name_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)404 int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
405 {
406 int ret;
407 char *lc_name;
408 const char *ns_separator;
409 int lc_len;
410 zval c;
411 int lc_literal;
412
413 if (op_array->last_literal > 0 &&
414 &op_array->literals[op_array->last_literal - 1].constant == zv &&
415 op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
416 /* we already have function name as last literal (do nothing) */
417 ret = op_array->last_literal - 1;
418 } else {
419 ret = zend_add_literal(op_array, zv TSRMLS_CC);
420 }
421
422 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
423 ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
424 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
425 CALCULATE_LITERAL_HASH(lc_literal);
426
427 ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv)) + 1;
428 lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv));
429 lc_name = zend_str_tolower_dup(ns_separator, lc_len);
430 ZVAL_STRINGL(&c, lc_name, lc_len, 0);
431 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
432 CALCULATE_LITERAL_HASH(lc_literal);
433
434 return ret;
435 }
436 /* }}} */
437
zend_add_class_name_literal(zend_op_array * op_array,const zval * zv TSRMLS_DC)438 int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
439 {
440 int ret;
441 char *lc_name;
442 int lc_len;
443 zval c;
444 int lc_literal;
445
446 if (op_array->last_literal > 0 &&
447 &op_array->literals[op_array->last_literal - 1].constant == zv &&
448 op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
449 /* we already have function name as last literal (do nothing) */
450 ret = op_array->last_literal - 1;
451 } else {
452 ret = zend_add_literal(op_array, zv TSRMLS_CC);
453 }
454
455 if (Z_STRVAL_P(zv)[0] == '\\') {
456 lc_len = Z_STRLEN_P(zv) - 1;
457 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv) + 1, lc_len);
458 } else {
459 lc_len = Z_STRLEN_P(zv);
460 lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), lc_len);
461 }
462 ZVAL_STRINGL(&c, lc_name, lc_len, 0);
463 lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
464 CALCULATE_LITERAL_HASH(lc_literal);
465
466 GET_CACHE_SLOT(ret);
467
468 return ret;
469 }
470 /* }}} */
471
zend_add_const_name_literal(zend_op_array * op_array,const zval * zv,int unqualified TSRMLS_DC)472 int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unqualified TSRMLS_DC) /* {{{ */
473 {
474 int ret, tmp_literal;
475 char *name, *tmp_name;
476 const char *ns_separator;
477 int name_len, ns_len;
478 zval c;
479
480 if (op_array->last_literal > 0 &&
481 &op_array->literals[op_array->last_literal - 1].constant == zv &&
482 op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
483 /* we already have function name as last literal (do nothing) */
484 ret = op_array->last_literal - 1;
485 } else {
486 ret = zend_add_literal(op_array, zv TSRMLS_CC);
487 }
488
489 /* skip leading '\\' */
490 if (Z_STRVAL_P(zv)[0] == '\\') {
491 name_len = Z_STRLEN_P(zv) - 1;
492 name = Z_STRVAL_P(zv) + 1;
493 } else {
494 name_len = Z_STRLEN_P(zv);
495 name = Z_STRVAL_P(zv);
496 }
497 ns_separator = zend_memrchr(name, '\\', name_len);
498 if (ns_separator) {
499 ns_len = ns_separator - name;
500 } else {
501 ns_len = 0;
502 }
503
504 if (ns_len) {
505 /* lowercased namespace name & original constant name */
506 tmp_name = estrndup(name, name_len);
507 zend_str_tolower(tmp_name, ns_len);
508 ZVAL_STRINGL(&c, tmp_name, name_len, 0);
509 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
510 CALCULATE_LITERAL_HASH(tmp_literal);
511
512 /* lowercased namespace name & lowercased constant name */
513 tmp_name = zend_str_tolower_dup(name, name_len);
514 ZVAL_STRINGL(&c, tmp_name, name_len, 0);
515 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
516 CALCULATE_LITERAL_HASH(tmp_literal);
517 }
518
519 if (ns_len) {
520 if (!unqualified) {
521 return ret;
522 }
523 ns_len++;
524 name += ns_len;
525 name_len -= ns_len;
526 }
527
528 /* original constant name */
529 tmp_name = estrndup(name, name_len);
530 ZVAL_STRINGL(&c, tmp_name, name_len, 0);
531 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
532 CALCULATE_LITERAL_HASH(tmp_literal);
533
534 /* lowercased constant name */
535 tmp_name = zend_str_tolower_dup(name, name_len);
536 ZVAL_STRINGL(&c, tmp_name, name_len, 0);
537 tmp_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
538 CALCULATE_LITERAL_HASH(tmp_literal);
539
540 return ret;
541 }
542 /* }}} */
543
544 #define LITERAL_STRINGL(op, str, len, copy) do { \
545 zval _c; \
546 ZVAL_STRINGL(&_c, str, len, copy); \
547 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
548 } while (0)
549
550 #define LITERAL_LONG(op, val) do { \
551 zval _c; \
552 ZVAL_LONG(&_c, val); \
553 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
554 } while (0)
555
556 #define LITERAL_LONG_EX(op_array, op, val) do { \
557 zval _c; \
558 ZVAL_LONG(&_c, val); \
559 op.constant = zend_add_literal(op_array, &_c TSRMLS_CC); \
560 } while (0)
561
562 #define LITERAL_NULL(op) do { \
563 zval _c; \
564 INIT_ZVAL( _c); \
565 op.constant = zend_add_literal(CG(active_op_array), &_c TSRMLS_CC); \
566 } while (0)
567
zend_is_function_or_method_call(const znode * variable)568 static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */
569 {
570 zend_uint type = variable->EA;
571
572 return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
573 }
574 /* }}} */
575
zend_do_binary_op(zend_uchar op,znode * result,const znode * op1,const znode * op2 TSRMLS_DC)576 void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
577 {
578 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
579
580 opline->opcode = op;
581 opline->result_type = IS_TMP_VAR;
582 opline->result.var = get_temporary_variable(CG(active_op_array));
583 SET_NODE(opline->op1, op1);
584 SET_NODE(opline->op2, op2);
585 GET_NODE(result, opline->result);
586 }
587 /* }}} */
588
zend_do_unary_op(zend_uchar op,znode * result,const znode * op1 TSRMLS_DC)589 void zend_do_unary_op(zend_uchar op, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */
590 {
591 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
592
593 opline->opcode = op;
594 opline->result_type = IS_TMP_VAR;
595 opline->result.var = get_temporary_variable(CG(active_op_array));
596 SET_NODE(opline->op1, op1);
597 GET_NODE(result, opline->result);
598 SET_UNUSED(opline->op2);
599 }
600 /* }}} */
601
602 #define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; }
603
zend_do_op_data(zend_op * data_op,const znode * value TSRMLS_DC)604 static void zend_do_op_data(zend_op *data_op, const znode *value TSRMLS_DC) /* {{{ */
605 {
606 data_op->opcode = ZEND_OP_DATA;
607 SET_NODE(data_op->op1, value);
608 SET_UNUSED(data_op->op2);
609 }
610 /* }}} */
611
zend_do_binary_assign_op(zend_uchar op,znode * result,const znode * op1,const znode * op2 TSRMLS_DC)612 void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
613 {
614 int last_op_number = get_next_op_number(CG(active_op_array));
615 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
616
617 if (last_op_number > 0) {
618 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
619
620 switch (last_op->opcode) {
621 case ZEND_FETCH_OBJ_RW:
622 last_op->opcode = op;
623 last_op->extended_value = ZEND_ASSIGN_OBJ;
624
625 zend_do_op_data(opline, op2 TSRMLS_CC);
626 SET_UNUSED(opline->result);
627 GET_NODE(result, last_op->result);
628 return;
629 case ZEND_FETCH_DIM_RW:
630 last_op->opcode = op;
631 last_op->extended_value = ZEND_ASSIGN_DIM;
632
633 zend_do_op_data(opline, op2 TSRMLS_CC);
634 opline->op2.var = get_temporary_variable(CG(active_op_array));
635 opline->op2_type = IS_VAR;
636 SET_UNUSED(opline->result);
637 GET_NODE(result,last_op->result);
638 return;
639 default:
640 break;
641 }
642 }
643
644 opline->opcode = op;
645 SET_NODE(opline->op1, op1);
646 SET_NODE(opline->op2, op2);
647 opline->result_type = IS_VAR;
648 opline->result.var = get_temporary_variable(CG(active_op_array));
649 GET_NODE(result, opline->result);
650 }
651 /* }}} */
652
fetch_simple_variable_ex(znode * result,znode * varname,int bp,zend_uchar op TSRMLS_DC)653 void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC) /* {{{ */
654 {
655 zend_op opline;
656 zend_op *opline_ptr;
657 zend_llist *fetch_list_ptr;
658
659 if (varname->op_type == IS_CONST) {
660 ulong hash = 0;
661
662 if (Z_TYPE(varname->u.constant) != IS_STRING) {
663 convert_to_string(&varname->u.constant);
664 } else if (IS_INTERNED(Z_STRVAL(varname->u.constant))) {
665 hash = INTERNED_HASH(Z_STRVAL(varname->u.constant));
666 }
667 if (!zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC) &&
668 !(varname->u.constant.value.str.len == (sizeof("this")-1) &&
669 !memcmp(varname->u.constant.value.str.val, "this", sizeof("this"))) &&
670 (CG(active_op_array)->last == 0 ||
671 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) {
672 result->op_type = IS_CV;
673 result->u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, hash TSRMLS_CC);
674 varname->u.constant.value.str.val = (char*)CG(active_op_array)->vars[result->u.op.var].name;
675 result->EA = 0;
676 return;
677 }
678 }
679
680 if (bp) {
681 opline_ptr = &opline;
682 init_op(opline_ptr TSRMLS_CC);
683 } else {
684 opline_ptr = get_next_op(CG(active_op_array) TSRMLS_CC);
685 }
686
687 opline_ptr->opcode = op;
688 opline_ptr->result_type = IS_VAR;
689 opline_ptr->result.var = get_temporary_variable(CG(active_op_array));
690 SET_NODE(opline_ptr->op1, varname);
691 GET_NODE(result, opline_ptr->result);
692 SET_UNUSED(opline_ptr->op2);
693 opline_ptr->extended_value = ZEND_FETCH_LOCAL;
694
695 if (varname->op_type == IS_CONST) {
696 CALCULATE_LITERAL_HASH(opline_ptr->op1.constant);
697 if (zend_is_auto_global_quick(varname->u.constant.value.str.val, varname->u.constant.value.str.len, Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC)) {
698 opline_ptr->extended_value = ZEND_FETCH_GLOBAL;
699 }
700 }
701
702 if (bp) {
703 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
704 zend_llist_add_element(fetch_list_ptr, opline_ptr);
705 }
706 }
707 /* }}} */
708
fetch_simple_variable(znode * result,znode * varname,int bp TSRMLS_DC)709 void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC) /* {{{ */
710 {
711 /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
712 fetch_simple_variable_ex(result, varname, bp, ZEND_FETCH_W TSRMLS_CC);
713 }
714 /* }}} */
715
zend_do_fetch_static_member(znode * result,znode * class_name TSRMLS_DC)716 void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
717 {
718 znode class_node;
719 zend_llist *fetch_list_ptr;
720 zend_llist_element *le;
721 zend_op *opline_ptr;
722 zend_op opline;
723
724 if (class_name->op_type == IS_CONST &&
725 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
726 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
727 class_node = *class_name;
728 } else {
729 zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
730 }
731 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
732 if (result->op_type == IS_CV) {
733 init_op(&opline TSRMLS_CC);
734
735 opline.opcode = ZEND_FETCH_W;
736 opline.result_type = IS_VAR;
737 opline.result.var = get_temporary_variable(CG(active_op_array));
738 opline.op1_type = IS_CONST;
739 LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0);
740 CALCULATE_LITERAL_HASH(opline.op1.constant);
741 GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
742 if (class_node.op_type == IS_CONST) {
743 opline.op2_type = IS_CONST;
744 opline.op2.constant =
745 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
746 } else {
747 SET_NODE(opline.op2, &class_node);
748 }
749 GET_NODE(result,opline.result);
750 opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
751 opline_ptr = &opline;
752
753 zend_llist_add_element(fetch_list_ptr, &opline);
754 } else {
755 le = fetch_list_ptr->head;
756
757 opline_ptr = (zend_op *)le->data;
758 if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) {
759 init_op(&opline TSRMLS_CC);
760 opline.opcode = ZEND_FETCH_W;
761 opline.result_type = IS_VAR;
762 opline.result.var = get_temporary_variable(CG(active_op_array));
763 opline.op1_type = IS_CONST;
764 LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0);
765 CALCULATE_LITERAL_HASH(opline.op1.constant);
766 GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
767 if (class_node.op_type == IS_CONST) {
768 opline.op2_type = IS_CONST;
769 opline.op2.constant =
770 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
771 } else {
772 SET_NODE(opline.op2, &class_node);
773 }
774 opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
775 COPY_NODE(opline_ptr->op1, opline.result);
776
777 zend_llist_prepend_element(fetch_list_ptr, &opline);
778 } else {
779 if (opline_ptr->op1_type == IS_CONST) {
780 GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant);
781 }
782 if (class_node.op_type == IS_CONST) {
783 opline_ptr->op2_type = IS_CONST;
784 opline_ptr->op2.constant =
785 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
786 } else {
787 SET_NODE(opline_ptr->op2, &class_node);
788 }
789 opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER;
790 }
791 }
792 }
793 /* }}} */
794
fetch_array_begin(znode * result,znode * varname,znode * first_dim TSRMLS_DC)795 void fetch_array_begin(znode *result, znode *varname, znode *first_dim TSRMLS_DC) /* {{{ */
796 {
797 fetch_simple_variable(result, varname, 1 TSRMLS_CC);
798
799 fetch_array_dim(result, result, first_dim TSRMLS_CC);
800 }
801 /* }}} */
802
fetch_array_dim(znode * result,const znode * parent,const znode * dim TSRMLS_DC)803 void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS_DC) /* {{{ */
804 {
805 zend_op opline;
806 zend_llist *fetch_list_ptr;
807
808 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
809
810 if (zend_is_function_or_method_call(parent)) {
811 init_op(&opline TSRMLS_CC);
812 opline.opcode = ZEND_SEPARATE;
813 SET_NODE(opline.op1, parent);
814 SET_UNUSED(opline.op2);
815 opline.result_type = IS_VAR;
816 opline.result.var = opline.op1.var;
817 zend_llist_add_element(fetch_list_ptr, &opline);
818 }
819
820 init_op(&opline TSRMLS_CC);
821 opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */
822 opline.result_type = IS_VAR;
823 opline.result.var = get_temporary_variable(CG(active_op_array));
824 SET_NODE(opline.op1, parent);
825 SET_NODE(opline.op2, dim);
826 if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) {
827 ulong index;
828 int numeric = 0;
829
830 ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1);
831 if (numeric) {
832 zval_dtor(&CONSTANT(opline.op2.constant));
833 ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
834 } else {
835 CALCULATE_LITERAL_HASH(opline.op2.constant);
836 }
837 }
838
839 GET_NODE(result, opline.result);
840
841 zend_llist_add_element(fetch_list_ptr, &opline);
842 }
843 /* }}} */
844
fetch_string_offset(znode * result,const znode * parent,const znode * offset TSRMLS_DC)845 void fetch_string_offset(znode *result, const znode *parent, const znode *offset TSRMLS_DC) /* {{{ */
846 {
847 fetch_array_dim(result, parent, offset TSRMLS_CC);
848 }
849 /* }}} */
850
zend_do_print(znode * result,const znode * arg TSRMLS_DC)851 void zend_do_print(znode *result, const znode *arg TSRMLS_DC) /* {{{ */
852 {
853 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
854
855 opline->result_type = IS_TMP_VAR;
856 opline->result.var = get_temporary_variable(CG(active_op_array));
857 opline->opcode = ZEND_PRINT;
858 SET_NODE(opline->op1, arg);
859 SET_UNUSED(opline->op2);
860 GET_NODE(result, opline->result);
861 }
862 /* }}} */
863
zend_do_echo(const znode * arg TSRMLS_DC)864 void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */
865 {
866 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
867
868 opline->opcode = ZEND_ECHO;
869 SET_NODE(opline->op1, arg);
870 SET_UNUSED(opline->op2);
871 }
872 /* }}} */
873
zend_do_abstract_method(const znode * function_name,znode * modifiers,const znode * body TSRMLS_DC)874 void zend_do_abstract_method(const znode *function_name, znode *modifiers, const znode *body TSRMLS_DC) /* {{{ */
875 {
876 char *method_type;
877
878 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
879 Z_LVAL(modifiers->u.constant) |= ZEND_ACC_ABSTRACT;
880 method_type = "Interface";
881 } else {
882 method_type = "Abstract";
883 }
884
885 if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
886 if(modifiers->u.constant.value.lval & ZEND_ACC_PRIVATE) {
887 zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
888 }
889 if (Z_LVAL(body->u.constant) == ZEND_ACC_ABSTRACT) {
890 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
891
892 opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
893 SET_UNUSED(opline->op1);
894 SET_UNUSED(opline->op2);
895 } else {
896 /* we had code in the function body */
897 zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
898 }
899 } else {
900 if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
901 zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
902 }
903 }
904 }
905 /* }}} */
906
opline_is_fetch_this(const zend_op * opline TSRMLS_DC)907 static zend_bool opline_is_fetch_this(const zend_op *opline TSRMLS_DC) /* {{{ */
908 {
909 if ((opline->opcode == ZEND_FETCH_W) && (opline->op1_type == IS_CONST)
910 && (Z_TYPE(CONSTANT(opline->op1.constant)) == IS_STRING)
911 && ((opline->extended_value & ZEND_FETCH_STATIC_MEMBER) != ZEND_FETCH_STATIC_MEMBER)
912 && (Z_HASH_P(&CONSTANT(opline->op1.constant)) == THIS_HASHVAL)
913 && (Z_STRLEN(CONSTANT(opline->op1.constant)) == (sizeof("this")-1))
914 && !memcmp(Z_STRVAL(CONSTANT(opline->op1.constant)), "this", sizeof("this"))) {
915 return 1;
916 } else {
917 return 0;
918 }
919 }
920 /* }}} */
921
zend_do_assign(znode * result,znode * variable,znode * value TSRMLS_DC)922 void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */
923 {
924 int last_op_number;
925 zend_op *opline;
926
927 if (value->op_type == IS_CV) {
928 zend_llist *fetch_list_ptr;
929
930 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
931 if (fetch_list_ptr && fetch_list_ptr->head) {
932 opline = (zend_op *)fetch_list_ptr->head->data;
933
934 if (opline->opcode == ZEND_FETCH_DIM_W &&
935 opline->op1_type == IS_CV &&
936 opline->op1.var == value->u.op.var) {
937
938 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
939 opline->opcode = ZEND_FETCH_R;
940 opline->result_type = IS_VAR;
941 opline->result.var = get_temporary_variable(CG(active_op_array));
942 opline->op1_type = IS_CONST;
943 LITERAL_STRINGL(opline->op1,
944 CG(active_op_array)->vars[value->u.op.var].name,
945 CG(active_op_array)->vars[value->u.op.var].name_len, 1);
946 CALCULATE_LITERAL_HASH(opline->op1.constant);
947 SET_UNUSED(opline->op2);
948 opline->extended_value = ZEND_FETCH_LOCAL;
949 GET_NODE(value, opline->result);
950 }
951 }
952 }
953
954 zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC);
955
956 last_op_number = get_next_op_number(CG(active_op_array));
957 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
958
959 if (variable->op_type == IS_CV) {
960 if (variable->u.op.var == CG(active_op_array)->this_var) {
961 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
962 }
963 } else if (variable->op_type == IS_VAR) {
964 int n = 0;
965
966 while (last_op_number - n > 0) {
967 zend_op *last_op;
968
969 last_op = &CG(active_op_array)->opcodes[last_op_number-n-1];
970
971 if (last_op->result_type == IS_VAR &&
972 last_op->result.var == variable->u.op.var) {
973 if (last_op->opcode == ZEND_FETCH_OBJ_W) {
974 if (n > 0) {
975 int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
976 *opline = *last_op;
977 MAKE_NOP(last_op);
978 /* last_op = opline; */
979 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
980 /* get_next_op can realloc, we need to move last_op */
981 last_op = &CG(active_op_array)->opcodes[opline_no];
982 }
983 last_op->opcode = ZEND_ASSIGN_OBJ;
984 zend_do_op_data(opline, value TSRMLS_CC);
985 SET_UNUSED(opline->result);
986 GET_NODE(result, last_op->result);
987 return;
988 } else if (last_op->opcode == ZEND_FETCH_DIM_W) {
989 if (n > 0) {
990 int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline);
991 *opline = *last_op;
992 MAKE_NOP(last_op);
993 /* last_op = opline; */
994 /* TBFixed: this can realloc opcodes, leaving last_op pointing wrong */
995 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
996 /* get_next_op can realloc, we need to move last_op */
997 last_op = &CG(active_op_array)->opcodes[opline_no];
998 }
999 last_op->opcode = ZEND_ASSIGN_DIM;
1000 zend_do_op_data(opline, value TSRMLS_CC);
1001 opline->op2.var = get_temporary_variable(CG(active_op_array));
1002 opline->op2_type = IS_VAR;
1003 SET_UNUSED(opline->result);
1004 GET_NODE(result, last_op->result);
1005 return;
1006 } else if (opline_is_fetch_this(last_op TSRMLS_CC)) {
1007 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1008 } else {
1009 break;
1010 }
1011 }
1012 n++;
1013 }
1014 }
1015
1016 opline->opcode = ZEND_ASSIGN;
1017 SET_NODE(opline->op1, variable);
1018 SET_NODE(opline->op2, value);
1019 opline->result_type = IS_VAR;
1020 opline->result.var = get_temporary_variable(CG(active_op_array));
1021 GET_NODE(result, opline->result);
1022 }
1023 /* }}} */
1024
zend_do_assign_ref(znode * result,const znode * lvar,const znode * rvar TSRMLS_DC)1025 void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
1026 {
1027 zend_op *opline;
1028
1029 if (lvar->op_type == IS_CV) {
1030 if (lvar->u.op.var == CG(active_op_array)->this_var) {
1031 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1032 }
1033 } else if (lvar->op_type == IS_VAR) {
1034 int last_op_number = get_next_op_number(CG(active_op_array));
1035
1036 if (last_op_number > 0) {
1037 opline = &CG(active_op_array)->opcodes[last_op_number-1];
1038 if (opline_is_fetch_this(opline TSRMLS_CC)) {
1039 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1040 }
1041 }
1042 }
1043
1044 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1045 opline->opcode = ZEND_ASSIGN_REF;
1046 if (zend_is_function_or_method_call(rvar)) {
1047 opline->extended_value = ZEND_RETURNS_FUNCTION;
1048 } else if (rvar->EA & ZEND_PARSED_NEW) {
1049 opline->extended_value = ZEND_RETURNS_NEW;
1050 } else {
1051 opline->extended_value = 0;
1052 }
1053 if (result) {
1054 opline->result_type = IS_VAR;
1055 opline->result.var = get_temporary_variable(CG(active_op_array));
1056 GET_NODE(result, opline->result);
1057 } else {
1058 opline->result_type = IS_UNUSED | EXT_TYPE_UNUSED;
1059 }
1060 SET_NODE(opline->op1, lvar);
1061 SET_NODE(opline->op2, rvar);
1062 }
1063 /* }}} */
1064
do_begin_loop(TSRMLS_D)1065 static inline void do_begin_loop(TSRMLS_D) /* {{{ */
1066 {
1067 zend_brk_cont_element *brk_cont_element;
1068 int parent;
1069
1070 parent = CG(context).current_brk_cont;
1071 CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont;
1072 brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
1073 brk_cont_element->start = get_next_op_number(CG(active_op_array));
1074 brk_cont_element->parent = parent;
1075 }
1076 /* }}} */
1077
do_end_loop(int cont_addr,int has_loop_var TSRMLS_DC)1078 static inline void do_end_loop(int cont_addr, int has_loop_var TSRMLS_DC) /* {{{ */
1079 {
1080 if (!has_loop_var) {
1081 /* The start fileld is used to free temporary variables in case of exceptions.
1082 * We won't try to free something of we don't have loop variable.
1083 */
1084 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1;
1085 }
1086 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr;
1087 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array));
1088 CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent;
1089 }
1090 /* }}} */
1091
zend_do_while_cond(const znode * expr,znode * close_bracket_token TSRMLS_DC)1092 void zend_do_while_cond(const znode *expr, znode *close_bracket_token TSRMLS_DC) /* {{{ */
1093 {
1094 int while_cond_op_number = get_next_op_number(CG(active_op_array));
1095 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1096
1097 opline->opcode = ZEND_JMPZ;
1098 SET_NODE(opline->op1, expr);
1099 close_bracket_token->u.op.opline_num = while_cond_op_number;
1100 SET_UNUSED(opline->op2);
1101
1102 do_begin_loop(TSRMLS_C);
1103 INC_BPC(CG(active_op_array));
1104 }
1105 /* }}} */
1106
zend_do_while_end(const znode * while_token,const znode * close_bracket_token TSRMLS_DC)1107 void zend_do_while_end(const znode *while_token, const znode *close_bracket_token TSRMLS_DC) /* {{{ */
1108 {
1109 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1110
1111 /* add unconditional jump */
1112 opline->opcode = ZEND_JMP;
1113 opline->op1.opline_num = while_token->u.op.opline_num;
1114 SET_UNUSED(opline->op1);
1115 SET_UNUSED(opline->op2);
1116
1117 /* update while's conditional jmp */
1118 CG(active_op_array)->opcodes[close_bracket_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1119
1120 do_end_loop(while_token->u.op.opline_num, 0 TSRMLS_CC);
1121
1122 DEC_BPC(CG(active_op_array));
1123 }
1124 /* }}} */
1125
zend_do_for_cond(const znode * expr,znode * second_semicolon_token TSRMLS_DC)1126 void zend_do_for_cond(const znode *expr, znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1127 {
1128 int for_cond_op_number = get_next_op_number(CG(active_op_array));
1129 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1130
1131 opline->opcode = ZEND_JMPZNZ;
1132 SET_NODE(opline->op1, expr); /* the conditional expression */
1133 second_semicolon_token->u.op.opline_num = for_cond_op_number;
1134 SET_UNUSED(opline->op2);
1135 }
1136 /* }}} */
1137
zend_do_for_before_statement(const znode * cond_start,const znode * second_semicolon_token TSRMLS_DC)1138 void zend_do_for_before_statement(const znode *cond_start, const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1139 {
1140 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1141
1142 opline->opcode = ZEND_JMP;
1143 opline->op1.opline_num = cond_start->u.op.opline_num;
1144 CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
1145 SET_UNUSED(opline->op1);
1146 SET_UNUSED(opline->op2);
1147
1148 do_begin_loop(TSRMLS_C);
1149
1150 INC_BPC(CG(active_op_array));
1151 }
1152 /* }}} */
1153
zend_do_for_end(const znode * second_semicolon_token TSRMLS_DC)1154 void zend_do_for_end(const znode *second_semicolon_token TSRMLS_DC) /* {{{ */
1155 {
1156 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1157
1158 opline->opcode = ZEND_JMP;
1159 opline->op1.opline_num = second_semicolon_token->u.op.opline_num+1;
1160 CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
1161 SET_UNUSED(opline->op1);
1162 SET_UNUSED(opline->op2);
1163
1164 do_end_loop(second_semicolon_token->u.op.opline_num+1, 0 TSRMLS_CC);
1165
1166 DEC_BPC(CG(active_op_array));
1167 }
1168 /* }}} */
1169
zend_do_pre_incdec(znode * result,const znode * op1,zend_uchar op TSRMLS_DC)1170 void zend_do_pre_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1171 {
1172 int last_op_number = get_next_op_number(CG(active_op_array));
1173 zend_op *opline;
1174
1175 if (last_op_number > 0) {
1176 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1177
1178 if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1179 last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ;
1180 last_op->result_type = IS_VAR;
1181 last_op->result.var = get_temporary_variable(CG(active_op_array));
1182 GET_NODE(result, last_op->result);
1183 return;
1184 }
1185 }
1186
1187 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1188 opline->opcode = op;
1189 SET_NODE(opline->op1, op1);
1190 SET_UNUSED(opline->op2);
1191 opline->result_type = IS_VAR;
1192 opline->result.var = get_temporary_variable(CG(active_op_array));
1193 GET_NODE(result, opline->result);
1194 }
1195 /* }}} */
1196
zend_do_post_incdec(znode * result,const znode * op1,zend_uchar op TSRMLS_DC)1197 void zend_do_post_incdec(znode *result, const znode *op1, zend_uchar op TSRMLS_DC) /* {{{ */
1198 {
1199 int last_op_number = get_next_op_number(CG(active_op_array));
1200 zend_op *opline;
1201
1202 if (last_op_number > 0) {
1203 zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1];
1204
1205 if (last_op->opcode == ZEND_FETCH_OBJ_RW) {
1206 last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ;
1207 last_op->result_type = IS_TMP_VAR;
1208 last_op->result.var = get_temporary_variable(CG(active_op_array));
1209 GET_NODE(result, last_op->result);
1210 return;
1211 }
1212 }
1213
1214 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1215 opline->opcode = op;
1216 SET_NODE(opline->op1, op1);
1217 SET_UNUSED(opline->op2);
1218 opline->result_type = IS_TMP_VAR;
1219 opline->result.var = get_temporary_variable(CG(active_op_array));
1220 GET_NODE(result, opline->result);
1221 }
1222 /* }}} */
1223
zend_do_if_cond(const znode * cond,znode * closing_bracket_token TSRMLS_DC)1224 void zend_do_if_cond(const znode *cond, znode *closing_bracket_token TSRMLS_DC) /* {{{ */
1225 {
1226 int if_cond_op_number = get_next_op_number(CG(active_op_array));
1227 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1228
1229 opline->opcode = ZEND_JMPZ;
1230 SET_NODE(opline->op1, cond);
1231 closing_bracket_token->u.op.opline_num = if_cond_op_number;
1232 SET_UNUSED(opline->op2);
1233 INC_BPC(CG(active_op_array));
1234 }
1235 /* }}} */
1236
zend_do_if_after_statement(const znode * closing_bracket_token,unsigned char initialize TSRMLS_DC)1237 void zend_do_if_after_statement(const znode *closing_bracket_token, unsigned char initialize TSRMLS_DC) /* {{{ */
1238 {
1239 int if_end_op_number = get_next_op_number(CG(active_op_array));
1240 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1241 zend_llist *jmp_list_ptr;
1242
1243 opline->opcode = ZEND_JMP;
1244 /* save for backpatching */
1245 if (initialize) {
1246 zend_llist jmp_list;
1247
1248 zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
1249 zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
1250 }
1251 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1252 zend_llist_add_element(jmp_list_ptr, &if_end_op_number);
1253
1254 CG(active_op_array)->opcodes[closing_bracket_token->u.op.opline_num].op2.opline_num = if_end_op_number+1;
1255 SET_UNUSED(opline->op1);
1256 SET_UNUSED(opline->op2);
1257 }
1258 /* }}} */
1259
zend_do_if_end(TSRMLS_D)1260 void zend_do_if_end(TSRMLS_D) /* {{{ */
1261 {
1262 int next_op_number = get_next_op_number(CG(active_op_array));
1263 zend_llist *jmp_list_ptr;
1264 zend_llist_element *le;
1265
1266 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
1267 for (le=jmp_list_ptr->head; le; le = le->next) {
1268 CG(active_op_array)->opcodes[*((int *) le->data)].op1.opline_num = next_op_number;
1269 }
1270 zend_llist_destroy(jmp_list_ptr);
1271 zend_stack_del_top(&CG(bp_stack));
1272 DEC_BPC(CG(active_op_array));
1273 }
1274 /* }}} */
1275
zend_check_writable_variable(const znode * variable)1276 void zend_check_writable_variable(const znode *variable) /* {{{ */
1277 {
1278 zend_uint type = variable->EA;
1279
1280 if (type & ZEND_PARSED_METHOD_CALL) {
1281 zend_error(E_COMPILE_ERROR, "Can't use method return value in write context");
1282 }
1283 if (type == ZEND_PARSED_FUNCTION_CALL) {
1284 zend_error(E_COMPILE_ERROR, "Can't use function return value in write context");
1285 }
1286 }
1287 /* }}} */
1288
zend_do_begin_variable_parse(TSRMLS_D)1289 void zend_do_begin_variable_parse(TSRMLS_D) /* {{{ */
1290 {
1291 zend_llist fetch_list;
1292
1293 zend_llist_init(&fetch_list, sizeof(zend_op), NULL, 0);
1294 zend_stack_push(&CG(bp_stack), (void *) &fetch_list, sizeof(zend_llist));
1295 }
1296 /* }}} */
1297
zend_do_end_variable_parse(znode * variable,int type,int arg_offset TSRMLS_DC)1298 void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) /* {{{ */
1299 {
1300 zend_llist *fetch_list_ptr;
1301 zend_llist_element *le;
1302 zend_op *opline = NULL;
1303 zend_op *opline_ptr;
1304 zend_uint this_var = -1;
1305
1306 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
1307
1308 le = fetch_list_ptr->head;
1309
1310 /* TODO: $foo->x->y->z = 1 should fetch "x" and "y" for R or RW, not just W */
1311
1312 if (le) {
1313 opline_ptr = (zend_op *)le->data;
1314 if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
1315 /* convert to FETCH_?(this) into IS_CV */
1316 if (CG(active_op_array)->last == 0 ||
1317 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) {
1318
1319 this_var = opline_ptr->result.var;
1320 if (CG(active_op_array)->this_var == -1) {
1321 CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(CONSTANT(opline_ptr->op1.constant)), Z_STRLEN(CONSTANT(opline_ptr->op1.constant)), Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC);
1322 Z_TYPE(CONSTANT(opline_ptr->op1.constant)) = IS_NULL;
1323 } else {
1324 zend_del_literal(CG(active_op_array), opline_ptr->op1.constant);
1325 }
1326 le = le->next;
1327 if (variable->op_type == IS_VAR &&
1328 variable->u.op.var == this_var) {
1329 variable->op_type = IS_CV;
1330 variable->u.op.var = CG(active_op_array)->this_var;
1331 }
1332 } else if (CG(active_op_array)->this_var == -1) {
1333 CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1, THIS_HASHVAL TSRMLS_CC);
1334 }
1335 }
1336
1337 while (le) {
1338 opline_ptr = (zend_op *)le->data;
1339 if (opline_ptr->opcode == ZEND_SEPARATE) {
1340 if (type != BP_VAR_R && type != BP_VAR_IS) {
1341 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1342 memcpy(opline, opline_ptr, sizeof(zend_op));
1343 }
1344 le = le->next;
1345 continue;
1346 }
1347 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1348 memcpy(opline, opline_ptr, sizeof(zend_op));
1349 if (opline->op1_type == IS_VAR &&
1350 opline->op1.var == this_var) {
1351 opline->op1_type = IS_CV;
1352 opline->op1.var = CG(active_op_array)->this_var;
1353 }
1354 switch (type) {
1355 case BP_VAR_R:
1356 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1357 zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1358 }
1359 opline->opcode -= 3;
1360 break;
1361 case BP_VAR_W:
1362 break;
1363 case BP_VAR_RW:
1364 opline->opcode += 3;
1365 break;
1366 case BP_VAR_IS:
1367 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1368 zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
1369 }
1370 opline->opcode += 6; /* 3+3 */
1371 break;
1372 case BP_VAR_FUNC_ARG:
1373 opline->opcode += 9; /* 3+3+3 */
1374 opline->extended_value |= arg_offset;
1375 break;
1376 case BP_VAR_UNSET:
1377 if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) {
1378 zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting");
1379 }
1380 opline->opcode += 12; /* 3+3+3+3 */
1381 break;
1382 }
1383 le = le->next;
1384 }
1385 if (opline && type == BP_VAR_W && arg_offset) {
1386 opline->extended_value |= ZEND_FETCH_MAKE_REF;
1387 }
1388 }
1389 zend_llist_destroy(fetch_list_ptr);
1390 zend_stack_del_top(&CG(bp_stack));
1391 }
1392 /* }}} */
1393
zend_do_add_string(znode * result,const znode * op1,znode * op2 TSRMLS_DC)1394 void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC) /* {{{ */
1395 {
1396 zend_op *opline;
1397
1398 if (Z_STRLEN(op2->u.constant) > 1) {
1399 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1400 opline->opcode = ZEND_ADD_STRING;
1401 } else if (Z_STRLEN(op2->u.constant) == 1) {
1402 int ch = *Z_STRVAL(op2->u.constant);
1403
1404 /* Free memory and use ZEND_ADD_CHAR in case of 1 character strings */
1405 efree(Z_STRVAL(op2->u.constant));
1406 ZVAL_LONG(&op2->u.constant, ch);
1407 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1408 opline->opcode = ZEND_ADD_CHAR;
1409 } else { /* String can be empty after a variable at the end of a heredoc */
1410 efree(Z_STRVAL(op2->u.constant));
1411 return;
1412 }
1413
1414 if (op1) {
1415 SET_NODE(opline->op1, op1);
1416 SET_NODE(opline->result, op1);
1417 } else {
1418 SET_UNUSED(opline->op1);
1419 opline->result_type = IS_TMP_VAR;
1420 opline->result.var = get_temporary_variable(CG(active_op_array));
1421 }
1422 SET_NODE(opline->op2, op2);
1423 GET_NODE(result, opline->result);
1424 }
1425 /* }}} */
1426
zend_do_add_variable(znode * result,const znode * op1,const znode * op2 TSRMLS_DC)1427 void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
1428 {
1429 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1430
1431 opline->opcode = ZEND_ADD_VAR;
1432
1433 if (op1) {
1434 SET_NODE(opline->op1, op1);
1435 SET_NODE(opline->result, op1);
1436 } else {
1437 SET_UNUSED(opline->op1);
1438 opline->result_type = IS_TMP_VAR;
1439 opline->result.var = get_temporary_variable(CG(active_op_array));
1440 }
1441 SET_NODE(opline->op2, op2);
1442 GET_NODE(result, opline->result);
1443 }
1444 /* }}} */
1445
zend_do_free(znode * op1 TSRMLS_DC)1446 void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
1447 {
1448 if (op1->op_type==IS_TMP_VAR) {
1449 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1450
1451 opline->opcode = ZEND_FREE;
1452 SET_NODE(opline->op1, op1);
1453 SET_UNUSED(opline->op2);
1454 } else if (op1->op_type==IS_VAR) {
1455 zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
1456
1457 while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) {
1458 opline--;
1459 }
1460 if (opline->result_type == IS_VAR
1461 && opline->result.var == op1->u.op.var) {
1462 if (opline->opcode == ZEND_FETCH_R ||
1463 opline->opcode == ZEND_FETCH_DIM_R ||
1464 opline->opcode == ZEND_FETCH_OBJ_R ||
1465 opline->opcode == ZEND_QM_ASSIGN_VAR) {
1466 /* It's very rare and useless case. It's better to use
1467 additional FREE opcode and simplify the FETCH handlers
1468 their selves */
1469 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1470 opline->opcode = ZEND_FREE;
1471 SET_NODE(opline->op1, op1);
1472 SET_UNUSED(opline->op2);
1473 } else {
1474 opline->result_type |= EXT_TYPE_UNUSED;
1475 }
1476 } else {
1477 while (opline>CG(active_op_array)->opcodes) {
1478 if (opline->opcode == ZEND_FETCH_DIM_R
1479 && opline->op1_type == IS_VAR
1480 && opline->op1.var == op1->u.op.var) {
1481 /* This should the end of a list() construct
1482 * Mark its result as unused
1483 */
1484 opline->extended_value = ZEND_FETCH_STANDARD;
1485 break;
1486 } else if (opline->result_type==IS_VAR
1487 && opline->result.var == op1->u.op.var) {
1488 if (opline->opcode == ZEND_NEW) {
1489 opline->result_type |= EXT_TYPE_UNUSED;
1490 }
1491 break;
1492 }
1493 opline--;
1494 }
1495 }
1496 } else if (op1->op_type == IS_CONST) {
1497 zval_dtor(&op1->u.constant);
1498 }
1499 }
1500 /* }}} */
1501
zend_do_verify_access_types(const znode * current_access_type,const znode * new_modifier)1502 int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier) /* {{{ */
1503 {
1504 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_PPP_MASK)
1505 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_PPP_MASK)) {
1506 zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
1507 }
1508 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_ABSTRACT)
1509 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_ABSTRACT)) {
1510 zend_error(E_COMPILE_ERROR, "Multiple abstract modifiers are not allowed");
1511 }
1512 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_STATIC)
1513 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_STATIC)) {
1514 zend_error(E_COMPILE_ERROR, "Multiple static modifiers are not allowed");
1515 }
1516 if ((Z_LVAL(current_access_type->u.constant) & ZEND_ACC_FINAL)
1517 && (Z_LVAL(new_modifier->u.constant) & ZEND_ACC_FINAL)) {
1518 zend_error(E_COMPILE_ERROR, "Multiple final modifiers are not allowed");
1519 }
1520 if (((Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant)) & (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) == (ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL)) {
1521 zend_error(E_COMPILE_ERROR, "Cannot use the final modifier on an abstract class member");
1522 }
1523 return (Z_LVAL(current_access_type->u.constant) | Z_LVAL(new_modifier->u.constant));
1524 }
1525 /* }}} */
1526
zend_do_begin_function_declaration(znode * function_token,znode * function_name,int is_method,int return_reference,znode * fn_flags_znode TSRMLS_DC)1527 void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
1528 {
1529 zend_op_array op_array;
1530 char *name = function_name->u.constant.value.str.val;
1531 int name_len = function_name->u.constant.value.str.len;
1532 int function_begin_line = function_token->u.op.opline_num;
1533 zend_uint fn_flags;
1534 const char *lcname;
1535 zend_bool orig_interactive;
1536 ALLOCA_FLAG(use_heap)
1537
1538 if (is_method) {
1539 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1540 if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) {
1541 zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
1542 }
1543 Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
1544 }
1545 fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
1546 } else {
1547 fn_flags = 0;
1548 }
1549 if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
1550 zend_error(E_STRICT, "Static function %s%s%s() should not be abstract", is_method ? CG(active_class_entry)->name : "", is_method ? "::" : "", Z_STRVAL(function_name->u.constant));
1551 }
1552
1553 function_token->u.op_array = CG(active_op_array);
1554
1555 orig_interactive = CG(interactive);
1556 CG(interactive) = 0;
1557 init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
1558 CG(interactive) = orig_interactive;
1559
1560 op_array.function_name = name;
1561 if (return_reference) {
1562 op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1563 }
1564 op_array.fn_flags |= fn_flags;
1565
1566 op_array.scope = is_method?CG(active_class_entry):NULL;
1567 op_array.prototype = NULL;
1568
1569 op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);
1570
1571 if (is_method) {
1572 int result;
1573
1574 lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);
1575
1576 if (IS_INTERNED(lcname)) {
1577 result = zend_hash_quick_add(&CG(active_class_entry)->function_table, lcname, name_len+1, INTERNED_HASH(lcname), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1578 } else {
1579 result = zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1580 }
1581 if (result == FAILURE) {
1582 zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
1583 }
1584
1585 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1586 zend_init_compiler_context(TSRMLS_C);
1587
1588 if (fn_flags & ZEND_ACC_ABSTRACT) {
1589 CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1590 }
1591
1592 if (!(fn_flags & ZEND_ACC_PPP_MASK)) {
1593 fn_flags |= ZEND_ACC_PUBLIC;
1594 }
1595
1596 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
1597 if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1598 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1599 zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1600 }
1601 } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1602 if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1603 zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1604 }
1605 } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1606 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1607 zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1608 }
1609 } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1610 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1611 zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1612 }
1613 } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1614 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1615 zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1616 }
1617 } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1618 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1619 zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1620 }
1621 } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1622 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1623 zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1624 }
1625 } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1626 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1627 zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1628 }
1629 }
1630 } else {
1631 char *class_lcname;
1632
1633 class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
1634 zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
1635 /* Improve after RC: cache the lowercase class name */
1636
1637 if ((CG(active_class_entry)->name_length == name_len) && ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) && (!memcmp(class_lcname, lcname, name_len))) {
1638 if (!CG(active_class_entry)->constructor) {
1639 CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1640 }
1641 } else if ((name_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)))) {
1642 if (CG(active_class_entry)->constructor) {
1643 zend_error(E_STRICT, "Redefining already defined constructor for class %s", CG(active_class_entry)->name);
1644 }
1645 CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
1646 } else if ((name_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1))) {
1647 CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array);
1648 } else if ((name_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1))) {
1649 CG(active_class_entry)->clone = (zend_function *) CG(active_op_array);
1650 } else if ((name_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1))) {
1651 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1652 zend_error(E_WARNING, "The magic method __call() must have public visibility and cannot be static");
1653 }
1654 CG(active_class_entry)->__call = (zend_function *) CG(active_op_array);
1655 } else if ((name_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1))) {
1656 if ((fn_flags & (ZEND_ACC_PPP_MASK ^ ZEND_ACC_PUBLIC)) || (fn_flags & ZEND_ACC_STATIC) == 0) {
1657 zend_error(E_WARNING, "The magic method __callStatic() must have public visibility and be static");
1658 }
1659 CG(active_class_entry)->__callstatic = (zend_function *) CG(active_op_array);
1660 } else if ((name_len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1))) {
1661 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1662 zend_error(E_WARNING, "The magic method __get() must have public visibility and cannot be static");
1663 }
1664 CG(active_class_entry)->__get = (zend_function *) CG(active_op_array);
1665 } else if ((name_len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1))) {
1666 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1667 zend_error(E_WARNING, "The magic method __set() must have public visibility and cannot be static");
1668 }
1669 CG(active_class_entry)->__set = (zend_function *) CG(active_op_array);
1670 } else if ((name_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME)-1))) {
1671 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1672 zend_error(E_WARNING, "The magic method __unset() must have public visibility and cannot be static");
1673 }
1674 CG(active_class_entry)->__unset = (zend_function *) CG(active_op_array);
1675 } else if ((name_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME)-1))) {
1676 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1677 zend_error(E_WARNING, "The magic method __isset() must have public visibility and cannot be static");
1678 }
1679 CG(active_class_entry)->__isset = (zend_function *) CG(active_op_array);
1680 } else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
1681 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1682 zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
1683 }
1684 CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
1685 } else if ((name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1))) {
1686 if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
1687 zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static");
1688 }
1689 } else if (!(fn_flags & ZEND_ACC_STATIC)) {
1690 CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
1691 }
1692 free_alloca(class_lcname, use_heap);
1693 }
1694
1695 str_efree(lcname);
1696 } else {
1697 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1698 zval key;
1699
1700 if (CG(current_namespace)) {
1701 /* Prefix function name with current namespace name */
1702 znode tmp;
1703
1704 tmp.u.constant = *CG(current_namespace);
1705 zval_copy_ctor(&tmp.u.constant);
1706 zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
1707 op_array.function_name = Z_STRVAL(tmp.u.constant);
1708 name_len = Z_STRLEN(tmp.u.constant);
1709 lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
1710 } else {
1711 lcname = zend_str_tolower_dup(name, name_len);
1712 }
1713
1714 opline->opcode = ZEND_DECLARE_FUNCTION;
1715 opline->op1_type = IS_CONST;
1716 build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC);
1717 opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
1718 Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
1719 opline->op2_type = IS_CONST;
1720 LITERAL_STRINGL(opline->op2, lcname, name_len, 0);
1721 CALCULATE_LITERAL_HASH(opline->op2.constant);
1722 opline->extended_value = ZEND_DECLARE_FUNCTION;
1723 zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
1724 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
1725 zend_init_compiler_context(TSRMLS_C);
1726 }
1727
1728 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
1729 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1730
1731 opline->opcode = ZEND_EXT_NOP;
1732 opline->lineno = function_begin_line;
1733 SET_UNUSED(opline->op1);
1734 SET_UNUSED(opline->op2);
1735 }
1736
1737 {
1738 /* Push a separator to the switch stack */
1739 zend_switch_entry switch_entry;
1740
1741 switch_entry.cond.op_type = IS_UNUSED;
1742 switch_entry.default_case = 0;
1743 switch_entry.control_var = 0;
1744
1745 zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
1746 }
1747
1748 {
1749 /* Push a separator to the foreach stack */
1750 zend_op dummy_opline;
1751
1752 dummy_opline.result_type = IS_UNUSED;
1753
1754 zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
1755 }
1756
1757 if (CG(doc_comment)) {
1758 CG(active_op_array)->doc_comment = CG(doc_comment);
1759 CG(active_op_array)->doc_comment_len = CG(doc_comment_len);
1760 CG(doc_comment) = NULL;
1761 CG(doc_comment_len) = 0;
1762 }
1763 }
1764 /* }}} */
1765
zend_do_begin_lambda_function_declaration(znode * result,znode * function_token,int return_reference,int is_static TSRMLS_DC)1766 void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC) /* {{{ */
1767 {
1768 znode function_name;
1769 zend_op_array *current_op_array = CG(active_op_array);
1770 int current_op_number = get_next_op_number(CG(active_op_array));
1771 zend_op *current_op;
1772
1773 function_name.op_type = IS_CONST;
1774 ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1);
1775
1776 zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC);
1777
1778 result->op_type = IS_TMP_VAR;
1779 result->u.op.var = get_temporary_variable(current_op_array);
1780
1781 current_op = ¤t_op_array->opcodes[current_op_number];
1782 current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION;
1783 zend_del_literal(current_op_array, current_op->op2.constant);
1784 SET_UNUSED(current_op->op2);
1785 SET_NODE(current_op->result, result);
1786 if (is_static) {
1787 CG(active_op_array)->fn_flags |= ZEND_ACC_STATIC;
1788 }
1789 CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE;
1790 }
1791 /* }}} */
1792
zend_do_handle_exception(TSRMLS_D)1793 void zend_do_handle_exception(TSRMLS_D) /* {{{ */
1794 {
1795 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1796
1797 opline->opcode = ZEND_HANDLE_EXCEPTION;
1798 SET_UNUSED(opline->op1);
1799 SET_UNUSED(opline->op2);
1800 }
1801 /* }}} */
1802
zend_do_end_function_declaration(const znode * function_token TSRMLS_DC)1803 void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /* {{{ */
1804 {
1805 char lcname[16];
1806 int name_len;
1807
1808 zend_do_extended_info(TSRMLS_C);
1809 zend_do_return(NULL, 0 TSRMLS_CC);
1810
1811 pass_two(CG(active_op_array) TSRMLS_CC);
1812 zend_release_labels(0 TSRMLS_CC);
1813
1814 if (CG(active_class_entry)) {
1815 zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
1816 } else {
1817 /* we don't care if the function name is longer, in fact lowercasing only
1818 * the beginning of the name speeds up the check process */
1819 name_len = strlen(CG(active_op_array)->function_name);
1820 zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1));
1821 lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
1822 if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) {
1823 zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME);
1824 }
1825 }
1826
1827 CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
1828 CG(active_op_array) = function_token->u.op_array;
1829
1830
1831 /* Pop the switch and foreach separators */
1832 zend_stack_del_top(&CG(switch_cond_stack));
1833 zend_stack_del_top(&CG(foreach_copy_stack));
1834 }
1835 /* }}} */
1836
zend_do_receive_arg(zend_uchar op,znode * varname,const znode * offset,const znode * initialization,znode * class_type,zend_uchar pass_by_reference TSRMLS_DC)1837 void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
1838 {
1839 zend_op *opline;
1840 zend_arg_info *cur_arg_info;
1841 znode var;
1842
1843 if (class_type->op_type == IS_CONST &&
1844 Z_TYPE(class_type->u.constant) == IS_STRING &&
1845 Z_STRLEN(class_type->u.constant) == 0) {
1846 /* Usage of namespace as class name not in namespace */
1847 zval_dtor(&class_type->u.constant);
1848 zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
1849 return;
1850 }
1851
1852 if (zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), 0 TSRMLS_CC)) {
1853 zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant));
1854 } else {
1855 var.op_type = IS_CV;
1856 var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len, 0 TSRMLS_CC);
1857 Z_STRVAL(varname->u.constant) = (char*)CG(active_op_array)->vars[var.u.op.var].name;
1858 var.EA = 0;
1859 if (CG(active_op_array)->vars[var.u.op.var].hash_value == THIS_HASHVAL &&
1860 Z_STRLEN(varname->u.constant) == sizeof("this")-1 &&
1861 !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) {
1862 if (CG(active_op_array)->scope &&
1863 (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
1864 zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
1865 }
1866 CG(active_op_array)->this_var = var.u.op.var;
1867 }
1868 }
1869
1870 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
1871 CG(active_op_array)->num_args++;
1872 opline->opcode = op;
1873 SET_NODE(opline->result, &var);
1874 SET_NODE(opline->op1, offset);
1875 if (op == ZEND_RECV_INIT) {
1876 SET_NODE(opline->op2, initialization);
1877 } else {
1878 CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
1879 SET_UNUSED(opline->op2);
1880 }
1881 CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
1882 cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
1883 cur_arg_info->name = zend_new_interned_string(estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len), varname->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1884 cur_arg_info->name_len = varname->u.constant.value.str.len;
1885 cur_arg_info->type_hint = 0;
1886 cur_arg_info->allow_null = 1;
1887 cur_arg_info->pass_by_reference = pass_by_reference;
1888 cur_arg_info->class_name = NULL;
1889 cur_arg_info->class_name_len = 0;
1890
1891 if (class_type->op_type != IS_UNUSED) {
1892 cur_arg_info->allow_null = 0;
1893
1894 if (class_type->u.constant.type != IS_NULL) {
1895 if (class_type->u.constant.type == IS_ARRAY) {
1896 cur_arg_info->type_hint = IS_ARRAY;
1897 if (op == ZEND_RECV_INIT) {
1898 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1899 cur_arg_info->allow_null = 1;
1900 } else if (Z_TYPE(initialization->u.constant) != IS_ARRAY && Z_TYPE(initialization->u.constant) != IS_CONSTANT_ARRAY) {
1901 zend_error(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL");
1902 }
1903 }
1904 } else if (class_type->u.constant.type == IS_CALLABLE) {
1905 cur_arg_info->type_hint = IS_CALLABLE;
1906 if (op == ZEND_RECV_INIT) {
1907 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1908 cur_arg_info->allow_null = 1;
1909 } else {
1910 zend_error(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
1911 }
1912 }
1913 } else {
1914 cur_arg_info->type_hint = IS_OBJECT;
1915 if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) {
1916 zend_resolve_class_name(class_type, opline->extended_value, 1 TSRMLS_CC);
1917 }
1918 Z_STRVAL(class_type->u.constant) = (char*)zend_new_interned_string(class_type->u.constant.value.str.val, class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC);
1919 cur_arg_info->class_name = class_type->u.constant.value.str.val;
1920 cur_arg_info->class_name_len = class_type->u.constant.value.str.len;
1921 if (op == ZEND_RECV_INIT) {
1922 if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
1923 cur_arg_info->allow_null = 1;
1924 } else {
1925 zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL");
1926 }
1927 }
1928 }
1929 }
1930 }
1931 }
1932 /* }}} */
1933
zend_do_begin_function_call(znode * function_name,zend_bool check_namespace TSRMLS_DC)1934 int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
1935 {
1936 zend_function *function;
1937 char *lcname;
1938 char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
1939
1940 zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC);
1941
1942 if (check_namespace && CG(current_namespace) && !is_compound) {
1943 /* We assume we call function from the current namespace
1944 if it is not prefixed. */
1945
1946 /* In run-time PHP will check for function with full name and
1947 internal function with short name */
1948 zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
1949 return 1;
1950 }
1951
1952 lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
1953 if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
1954 ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
1955 (function->type == ZEND_INTERNAL_FUNCTION))) {
1956 zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
1957 efree(lcname);
1958 return 1; /* Dynamic */
1959 }
1960 efree(function_name->u.constant.value.str.val);
1961 function_name->u.constant.value.str.val = lcname;
1962
1963 zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
1964 if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
1965 CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
1966 }
1967 zend_do_extended_fcall_begin(TSRMLS_C);
1968 return 0;
1969 }
1970 /* }}} */
1971
zend_do_begin_method_call(znode * left_bracket TSRMLS_DC)1972 void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
1973 {
1974 zend_op *last_op;
1975 int last_op_number;
1976 unsigned char *ptr = NULL;
1977
1978 zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC);
1979 zend_do_begin_variable_parse(TSRMLS_C);
1980
1981 last_op_number = get_next_op_number(CG(active_op_array))-1;
1982 last_op = &CG(active_op_array)->opcodes[last_op_number];
1983
1984 if ((last_op->op2_type == IS_CONST) && (Z_TYPE(CONSTANT(last_op->op2.constant)) == IS_STRING) && (Z_STRLEN(CONSTANT(last_op->op2.constant)) == sizeof(ZEND_CLONE_FUNC_NAME)-1)
1985 && !zend_binary_strcasecmp(Z_STRVAL(CONSTANT(last_op->op2.constant)), Z_STRLEN(CONSTANT(last_op->op2.constant)), ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) {
1986 zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead");
1987 }
1988
1989 if (last_op->opcode == ZEND_FETCH_OBJ_R) {
1990 if (last_op->op2_type == IS_CONST) {
1991 zval name;
1992 name = CONSTANT(last_op->op2.constant);
1993 if (Z_TYPE(name) != IS_STRING) {
1994 zend_error(E_COMPILE_ERROR, "Method name must be a string");
1995 }
1996 if (!IS_INTERNED(Z_STRVAL(name))) {
1997 Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
1998 }
1999 FREE_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2000 last_op->op2.constant =
2001 zend_add_func_name_literal(CG(active_op_array), &name TSRMLS_CC);
2002 GET_POLYMORPHIC_CACHE_SLOT(last_op->op2.constant);
2003 }
2004 last_op->opcode = ZEND_INIT_METHOD_CALL;
2005 last_op->result_type = IS_UNUSED;
2006 last_op->result.num = CG(context).nested_calls;
2007 Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME;
2008 } else {
2009 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2010 opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2011 opline->result.num = CG(context).nested_calls;
2012 SET_UNUSED(opline->op1);
2013 if (left_bracket->op_type == IS_CONST) {
2014 opline->op2_type = IS_CONST;
2015 opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &left_bracket->u.constant TSRMLS_CC);
2016 GET_CACHE_SLOT(opline->op2.constant);
2017 } else {
2018 SET_NODE(opline->op2, left_bracket);
2019 }
2020 }
2021
2022 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2023 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2024 CG(active_op_array)->nested_calls = CG(context).nested_calls;
2025 }
2026 zend_do_extended_fcall_begin(TSRMLS_C);
2027 }
2028 /* }}} */
2029
zend_do_clone(znode * result,const znode * expr TSRMLS_DC)2030 void zend_do_clone(znode *result, const znode *expr TSRMLS_DC) /* {{{ */
2031 {
2032 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2033
2034 opline->opcode = ZEND_CLONE;
2035 SET_NODE(opline->op1, expr);
2036 SET_UNUSED(opline->op2);
2037 opline->result_type = IS_VAR;
2038 opline->result.var = get_temporary_variable(CG(active_op_array));
2039 GET_NODE(result, opline->result);
2040 }
2041 /* }}} */
2042
zend_do_begin_dynamic_function_call(znode * function_name,int ns_call TSRMLS_DC)2043 void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */
2044 {
2045 unsigned char *ptr = NULL;
2046 zend_op *opline;
2047
2048 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2049 if (ns_call) {
2050 /* In run-time PHP will check for function with full name and
2051 internal function with short name */
2052 opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
2053 opline->result.num = CG(context).nested_calls;
2054 SET_UNUSED(opline->op1);
2055 opline->op2_type = IS_CONST;
2056 opline->op2.constant = zend_add_ns_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2057 GET_CACHE_SLOT(opline->op2.constant);
2058 } else {
2059 opline->opcode = ZEND_INIT_FCALL_BY_NAME;
2060 opline->result.num = CG(context).nested_calls;
2061 SET_UNUSED(opline->op1);
2062 if (function_name->op_type == IS_CONST) {
2063 opline->op2_type = IS_CONST;
2064 opline->op2.constant = zend_add_func_name_literal(CG(active_op_array), &function_name->u.constant TSRMLS_CC);
2065 GET_CACHE_SLOT(opline->op2.constant);
2066 } else {
2067 SET_NODE(opline->op2, function_name);
2068 }
2069 }
2070
2071 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2072 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2073 CG(active_op_array)->nested_calls = CG(context).nested_calls;
2074 }
2075 zend_do_extended_fcall_begin(TSRMLS_C);
2076 }
2077 /* }}} */
2078
zend_resolve_non_class_name(znode * element_name,zend_bool check_namespace TSRMLS_DC)2079 void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
2080 {
2081 znode tmp;
2082 int len;
2083 zval **ns;
2084 char *lcname, *compound = memchr(Z_STRVAL(element_name->u.constant), '\\', Z_STRLEN(element_name->u.constant));
2085
2086 if (Z_STRVAL(element_name->u.constant)[0] == '\\') {
2087 /* name starts with \ so it is known and unambiguos, nothing to do here but shorten it */
2088 memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+1, Z_STRLEN(element_name->u.constant));
2089 --Z_STRLEN(element_name->u.constant);
2090 return;
2091 }
2092
2093 if(!check_namespace) {
2094 return;
2095 }
2096
2097 if (compound && CG(current_import)) {
2098 len = compound - Z_STRVAL(element_name->u.constant);
2099 lcname = zend_str_tolower_dup(Z_STRVAL(element_name->u.constant), len);
2100 /* Check if first part of compound name is an import name */
2101 if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2102 /* Substitute import name */
2103 tmp.op_type = IS_CONST;
2104 tmp.u.constant = **ns;
2105 zval_copy_ctor(&tmp.u.constant);
2106 len += 1;
2107 Z_STRLEN(element_name->u.constant) -= len;
2108 memmove(Z_STRVAL(element_name->u.constant), Z_STRVAL(element_name->u.constant)+len, Z_STRLEN(element_name->u.constant)+1);
2109 zend_do_build_namespace_name(&tmp, &tmp, element_name TSRMLS_CC);
2110 *element_name = tmp;
2111 efree(lcname);
2112 return;
2113 }
2114 efree(lcname);
2115 }
2116
2117 if (CG(current_namespace)) {
2118 tmp = *element_name;
2119 Z_STRLEN(tmp.u.constant) = sizeof("\\")-1 + Z_STRLEN(element_name->u.constant) + Z_STRLEN_P(CG(current_namespace));
2120 Z_STRVAL(tmp.u.constant) = (char *) emalloc(Z_STRLEN(tmp.u.constant)+1);
2121 memcpy(Z_STRVAL(tmp.u.constant), Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
2122 memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace))]), "\\", sizeof("\\")-1);
2123 memcpy(&(Z_STRVAL(tmp.u.constant)[Z_STRLEN_P(CG(current_namespace)) + sizeof("\\")-1]), Z_STRVAL(element_name->u.constant), Z_STRLEN(element_name->u.constant)+1);
2124 STR_FREE(Z_STRVAL(element_name->u.constant));
2125 *element_name = tmp;
2126 }
2127 }
2128 /* }}} */
2129
zend_do_resolve_class_name(znode * result,znode * class_name,int is_static TSRMLS_DC)2130 void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */
2131 {
2132 char *lcname;
2133 int lctype;
2134 znode constant_name;
2135
2136 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len);
2137 lctype = zend_get_class_fetch_type(lcname, strlen(lcname));
2138 switch (lctype) {
2139 case ZEND_FETCH_CLASS_SELF:
2140 if (!CG(active_class_entry)) {
2141 zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active");
2142 }
2143 if (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) {
2144 constant_name.op_type = IS_CONST;
2145 ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
2146 zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
2147 break;
2148 }
2149 zval_dtor(&class_name->u.constant);
2150 class_name->op_type = IS_CONST;
2151 ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1);
2152 *result = *class_name;
2153 break;
2154 case ZEND_FETCH_CLASS_STATIC:
2155 case ZEND_FETCH_CLASS_PARENT:
2156 if (is_static) {
2157 zend_error(E_COMPILE_ERROR,
2158 "%s::class cannot be used for compile-time class name resolution",
2159 lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2160 );
2161 }
2162 if (!CG(active_class_entry)) {
2163 zend_error(E_COMPILE_ERROR,
2164 "Cannot access %s::class when no class scope is active",
2165 lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
2166 );
2167 }
2168 constant_name.op_type = IS_CONST;
2169 ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
2170 zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
2171 break;
2172 case ZEND_FETCH_CLASS_DEFAULT:
2173 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2174 *result = *class_name;
2175 break;
2176 }
2177
2178 efree(lcname);
2179
2180 }
2181 /* }}} */
2182
zend_resolve_class_name(znode * class_name,ulong fetch_type,int check_ns_name TSRMLS_DC)2183 void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */
2184 {
2185 char *compound;
2186 char *lcname;
2187 zval **ns;
2188 znode tmp;
2189 int len;
2190
2191 compound = memchr(Z_STRVAL(class_name->u.constant), '\\', Z_STRLEN(class_name->u.constant));
2192 if (compound) {
2193 /* This is a compound class name that contains namespace prefix */
2194 if (Z_STRVAL(class_name->u.constant)[0] == '\\') {
2195 /* The STRING name has "\" prefix */
2196 Z_STRLEN(class_name->u.constant) -= 1;
2197 memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+1, Z_STRLEN(class_name->u.constant)+1);
2198 Z_STRVAL(class_name->u.constant) = erealloc(
2199 Z_STRVAL(class_name->u.constant),
2200 Z_STRLEN(class_name->u.constant) + 1);
2201
2202 if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2203 zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant));
2204 }
2205 } else {
2206 if (CG(current_import)) {
2207 len = compound - Z_STRVAL(class_name->u.constant);
2208 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len);
2209 /* Check if first part of compound name is an import name */
2210 if (zend_hash_find(CG(current_import), lcname, len+1, (void**)&ns) == SUCCESS) {
2211 /* Substitute import name */
2212 tmp.op_type = IS_CONST;
2213 tmp.u.constant = **ns;
2214 zval_copy_ctor(&tmp.u.constant);
2215 len += 1;
2216 Z_STRLEN(class_name->u.constant) -= len;
2217 memmove(Z_STRVAL(class_name->u.constant), Z_STRVAL(class_name->u.constant)+len, Z_STRLEN(class_name->u.constant)+1);
2218 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2219 *class_name = tmp;
2220 efree(lcname);
2221 return;
2222 }
2223 efree(lcname);
2224 }
2225 /* Here name is not prefixed with \ and not imported */
2226 if (CG(current_namespace)) {
2227 tmp.op_type = IS_CONST;
2228 tmp.u.constant = *CG(current_namespace);
2229 zval_copy_ctor(&tmp.u.constant);
2230 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2231 *class_name = tmp;
2232 }
2233 }
2234 } else if (CG(current_import) || CG(current_namespace)) {
2235 /* this is a plain name (without \) */
2236 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
2237
2238 if (CG(current_import) &&
2239 zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns) == SUCCESS) {
2240 /* The given name is an import name. Substitute it. */
2241 zval_dtor(&class_name->u.constant);
2242 class_name->u.constant = **ns;
2243 zval_copy_ctor(&class_name->u.constant);
2244 } else if (CG(current_namespace)) {
2245 /* plain name, no import - prepend current namespace to it */
2246 tmp.op_type = IS_CONST;
2247 tmp.u.constant = *CG(current_namespace);
2248 zval_copy_ctor(&tmp.u.constant);
2249 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
2250 *class_name = tmp;
2251 }
2252 efree(lcname);
2253 }
2254 }
2255 /* }}} */
2256
zend_do_fetch_class(znode * result,znode * class_name TSRMLS_DC)2257 void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
2258 {
2259 long fetch_class_op_number;
2260 zend_op *opline;
2261
2262 if (class_name->op_type == IS_CONST &&
2263 Z_TYPE(class_name->u.constant) == IS_STRING &&
2264 Z_STRLEN(class_name->u.constant) == 0) {
2265 /* Usage of namespace as class name not in namespace */
2266 zval_dtor(&class_name->u.constant);
2267 zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
2268 return;
2269 }
2270
2271 fetch_class_op_number = get_next_op_number(CG(active_op_array));
2272 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2273
2274 opline->opcode = ZEND_FETCH_CLASS;
2275 SET_UNUSED(opline->op1);
2276 opline->extended_value = ZEND_FETCH_CLASS_GLOBAL;
2277 CG(catch_begin) = fetch_class_op_number;
2278 if (class_name->op_type == IS_CONST) {
2279 int fetch_type;
2280
2281 fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
2282 switch (fetch_type) {
2283 case ZEND_FETCH_CLASS_SELF:
2284 case ZEND_FETCH_CLASS_PARENT:
2285 case ZEND_FETCH_CLASS_STATIC:
2286 SET_UNUSED(opline->op2);
2287 opline->extended_value = fetch_type;
2288 zval_dtor(&class_name->u.constant);
2289 break;
2290 default:
2291 zend_resolve_class_name(class_name, opline->extended_value, 0 TSRMLS_CC);
2292 opline->op2_type = IS_CONST;
2293 opline->op2.constant =
2294 zend_add_class_name_literal(CG(active_op_array), &class_name->u.constant TSRMLS_CC);
2295 break;
2296 }
2297 } else {
2298 SET_NODE(opline->op2, class_name);
2299 }
2300 opline->result.var = get_temporary_variable(CG(active_op_array));
2301 opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */
2302 GET_NODE(result, opline->result);
2303 result->EA = opline->extended_value;
2304 }
2305 /* }}} */
2306
zend_do_label(znode * label TSRMLS_DC)2307 void zend_do_label(znode *label TSRMLS_DC) /* {{{ */
2308 {
2309 zend_label dest;
2310
2311 if (!CG(context).labels) {
2312 ALLOC_HASHTABLE(CG(context).labels);
2313 zend_hash_init(CG(context).labels, 4, NULL, NULL, 0);
2314 }
2315
2316 dest.brk_cont = CG(context).current_brk_cont;
2317 dest.opline_num = get_next_op_number(CG(active_op_array));
2318
2319 if (zend_hash_add(CG(context).labels, Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) {
2320 zend_error(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL(label->u.constant));
2321 }
2322
2323 /* Done with label now */
2324 zval_dtor(&label->u.constant);
2325 }
2326 /* }}} */
2327
zend_resolve_goto_label(zend_op_array * op_array,zend_op * opline,int pass2 TSRMLS_DC)2328 void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC) /* {{{ */
2329 {
2330 zend_label *dest;
2331 long current, distance;
2332 zval *label;
2333
2334 if (pass2) {
2335 label = opline->op2.zv;
2336 } else {
2337 label = &CONSTANT_EX(op_array, opline->op2.constant);
2338 }
2339 if (CG(context).labels == NULL ||
2340 zend_hash_find(CG(context).labels, Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) {
2341
2342 if (pass2) {
2343 CG(in_compilation) = 1;
2344 CG(active_op_array) = op_array;
2345 CG(zend_lineno) = opline->lineno;
2346 zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
2347 } else {
2348 /* Label is not defined. Delay to pass 2. */
2349 INC_BPC(op_array);
2350 return;
2351 }
2352 }
2353
2354 opline->op1.opline_num = dest->opline_num;
2355 zval_dtor(label);
2356 Z_TYPE_P(label) = IS_NULL;
2357
2358 /* Check that we are not moving into loop or switch */
2359 current = opline->extended_value;
2360 for (distance = 0; current != dest->brk_cont; distance++) {
2361 if (current == -1) {
2362 if (pass2) {
2363 CG(in_compilation) = 1;
2364 CG(active_op_array) = op_array;
2365 CG(zend_lineno) = opline->lineno;
2366 }
2367 zend_error(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
2368 }
2369 current = op_array->brk_cont_array[current].parent;
2370 }
2371
2372 if (distance == 0) {
2373 /* Nothing to break out of, optimize to ZEND_JMP */
2374 opline->opcode = ZEND_JMP;
2375 opline->extended_value = 0;
2376 SET_UNUSED(opline->op2);
2377 } else {
2378 /* Set real break distance */
2379 ZVAL_LONG(label, distance);
2380 }
2381
2382 if (pass2) {
2383 DEC_BPC(op_array);
2384 }
2385 }
2386 /* }}} */
2387
zend_do_goto(const znode * label TSRMLS_DC)2388 void zend_do_goto(const znode *label TSRMLS_DC) /* {{{ */
2389 {
2390 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2391
2392 opline->opcode = ZEND_GOTO;
2393 opline->extended_value = CG(context).current_brk_cont;
2394 SET_UNUSED(opline->op1);
2395 SET_NODE(opline->op2, label);
2396 zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC);
2397 }
2398 /* }}} */
2399
zend_release_labels(int temporary TSRMLS_DC)2400 void zend_release_labels(int temporary TSRMLS_DC) /* {{{ */
2401 {
2402 if (CG(context).labels) {
2403 zend_hash_destroy(CG(context).labels);
2404 FREE_HASHTABLE(CG(context).labels);
2405 CG(context).labels = NULL;
2406 }
2407 if (!temporary && !zend_stack_is_empty(&CG(context_stack))) {
2408 zend_compiler_context *ctx;
2409
2410 zend_stack_top(&CG(context_stack), (void**)&ctx);
2411 CG(context) = *ctx;
2412 zend_stack_del_top(&CG(context_stack));
2413 }
2414 }
2415 /* }}} */
2416
zend_do_build_full_name(znode * result,znode * prefix,znode * name,int is_class_member TSRMLS_DC)2417 void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC) /* {{{ */
2418 {
2419 zend_uint length;
2420
2421 if (!result) {
2422 result = prefix;
2423 } else {
2424 *result = *prefix;
2425 }
2426
2427 if (is_class_member) {
2428 length = sizeof("::")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2429 result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2430 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "::", sizeof("::")-1);
2431 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("::")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2432 STR_FREE(name->u.constant.value.str.val);
2433 result->u.constant.value.str.len = length;
2434 } else {
2435 length = sizeof("\\")-1 + result->u.constant.value.str.len + name->u.constant.value.str.len;
2436 result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1);
2437 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], "\\", sizeof("\\")-1);
2438 memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len + sizeof("\\")-1], name->u.constant.value.str.val, name->u.constant.value.str.len+1);
2439 STR_FREE(name->u.constant.value.str.val);
2440 result->u.constant.value.str.len = length;
2441 }
2442 }
2443 /* }}} */
2444
zend_do_begin_class_member_function_call(znode * class_name,znode * method_name TSRMLS_DC)2445 int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
2446 {
2447 znode class_node;
2448 unsigned char *ptr = NULL;
2449 zend_op *opline;
2450
2451 if (method_name->op_type == IS_CONST) {
2452 char *lcname;
2453 if (Z_TYPE(method_name->u.constant) != IS_STRING) {
2454 zend_error(E_COMPILE_ERROR, "Method name must be a string");
2455 }
2456 lcname = zend_str_tolower_dup(Z_STRVAL(method_name->u.constant), Z_STRLEN(method_name->u.constant));
2457 if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) &&
2458 memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) {
2459 zval_dtor(&method_name->u.constant);
2460 method_name->op_type = IS_UNUSED;
2461 }
2462 efree(lcname);
2463 }
2464
2465 if (class_name->op_type == IS_CONST &&
2466 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2467 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2468 class_node = *class_name;
2469 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2470 } else {
2471 zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
2472 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2473 opline->extended_value = class_node.EA ;
2474 }
2475 opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
2476 opline->result.num = CG(context).nested_calls;
2477 if (class_node.op_type == IS_CONST) {
2478 opline->op1_type = IS_CONST;
2479 opline->op1.constant =
2480 zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
2481 } else {
2482 SET_NODE(opline->op1, &class_node);
2483 }
2484 if (method_name->op_type == IS_CONST) {
2485 opline->op2_type = IS_CONST;
2486 opline->op2.constant =
2487 zend_add_func_name_literal(CG(active_op_array), &method_name->u.constant TSRMLS_CC);
2488 if (opline->op1_type == IS_CONST) {
2489 GET_CACHE_SLOT(opline->op2.constant);
2490 } else {
2491 GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
2492 }
2493 } else {
2494 SET_NODE(opline->op2, method_name);
2495 }
2496
2497 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *));
2498 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
2499 CG(active_op_array)->nested_calls = CG(context).nested_calls;
2500 }
2501 zend_do_extended_fcall_begin(TSRMLS_C);
2502 return 1; /* Dynamic */
2503 }
2504 /* }}} */
2505
zend_do_end_function_call(znode * function_name,znode * result,const znode * argument_list,int is_method,int is_dynamic_fcall TSRMLS_DC)2506 void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
2507 {
2508 zend_op *opline;
2509
2510 if (is_method && function_name && function_name->op_type == IS_UNUSED) {
2511 /* clone */
2512 if (Z_LVAL(argument_list->u.constant) != 0) {
2513 zend_error(E_WARNING, "Clone method does not require arguments");
2514 }
2515 opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
2516 } else {
2517 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2518 if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
2519 opline->opcode = ZEND_DO_FCALL;
2520 SET_NODE(opline->op1, function_name);
2521 SET_UNUSED(opline->op2);
2522 opline->op2.num = CG(context).nested_calls;
2523 CALCULATE_LITERAL_HASH(opline->op1.constant);
2524 GET_CACHE_SLOT(opline->op1.constant);
2525 } else {
2526 opline->opcode = ZEND_DO_FCALL_BY_NAME;
2527 SET_UNUSED(opline->op1);
2528 SET_UNUSED(opline->op2);
2529 opline->op2.num = --CG(context).nested_calls;
2530 }
2531 }
2532
2533 opline->result.var = get_temporary_variable(CG(active_op_array));
2534 opline->result_type = IS_VAR;
2535 GET_NODE(result, opline->result);
2536
2537 zend_stack_del_top(&CG(function_call_stack));
2538 opline->extended_value = Z_LVAL(argument_list->u.constant);
2539
2540 if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) {
2541 CG(active_op_array)->used_stack = CG(context).used_stack + 1;
2542 }
2543 CG(context).used_stack -= Z_LVAL(argument_list->u.constant);
2544 }
2545 /* }}} */
2546
zend_do_pass_param(znode * param,zend_uchar op,int offset TSRMLS_DC)2547 void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */
2548 {
2549 zend_op *opline;
2550 int original_op=op;
2551 zend_function **function_ptr_ptr, *function_ptr;
2552 int send_by_reference;
2553 int send_function = 0;
2554
2555 zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
2556 function_ptr = *function_ptr_ptr;
2557
2558 if (original_op == ZEND_SEND_REF) {
2559 if (function_ptr &&
2560 function_ptr->common.function_name &&
2561 function_ptr->common.type == ZEND_USER_FUNCTION &&
2562 !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2563 zend_error(E_COMPILE_ERROR,
2564 "Call-time pass-by-reference has been removed; "
2565 "If you would like to pass argument by reference, modify the declaration of %s().",
2566 function_ptr->common.function_name);
2567 } else {
2568 zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed");
2569 }
2570 return;
2571 }
2572
2573 if (function_ptr) {
2574 if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
2575 if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
2576 send_by_reference = 1;
2577 if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2578 /* Method call */
2579 op = ZEND_SEND_VAR_NO_REF;
2580 send_function = ZEND_ARG_SEND_FUNCTION | ZEND_ARG_SEND_SILENT;
2581 }
2582 } else {
2583 op = ZEND_SEND_VAL;
2584 send_by_reference = 0;
2585 }
2586 } else {
2587 send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0;
2588 }
2589 } else {
2590 send_by_reference = 0;
2591 }
2592
2593 if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
2594 /* Method call */
2595 op = ZEND_SEND_VAR_NO_REF;
2596 send_function = ZEND_ARG_SEND_FUNCTION;
2597 } else if (op == ZEND_SEND_VAL && (param->op_type & (IS_VAR|IS_CV))) {
2598 op = ZEND_SEND_VAR_NO_REF;
2599 }
2600
2601 if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) {
2602 /* change to passing by reference */
2603 switch (param->op_type) {
2604 case IS_VAR:
2605 case IS_CV:
2606 op = ZEND_SEND_REF;
2607 break;
2608 default:
2609 zend_error(E_COMPILE_ERROR, "Only variables can be passed by reference");
2610 break;
2611 }
2612 }
2613
2614 if (original_op == ZEND_SEND_VAR) {
2615 switch (op) {
2616 case ZEND_SEND_VAR_NO_REF:
2617 zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2618 break;
2619 case ZEND_SEND_VAR:
2620 if (function_ptr) {
2621 zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC);
2622 } else {
2623 zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC);
2624 }
2625 break;
2626 case ZEND_SEND_REF:
2627 zend_do_end_variable_parse(param, BP_VAR_W, 0 TSRMLS_CC);
2628 break;
2629 }
2630 }
2631
2632 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2633
2634 if (op == ZEND_SEND_VAR_NO_REF) {
2635 if (function_ptr) {
2636 opline->extended_value = ZEND_ARG_COMPILE_TIME_BOUND | send_by_reference | send_function;
2637 } else {
2638 opline->extended_value = send_function;
2639 }
2640 } else {
2641 if (function_ptr) {
2642 opline->extended_value = ZEND_DO_FCALL;
2643 } else {
2644 opline->extended_value = ZEND_DO_FCALL_BY_NAME;
2645 }
2646 }
2647 opline->opcode = op;
2648 SET_NODE(opline->op1, param);
2649 opline->op2.opline_num = offset;
2650 SET_UNUSED(opline->op2);
2651
2652 if (++CG(context).used_stack > CG(active_op_array)->used_stack) {
2653 CG(active_op_array)->used_stack = CG(context).used_stack;
2654 }
2655 }
2656 /* }}} */
2657
generate_free_switch_expr(const zend_switch_entry * switch_entry TSRMLS_DC)2658 static int generate_free_switch_expr(const zend_switch_entry *switch_entry TSRMLS_DC) /* {{{ */
2659 {
2660 zend_op *opline;
2661
2662 if (switch_entry->cond.op_type != IS_VAR && switch_entry->cond.op_type != IS_TMP_VAR) {
2663 return (switch_entry->cond.op_type == IS_UNUSED);
2664 }
2665
2666 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2667
2668 opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2669 SET_NODE(opline->op1, &switch_entry->cond);
2670 SET_UNUSED(opline->op2);
2671
2672 return 0;
2673 }
2674 /* }}} */
2675
generate_free_foreach_copy(const zend_op * foreach_copy TSRMLS_DC)2676 static int generate_free_foreach_copy(const zend_op *foreach_copy TSRMLS_DC) /* {{{ */
2677 {
2678 zend_op *opline;
2679
2680 /* If we reach the separator then stop applying the stack */
2681 if (foreach_copy->result_type == IS_UNUSED) {
2682 return 1;
2683 }
2684
2685 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2686
2687 opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
2688 COPY_NODE(opline->op1, foreach_copy->result);
2689 SET_UNUSED(opline->op2);
2690
2691 return 0;
2692 }
2693 /* }}} */
2694
zend_do_return(znode * expr,int do_end_vparse TSRMLS_DC)2695 void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
2696 {
2697 zend_op *opline;
2698 int start_op_number, end_op_number;
2699 zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2700
2701 /* The error for use of return inside a generator is thrown in pass_two. */
2702
2703 if (do_end_vparse) {
2704 if (returns_reference && !zend_is_function_or_method_call(expr)) {
2705 zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
2706 } else {
2707 zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);
2708 }
2709 }
2710
2711 start_op_number = get_next_op_number(CG(active_op_array));
2712
2713 #ifdef ZTS
2714 zend_stack_apply_with_argument(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_switch_expr TSRMLS_CC);
2715 zend_stack_apply_with_argument(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element, void *)) generate_free_foreach_copy TSRMLS_CC);
2716 #else
2717 zend_stack_apply(&CG(switch_cond_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_switch_expr);
2718 zend_stack_apply(&CG(foreach_copy_stack), ZEND_STACK_APPLY_TOPDOWN, (int (*)(void *element)) generate_free_foreach_copy);
2719 #endif
2720
2721 end_op_number = get_next_op_number(CG(active_op_array));
2722 while (start_op_number < end_op_number) {
2723 CG(active_op_array)->opcodes[start_op_number].extended_value |= EXT_TYPE_FREE_ON_RETURN;
2724 start_op_number++;
2725 }
2726
2727 if (CG(context).in_finally) {
2728 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2729 opline->opcode = ZEND_DISCARD_EXCEPTION;
2730 SET_UNUSED(opline->op1);
2731 SET_UNUSED(opline->op2);
2732 }
2733
2734 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2735
2736 opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
2737
2738 if (expr) {
2739 SET_NODE(opline->op1, expr);
2740
2741 if (do_end_vparse && zend_is_function_or_method_call(expr)) {
2742 opline->extended_value = ZEND_RETURNS_FUNCTION;
2743 }
2744 } else {
2745 opline->op1_type = IS_CONST;
2746 LITERAL_NULL(opline->op1);
2747 }
2748
2749 SET_UNUSED(opline->op2);
2750 }
2751 /* }}} */
2752
zend_do_yield(znode * result,znode * value,const znode * key,zend_bool is_variable TSRMLS_DC)2753 void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC) /* {{{ */
2754 {
2755 zend_op *opline;
2756
2757 if (!CG(active_op_array)->function_name) {
2758 zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
2759 }
2760
2761 CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
2762
2763 if (is_variable) {
2764 if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(value)) {
2765 zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
2766 } else {
2767 zend_do_end_variable_parse(value, BP_VAR_R, 0 TSRMLS_CC);
2768 }
2769 }
2770
2771 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2772
2773 opline->opcode = ZEND_YIELD;
2774
2775 if (value) {
2776 SET_NODE(opline->op1, value);
2777
2778 if (is_variable && zend_is_function_or_method_call(value)) {
2779 opline->extended_value = ZEND_RETURNS_FUNCTION;
2780 }
2781 } else {
2782 SET_UNUSED(opline->op1);
2783 }
2784
2785 if (key) {
2786 SET_NODE(opline->op2, key);
2787 } else {
2788 SET_UNUSED(opline->op2);
2789 }
2790
2791 opline->result_type = IS_VAR;
2792 opline->result.var = get_temporary_variable(CG(active_op_array));
2793 GET_NODE(result, opline->result);
2794 }
2795 /* }}} */
2796
zend_add_try_element(zend_uint try_op TSRMLS_DC)2797 static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
2798 {
2799 int try_catch_offset = CG(active_op_array)->last_try_catch++;
2800
2801 CG(active_op_array)->try_catch_array = erealloc(CG(active_op_array)->try_catch_array, sizeof(zend_try_catch_element)*CG(active_op_array)->last_try_catch);
2802 CG(active_op_array)->try_catch_array[try_catch_offset].try_op = try_op;
2803 CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = 0;
2804 CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = 0;
2805 CG(active_op_array)->try_catch_array[try_catch_offset].finally_end = 0;
2806 return try_catch_offset;
2807 }
2808 /* }}} */
2809
zend_add_catch_element(int offset,zend_uint catch_op TSRMLS_DC)2810 static void zend_add_catch_element(int offset, zend_uint catch_op TSRMLS_DC) /* {{{ */
2811 {
2812 CG(active_op_array)->try_catch_array[offset].catch_op = catch_op;
2813 }
2814 /* }}} */
2815
zend_do_first_catch(znode * open_parentheses TSRMLS_DC)2816 void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */
2817 {
2818 open_parentheses->u.op.opline_num = get_next_op_number(CG(active_op_array));
2819 }
2820 /* }}} */
2821
zend_initialize_try_catch_element(znode * catch_token TSRMLS_DC)2822 void zend_initialize_try_catch_element(znode *catch_token TSRMLS_DC) /* {{{ */
2823 {
2824 int jmp_op_number = get_next_op_number(CG(active_op_array));
2825 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2826 zend_llist jmp_list;
2827 zend_llist *jmp_list_ptr;
2828
2829 opline->opcode = ZEND_JMP;
2830 SET_UNUSED(opline->op1);
2831 SET_UNUSED(opline->op2);
2832 /* save for backpatching */
2833
2834 zend_llist_init(&jmp_list, sizeof(int), NULL, 0);
2835 zend_stack_push(&CG(bp_stack), (void *) &jmp_list, sizeof(zend_llist));
2836 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2837 zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2838
2839 catch_token->EA = get_next_op_number(CG(active_op_array));
2840 }
2841 /* }}} */
2842
zend_do_mark_last_catch(const znode * first_catch,const znode * last_additional_catch TSRMLS_DC)2843 void zend_do_mark_last_catch(const znode *first_catch, const znode *last_additional_catch TSRMLS_DC) /* {{{ */
2844 {
2845 CG(active_op_array)->last--;
2846 zend_do_if_end(TSRMLS_C);
2847 if (last_additional_catch->u.op.opline_num == -1) {
2848 CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1;
2849 CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2850 } else {
2851 CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].result.num = 1;
2852 CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2853 }
2854 DEC_BPC(CG(active_op_array));
2855 }
2856 /* }}} */
2857
zend_do_try(znode * try_token TSRMLS_DC)2858 void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */
2859 {
2860 try_token->u.op.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC);
2861 INC_BPC(CG(active_op_array));
2862 }
2863 /* }}} */
2864
zend_do_finally(znode * finally_token TSRMLS_DC)2865 void zend_do_finally(znode *finally_token TSRMLS_DC) /* {{{ */
2866 {
2867 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2868
2869 finally_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
2870 /* call the the "finally" block */
2871 opline->opcode = ZEND_FAST_CALL;
2872 SET_UNUSED(opline->op1);
2873 opline->op1.opline_num = finally_token->u.op.opline_num + 1;
2874 SET_UNUSED(opline->op2);
2875 /* jump to code after the "finally" block,
2876 * the actual jump address is going to be set in zend_do_end_finally()
2877 */
2878 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2879 opline->opcode = ZEND_JMP;
2880 SET_UNUSED(opline->op1);
2881 SET_UNUSED(opline->op2);
2882
2883 CG(context).in_finally++;
2884 }
2885 /* }}} */
2886
zend_do_begin_catch(znode * catch_token,znode * class_name,znode * catch_var,znode * first_catch TSRMLS_DC)2887 void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */
2888 {
2889 long catch_op_number;
2890 zend_op *opline;
2891 znode catch_class;
2892
2893 if (class_name->op_type == IS_CONST &&
2894 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
2895 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
2896 catch_class = *class_name;
2897 } else {
2898 zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
2899 }
2900
2901 catch_op_number = get_next_op_number(CG(active_op_array));
2902 if (first_catch) {
2903 first_catch->u.op.opline_num = catch_op_number;
2904 }
2905
2906 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2907 opline->opcode = ZEND_CATCH;
2908 opline->op1_type = IS_CONST;
2909 opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC);
2910 opline->op2_type = IS_CV;
2911 opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len, 0 TSRMLS_CC);
2912 Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
2913 opline->result.num = 0; /* 1 means it's the last catch in the block */
2914
2915 catch_token->u.op.opline_num = catch_op_number;
2916 }
2917 /* }}} */
2918
zend_do_end_catch(znode * catch_token TSRMLS_DC)2919 void zend_do_end_catch(znode *catch_token TSRMLS_DC) /* {{{ */
2920 {
2921 int jmp_op_number = get_next_op_number(CG(active_op_array));
2922 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2923 zend_llist *jmp_list_ptr;
2924
2925 opline->opcode = ZEND_JMP;
2926 SET_UNUSED(opline->op1);
2927 SET_UNUSED(opline->op2);
2928 /* save for backpatching */
2929
2930 zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr);
2931 zend_llist_add_element(jmp_list_ptr, &jmp_op_number);
2932
2933 CG(active_op_array)->opcodes[catch_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
2934 }
2935 /* }}} */
2936
zend_do_bind_catch(znode * try_token,znode * catch_token TSRMLS_DC)2937 void zend_do_bind_catch(znode *try_token, znode *catch_token TSRMLS_DC) /* {{{ */ {
2938 if (catch_token->op_type != IS_UNUSED) {
2939 zend_add_catch_element(try_token->u.op.opline_num, catch_token->EA TSRMLS_CC);
2940 }
2941 }
2942 /* }}} */
2943
zend_do_end_finally(znode * try_token,znode * catch_token,znode * finally_token TSRMLS_DC)2944 void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_token TSRMLS_DC) /* {{{ */
2945 {
2946 if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
2947 zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
2948 }
2949 if (finally_token->op_type != IS_UNUSED) {
2950 zend_op *opline;
2951
2952 CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
2953 CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
2954 CG(active_op_array)->has_finally_block = 1;
2955
2956 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2957 opline->opcode = ZEND_FAST_RET;
2958 SET_UNUSED(opline->op1);
2959 SET_UNUSED(opline->op2);
2960
2961 CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
2962
2963 CG(context).in_finally--;
2964 }
2965 }
2966 /* }}} */
2967
zend_do_throw(const znode * expr TSRMLS_DC)2968 void zend_do_throw(const znode *expr TSRMLS_DC) /* {{{ */
2969 {
2970 zend_op *opline;
2971
2972 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
2973 opline->opcode = ZEND_THROW;
2974 SET_NODE(opline->op1, expr);
2975 SET_UNUSED(opline->op2);
2976 }
2977 /* }}} */
2978
function_add_ref(zend_function * function)2979 ZEND_API void function_add_ref(zend_function *function) /* {{{ */
2980 {
2981 if (function->type == ZEND_USER_FUNCTION) {
2982 zend_op_array *op_array = &function->op_array;
2983
2984 (*op_array->refcount)++;
2985 if (op_array->static_variables) {
2986 HashTable *static_variables = op_array->static_variables;
2987 zval *tmp_zval;
2988
2989 ALLOC_HASHTABLE(op_array->static_variables);
2990 zend_hash_init(op_array->static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
2991 zend_hash_copy(op_array->static_variables, static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_zval, sizeof(zval *));
2992 }
2993 op_array->run_time_cache = NULL;
2994 }
2995 }
2996 /* }}} */
2997
do_inherit_parent_constructor(zend_class_entry * ce)2998 static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
2999 {
3000 zend_function *function, *new_function;
3001
3002 if (!ce->parent) {
3003 return;
3004 }
3005
3006 /* You cannot change create_object */
3007 ce->create_object = ce->parent->create_object;
3008
3009 /* Inherit special functions if needed */
3010 if (!ce->get_iterator) {
3011 ce->get_iterator = ce->parent->get_iterator;
3012 }
3013 if (!ce->iterator_funcs.funcs) {
3014 ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
3015 }
3016 if (!ce->__get) {
3017 ce->__get = ce->parent->__get;
3018 }
3019 if (!ce->__set) {
3020 ce->__set = ce->parent->__set;
3021 }
3022 if (!ce->__unset) {
3023 ce->__unset = ce->parent->__unset;
3024 }
3025 if (!ce->__isset) {
3026 ce->__isset = ce->parent->__isset;
3027 }
3028 if (!ce->__call) {
3029 ce->__call = ce->parent->__call;
3030 }
3031 if (!ce->__callstatic) {
3032 ce->__callstatic = ce->parent->__callstatic;
3033 }
3034 if (!ce->__tostring) {
3035 ce->__tostring = ce->parent->__tostring;
3036 }
3037 if (!ce->clone) {
3038 ce->clone = ce->parent->clone;
3039 }
3040 if(!ce->serialize) {
3041 ce->serialize = ce->parent->serialize;
3042 }
3043 if(!ce->unserialize) {
3044 ce->unserialize = ce->parent->unserialize;
3045 }
3046 if (!ce->destructor) {
3047 ce->destructor = ce->parent->destructor;
3048 }
3049 if (ce->constructor) {
3050 if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
3051 zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
3052 ce->parent->name, ce->parent->constructor->common.function_name,
3053 ce->name, ce->constructor->common.function_name
3054 );
3055 }
3056 return;
3057 }
3058
3059 if (zend_hash_find(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), (void **)&function)==SUCCESS) {
3060 /* inherit parent's constructor */
3061 zend_hash_update(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME), function, sizeof(zend_function), (void**)&new_function);
3062 function_add_ref(new_function);
3063 } else {
3064 /* Don't inherit the old style constructor if we already have the new style constructor */
3065 char *lc_class_name;
3066 char *lc_parent_class_name;
3067
3068 lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
3069 if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
3070 lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
3071 if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
3072 zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
3073 if (function->common.fn_flags & ZEND_ACC_CTOR) {
3074 /* inherit parent's constructor */
3075 zend_hash_update(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1, function, sizeof(zend_function), (void**)&new_function);
3076 function_add_ref(new_function);
3077 }
3078 }
3079 efree(lc_parent_class_name);
3080 }
3081 efree(lc_class_name);
3082 }
3083 ce->constructor = ce->parent->constructor;
3084 }
3085 /* }}} */
3086
zend_visibility_string(zend_uint fn_flags)3087 char *zend_visibility_string(zend_uint fn_flags) /* {{{ */
3088 {
3089 if (fn_flags & ZEND_ACC_PRIVATE) {
3090 return "private";
3091 }
3092 if (fn_flags & ZEND_ACC_PROTECTED) {
3093 return "protected";
3094 }
3095 if (fn_flags & ZEND_ACC_PUBLIC) {
3096 return "public";
3097 }
3098 return "";
3099 }
3100 /* }}} */
3101
do_inherit_method(zend_function * function)3102 static void do_inherit_method(zend_function *function) /* {{{ */
3103 {
3104 /* The class entry of the derived function intentionally remains the same
3105 * as that of the parent class. That allows us to know in which context
3106 * we're running, and handle private method calls properly.
3107 */
3108 function_add_ref(function);
3109 }
3110 /* }}} */
3111
zend_do_perform_implementation_check(const zend_function * fe,const zend_function * proto TSRMLS_DC)3112 static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
3113 {
3114 zend_uint i;
3115
3116 /* If it's a user function then arg_info == NULL means we don't have any parameters but
3117 * we still need to do the arg number checks. We are only willing to ignore this for internal
3118 * functions because extensions don't always define arg_info.
3119 */
3120 if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
3121 return 1;
3122 }
3123
3124 /* Checks for constructors only if they are declared in an interface,
3125 * or explicitly marked as abstract
3126 */
3127 if ((fe->common.fn_flags & ZEND_ACC_CTOR)
3128 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3129 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
3130 return 1;
3131 }
3132
3133 /* If both methods are private do not enforce a signature */
3134 if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
3135 return 1;
3136 }
3137
3138 /* check number of arguments */
3139 if (proto->common.required_num_args < fe->common.required_num_args
3140 || proto->common.num_args > fe->common.num_args) {
3141 return 0;
3142 }
3143
3144 if (fe->common.type != ZEND_USER_FUNCTION
3145 && (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0
3146 && (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) {
3147 return 0;
3148 }
3149
3150 /* by-ref constraints on return values are covariant */
3151 if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
3152 && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
3153 return 0;
3154 }
3155
3156 for (i=0; i < proto->common.num_args; i++) {
3157 if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) {
3158 /* Only one has a type hint and the other one doesn't */
3159 return 0;
3160 }
3161
3162 if (fe->common.arg_info[i].class_name) {
3163 const char *fe_class_name, *proto_class_name;
3164 zend_uint fe_class_name_len, proto_class_name_len;
3165
3166 if (!strcasecmp(fe->common.arg_info[i].class_name, "parent") && proto->common.scope) {
3167 fe_class_name = proto->common.scope->name;
3168 fe_class_name_len = proto->common.scope->name_length;
3169 } else if (!strcasecmp(fe->common.arg_info[i].class_name, "self") && fe->common.scope) {
3170 fe_class_name = fe->common.scope->name;
3171 fe_class_name_len = fe->common.scope->name_length;
3172 } else {
3173 fe_class_name = fe->common.arg_info[i].class_name;
3174 fe_class_name_len = fe->common.arg_info[i].class_name_len;
3175 }
3176
3177 if (!strcasecmp(proto->common.arg_info[i].class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
3178 proto_class_name = proto->common.scope->parent->name;
3179 proto_class_name_len = proto->common.scope->parent->name_length;
3180 } else if (!strcasecmp(proto->common.arg_info[i].class_name, "self") && proto->common.scope) {
3181 proto_class_name = proto->common.scope->name;
3182 proto_class_name_len = proto->common.scope->name_length;
3183 } else {
3184 proto_class_name = proto->common.arg_info[i].class_name;
3185 proto_class_name_len = proto->common.arg_info[i].class_name_len;
3186 }
3187
3188 if (strcasecmp(fe_class_name, proto_class_name)!=0) {
3189 const char *colon;
3190
3191 if (fe->common.type != ZEND_USER_FUNCTION) {
3192 return 0;
3193 } else if (strchr(proto_class_name, '\\') != NULL ||
3194 (colon = zend_memrchr(fe_class_name, '\\', fe_class_name_len)) == NULL ||
3195 strcasecmp(colon+1, proto_class_name) != 0) {
3196 zend_class_entry **fe_ce, **proto_ce;
3197 int found, found2;
3198
3199 found = zend_lookup_class(fe_class_name, fe_class_name_len, &fe_ce TSRMLS_CC);
3200 found2 = zend_lookup_class(proto_class_name, proto_class_name_len, &proto_ce TSRMLS_CC);
3201
3202 /* Check for class alias */
3203 if (found != SUCCESS || found2 != SUCCESS ||
3204 (*fe_ce)->type == ZEND_INTERNAL_CLASS ||
3205 (*proto_ce)->type == ZEND_INTERNAL_CLASS ||
3206 *fe_ce != *proto_ce) {
3207 return 0;
3208 }
3209 }
3210 }
3211 }
3212 if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
3213 /* Incompatible type hint */
3214 return 0;
3215 }
3216
3217 /* by-ref constraints on arguments are invariant */
3218 if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
3219 return 0;
3220 }
3221 }
3222
3223 if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) {
3224 for (i=proto->common.num_args; i < fe->common.num_args; i++) {
3225 if (!fe->common.arg_info[i].pass_by_reference) {
3226 return 0;
3227 }
3228 }
3229 }
3230 return 1;
3231 }
3232 /* }}} */
3233
3234 #define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
3235 if (UNEXPECTED(offset - buf + size >= length)) { \
3236 length += size + 1; \
3237 buf = erealloc(buf, length); \
3238 }
3239
zend_get_function_declaration(zend_function * fptr TSRMLS_DC)3240 static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
3241 {
3242 char *offset, *buf;
3243 zend_uint length = 1024;
3244
3245 offset = buf = (char *)emalloc(length * sizeof(char));
3246 if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3247 *(offset++) = '&';
3248 *(offset++) = ' ';
3249 }
3250
3251 if (fptr->common.scope) {
3252 memcpy(offset, fptr->common.scope->name, fptr->common.scope->name_length);
3253 offset += fptr->common.scope->name_length;
3254 *(offset++) = ':';
3255 *(offset++) = ':';
3256 }
3257
3258 {
3259 size_t name_len = strlen(fptr->common.function_name);
3260 REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
3261 memcpy(offset, fptr->common.function_name, name_len);
3262 offset += name_len;
3263 }
3264
3265 *(offset++) = '(';
3266 if (fptr->common.arg_info) {
3267 zend_uint i, required;
3268 zend_arg_info *arg_info = fptr->common.arg_info;
3269
3270 required = fptr->common.required_num_args;
3271 for (i = 0; i < fptr->common.num_args;) {
3272 if (arg_info->class_name) {
3273 const char *class_name;
3274 zend_uint class_name_len;
3275 if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
3276 class_name = fptr->common.scope->name;
3277 class_name_len = fptr->common.scope->name_length;
3278 } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
3279 class_name = fptr->common.scope->parent->name;
3280 class_name_len = fptr->common.scope->parent->name_length;
3281 } else {
3282 class_name = arg_info->class_name;
3283 class_name_len = arg_info->class_name_len;
3284 }
3285 REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
3286 memcpy(offset, class_name, class_name_len);
3287 offset += class_name_len;
3288 *(offset++) = ' ';
3289 } else if (arg_info->type_hint) {
3290 zend_uint type_name_len;
3291 char *type_name = zend_get_type_by_const(arg_info->type_hint);
3292 type_name_len = strlen(type_name);
3293 REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
3294 memcpy(offset, type_name, type_name_len);
3295 offset += type_name_len;
3296 *(offset++) = ' ';
3297 }
3298
3299 if (arg_info->pass_by_reference) {
3300 *(offset++) = '&';
3301 }
3302 *(offset++) = '$';
3303
3304 if (arg_info->name) {
3305 REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
3306 memcpy(offset, arg_info->name, arg_info->name_len);
3307 offset += arg_info->name_len;
3308 } else {
3309 zend_uint idx = i;
3310 memcpy(offset, "param", 5);
3311 offset += 5;
3312 do {
3313 *(offset++) = (char) (idx % 10) + '0';
3314 idx /= 10;
3315 } while (idx > 0);
3316 }
3317 if (i >= required) {
3318 *(offset++) = ' ';
3319 *(offset++) = '=';
3320 *(offset++) = ' ';
3321 if (fptr->type == ZEND_USER_FUNCTION) {
3322 zend_op *precv = NULL;
3323 {
3324 zend_uint idx = i;
3325 zend_op *op = ((zend_op_array *)fptr)->opcodes;
3326 zend_op *end = op + ((zend_op_array *)fptr)->last;
3327
3328 ++idx;
3329 while (op < end) {
3330 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
3331 && op->op1.num == (long)idx)
3332 {
3333 precv = op;
3334 }
3335 ++op;
3336 }
3337 }
3338 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
3339 zval *zv, zv_copy;
3340 int use_copy;
3341 ALLOC_ZVAL(zv);
3342 *zv = *precv->op2.zv;
3343 zval_copy_ctor(zv);
3344 INIT_PZVAL(zv);
3345 if ((Z_TYPE_P(zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
3346 REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
3347 memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
3348 offset += Z_STRLEN_P(zv);
3349 } else if (Z_TYPE_P(zv) == IS_BOOL) {
3350 if (Z_LVAL_P(zv)) {
3351 memcpy(offset, "true", 4);
3352 offset += 4;
3353 } else {
3354 memcpy(offset, "false", 5);
3355 offset += 5;
3356 }
3357 } else if (Z_TYPE_P(zv) == IS_NULL) {
3358 memcpy(offset, "NULL", 4);
3359 offset += 4;
3360 } else if (Z_TYPE_P(zv) == IS_STRING) {
3361 *(offset++) = '\'';
3362 REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
3363 memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
3364 offset += MIN(Z_STRLEN_P(zv), 10);
3365 if (Z_STRLEN_P(zv) > 10) {
3366 *(offset++) = '.';
3367 *(offset++) = '.';
3368 *(offset++) = '.';
3369 }
3370 *(offset++) = '\'';
3371 } else if (Z_TYPE_P(zv) == IS_ARRAY || (Z_TYPE_P(zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT_ARRAY) {
3372 memcpy(offset, "Array", 5);
3373 offset += 5;
3374 } else {
3375 zend_make_printable_zval(zv, &zv_copy, &use_copy);
3376 REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN(zv_copy));
3377 memcpy(offset, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
3378 offset += Z_STRLEN(zv_copy);
3379 if (use_copy) {
3380 zval_dtor(&zv_copy);
3381 }
3382 }
3383 zval_ptr_dtor(&zv);
3384 }
3385 } else {
3386 memcpy(offset, "NULL", 4);
3387 offset += 4;
3388 }
3389 }
3390
3391 if (++i < fptr->common.num_args) {
3392 *(offset++) = ',';
3393 *(offset++) = ' ';
3394 }
3395 arg_info++;
3396 REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
3397 }
3398 }
3399 *(offset++) = ')';
3400 *offset = '\0';
3401
3402 return buf;
3403 }
3404 /* }}} */
3405
do_inheritance_check_on_method(zend_function * child,zend_function * parent TSRMLS_DC)3406 static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
3407 {
3408 zend_uint child_flags;
3409 zend_uint parent_flags = parent->common.fn_flags;
3410
3411 if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
3412 && parent->common.fn_flags & ZEND_ACC_ABSTRACT
3413 && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
3414 && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
3415 zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
3416 parent->common.scope->name,
3417 child->common.function_name,
3418 child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);
3419 }
3420
3421 if (parent_flags & ZEND_ACC_FINAL) {
3422 zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name);
3423 }
3424
3425 child_flags = child->common.fn_flags;
3426 /* You cannot change from static to non static and vice versa.
3427 */
3428 if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
3429 if (child->common.fn_flags & ZEND_ACC_STATIC) {
3430 zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3431 } else {
3432 zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3433 }
3434 }
3435
3436 /* Disallow making an inherited method abstract. */
3437 if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
3438 zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
3439 }
3440
3441 if (parent_flags & ZEND_ACC_CHANGED) {
3442 child->common.fn_flags |= ZEND_ACC_CHANGED;
3443 } else {
3444 /* Prevent derived classes from restricting access that was available in parent classes
3445 */
3446 if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
3447 zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
3448 } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
3449 && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
3450 child->common.fn_flags |= ZEND_ACC_CHANGED;
3451 }
3452 }
3453
3454 if (parent_flags & ZEND_ACC_PRIVATE) {
3455 child->common.prototype = NULL;
3456 } else if (parent_flags & ZEND_ACC_ABSTRACT) {
3457 child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
3458 child->common.prototype = parent;
3459 } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
3460 /* ctors only have a prototype if it comes from an interface */
3461 child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
3462 }
3463
3464 if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3465 if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
3466 zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
3467 }
3468 } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
3469 if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
3470 char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
3471 zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
3472 efree(method_prototype);
3473 }
3474 }
3475 }
3476 /* }}} */
3477
do_inherit_method_check(HashTable * child_function_table,zend_function * parent,const zend_hash_key * hash_key,zend_class_entry * child_ce)3478 static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, const zend_hash_key *hash_key, zend_class_entry *child_ce) /* {{{ */
3479 {
3480 zend_uint parent_flags = parent->common.fn_flags;
3481 zend_function *child;
3482 TSRMLS_FETCH();
3483
3484 if (zend_hash_quick_find(child_function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child)==FAILURE) {
3485 if (parent_flags & (ZEND_ACC_ABSTRACT)) {
3486 child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3487 }
3488 return 1; /* method doesn't exist in child, copy from parent */
3489 }
3490
3491 do_inheritance_check_on_method(child, parent TSRMLS_CC);
3492
3493 return 0;
3494 }
3495 /* }}} */
3496
do_inherit_property_access_check(HashTable * target_ht,zend_property_info * parent_info,const zend_hash_key * hash_key,zend_class_entry * ce)3497 static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, const zend_hash_key *hash_key, zend_class_entry *ce) /* {{{ */
3498 {
3499 zend_property_info *child_info;
3500 zend_class_entry *parent_ce = ce->parent;
3501
3502 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
3503 if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3504 child_info->flags |= ZEND_ACC_CHANGED;
3505 } else {
3506 zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info);
3507 if(ce->type & ZEND_INTERNAL_CLASS) {
3508 zend_duplicate_property_info_internal(child_info);
3509 } else {
3510 zend_duplicate_property_info(child_info);
3511 }
3512 child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
3513 child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
3514 }
3515 return 0; /* don't copy access information to child */
3516 }
3517
3518 if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {
3519 if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
3520 zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
3521 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,
3522 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
3523
3524 }
3525
3526 if(parent_info->flags & ZEND_ACC_CHANGED) {
3527 child_info->flags |= ZEND_ACC_CHANGED;
3528 }
3529
3530 if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
3531 zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
3532 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
3533 zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
3534 ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
3535 ce->default_properties_table[child_info->offset] = NULL;
3536 child_info->offset = parent_info->offset;
3537 }
3538 return 0; /* Don't copy from parent */
3539 } else {
3540 return 1; /* Copy from parent */
3541 }
3542 }
3543 /* }}} */
3544
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface TSRMLS_DC)3545 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3546 {
3547 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
3548 zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name);
3549 }
3550 if (ce == iface) {
3551 zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name);
3552 }
3553 }
3554 /* }}} */
3555
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface TSRMLS_DC)3556 ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
3557 {
3558 /* expects interface to be contained in ce's interface list already */
3559 zend_uint i, ce_num, if_num = iface->num_interfaces;
3560 zend_class_entry *entry;
3561
3562 if (if_num==0) {
3563 return;
3564 }
3565 ce_num = ce->num_interfaces;
3566
3567 if (ce->type == ZEND_INTERNAL_CLASS) {
3568 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3569 } else {
3570 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
3571 }
3572
3573 /* Inherit the interfaces, only if they're not already inherited by the class */
3574 while (if_num--) {
3575 entry = iface->interfaces[if_num];
3576 for (i = 0; i < ce_num; i++) {
3577 if (ce->interfaces[i] == entry) {
3578 break;
3579 }
3580 }
3581 if (i == ce_num) {
3582 ce->interfaces[ce->num_interfaces++] = entry;
3583 }
3584 }
3585
3586 /* and now call the implementing handlers */
3587 while (ce_num < ce->num_interfaces) {
3588 do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
3589 }
3590 }
3591 /* }}} */
3592
3593 #ifdef ZTS
zval_internal_ctor(zval ** p)3594 static void zval_internal_ctor(zval **p) /* {{{ */
3595 {
3596 zval *orig_ptr = *p;
3597
3598 ALLOC_ZVAL(*p);
3599 MAKE_COPY_ZVAL(&orig_ptr, *p);
3600 }
3601 /* }}} */
3602
3603 # define zval_property_ctor(parent_ce, ce) \
3604 ((void (*)(void *)) (((parent_ce)->type != (ce)->type) ? zval_internal_ctor : zval_add_ref))
3605 #else
3606 # define zval_property_ctor(parent_ce, ce) \
3607 ((void (*)(void *)) zval_add_ref)
3608 #endif
3609
zend_do_inheritance(zend_class_entry * ce,zend_class_entry * parent_ce TSRMLS_DC)3610 ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
3611 {
3612 zend_property_info *property_info;
3613
3614 if ((ce->ce_flags & ZEND_ACC_INTERFACE)
3615 && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
3616 zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
3617 }
3618 if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
3619 zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name);
3620 }
3621
3622 ce->parent = parent_ce;
3623 /* Copy serialize/unserialize callbacks */
3624 if (!ce->serialize) {
3625 ce->serialize = parent_ce->serialize;
3626 }
3627 if (!ce->unserialize) {
3628 ce->unserialize = parent_ce->unserialize;
3629 }
3630
3631 /* Inherit interfaces */
3632 zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
3633
3634 /* Inherit properties */
3635 if (parent_ce->default_properties_count) {
3636 int i = ce->default_properties_count + parent_ce->default_properties_count;
3637
3638 ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3639 if (ce->default_properties_count) {
3640 while (i-- > parent_ce->default_properties_count) {
3641 ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
3642 }
3643 }
3644 for (i = 0; i < parent_ce->default_properties_count; i++) {
3645 ce->default_properties_table[i] = parent_ce->default_properties_table[i];
3646 if (ce->default_properties_table[i]) {
3647 #ifdef ZTS
3648 if (parent_ce->type != ce->type) {
3649 zval *p;
3650
3651 ALLOC_ZVAL(p);
3652 MAKE_COPY_ZVAL(&ce->default_properties_table[i], p);
3653 ce->default_properties_table[i] = p;
3654 } else {
3655 Z_ADDREF_P(ce->default_properties_table[i]);
3656 }
3657 #else
3658 Z_ADDREF_P(ce->default_properties_table[i]);
3659 #endif
3660 }
3661 }
3662 ce->default_properties_count += parent_ce->default_properties_count;
3663 }
3664
3665 if (parent_ce->type != ce->type) {
3666 /* User class extends internal class */
3667 zend_update_class_constants(parent_ce TSRMLS_CC);
3668 if (parent_ce->default_static_members_count) {
3669 int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3670
3671 ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i);
3672 if (ce->default_static_members_count) {
3673 while (i-- > parent_ce->default_static_members_count) {
3674 ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3675 }
3676 }
3677 for (i = 0; i < parent_ce->default_static_members_count; i++) {
3678 SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
3679 ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
3680 Z_ADDREF_P(ce->default_static_members_table[i]);
3681 }
3682 ce->default_static_members_count += parent_ce->default_static_members_count;
3683 ce->static_members_table = ce->default_static_members_table;
3684 }
3685 } else {
3686 if (parent_ce->default_static_members_count) {
3687 int i = ce->default_static_members_count + parent_ce->default_static_members_count;
3688
3689 ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS);
3690 if (ce->default_static_members_count) {
3691 while (i-- > parent_ce->default_static_members_count) {
3692 ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
3693 }
3694 }
3695 for (i = 0; i < parent_ce->default_static_members_count; i++) {
3696 SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]);
3697 ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
3698 Z_ADDREF_P(ce->default_static_members_table[i]);
3699 }
3700 ce->default_static_members_count += parent_ce->default_static_members_count;
3701 if (ce->type == ZEND_USER_CLASS) {
3702 ce->static_members_table = ce->default_static_members_table;
3703 }
3704 }
3705 }
3706
3707 for (zend_hash_internal_pointer_reset(&ce->properties_info);
3708 zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS;
3709 zend_hash_move_forward(&ce->properties_info)) {
3710 if (property_info->ce == ce) {
3711 if (property_info->flags & ZEND_ACC_STATIC) {
3712 property_info->offset += parent_ce->default_static_members_count;
3713 } else {
3714 property_info->offset += parent_ce->default_properties_count;
3715 }
3716 }
3717 }
3718
3719 zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce);
3720
3721 zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, zval_property_ctor(parent_ce, ce), NULL, sizeof(zval *), 0);
3722 zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
3723 do_inherit_parent_constructor(ce);
3724
3725 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
3726 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
3727 } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
3728 /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
3729 zend_verify_abstract_class(ce TSRMLS_CC);
3730 }
3731 ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
3732 }
3733 /* }}} */
3734
do_inherit_constant_check(HashTable * child_constants_table,const zval ** parent_constant,const zend_hash_key * hash_key,const zend_class_entry * iface)3735 static zend_bool do_inherit_constant_check(HashTable *child_constants_table, const zval **parent_constant, const zend_hash_key *hash_key, const zend_class_entry *iface) /* {{{ */
3736 {
3737 zval **old_constant;
3738
3739 if (zend_hash_quick_find(child_constants_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void**)&old_constant) == SUCCESS) {
3740 if (*old_constant != *parent_constant) {
3741 zend_error(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", hash_key->arKey, iface->name);
3742 }
3743 return 0;
3744 }
3745 return 1;
3746 }
3747 /* }}} */
3748
do_interface_constant_check(zval ** val TSRMLS_DC,int num_args,va_list args,const zend_hash_key * key)3749 static int do_interface_constant_check(zval **val TSRMLS_DC, int num_args, va_list args, const zend_hash_key *key) /* {{{ */
3750 {
3751 zend_class_entry **iface = va_arg(args, zend_class_entry**);
3752
3753 do_inherit_constant_check(&(*iface)->constants_table, (const zval **) val, key, *iface);
3754
3755 return ZEND_HASH_APPLY_KEEP;
3756 }
3757 /* }}} */
3758
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface TSRMLS_DC)3759 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
3760 {
3761 zend_uint i, ignore = 0;
3762 zend_uint current_iface_num = ce->num_interfaces;
3763 zend_uint parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
3764
3765 for (i = 0; i < ce->num_interfaces; i++) {
3766 if (ce->interfaces[i] == NULL) {
3767 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
3768 i--;
3769 } else if (ce->interfaces[i] == iface) {
3770 if (i < parent_iface_num) {
3771 ignore = 1;
3772 } else {
3773 zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name);
3774 }
3775 }
3776 }
3777 if (ignore) {
3778 /* Check for attempt to redeclare interface constants */
3779 zend_hash_apply_with_arguments(&ce->constants_table TSRMLS_CC, (apply_func_args_t) do_interface_constant_check, 1, &iface);
3780 } else {
3781 if (ce->num_interfaces >= current_iface_num) {
3782 if (ce->type == ZEND_INTERNAL_CLASS) {
3783 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3784 } else {
3785 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
3786 }
3787 }
3788 ce->interfaces[ce->num_interfaces++] = iface;
3789
3790 zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
3791 zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
3792
3793 do_implement_interface(ce, iface TSRMLS_CC);
3794 zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
3795 }
3796 }
3797 /* }}} */
3798
zend_do_implement_trait(zend_class_entry * ce,zend_class_entry * trait TSRMLS_DC)3799 ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
3800 {
3801 zend_uint i, ignore = 0;
3802 zend_uint current_trait_num = ce->num_traits;
3803 zend_uint parent_trait_num = ce->parent ? ce->parent->num_traits : 0;
3804
3805 for (i = 0; i < ce->num_traits; i++) {
3806 if (ce->traits[i] == NULL) {
3807 memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
3808 i--;
3809 } else if (ce->traits[i] == trait) {
3810 if (i < parent_trait_num) {
3811 ignore = 1;
3812 }
3813 }
3814 }
3815 if (!ignore) {
3816 if (ce->num_traits >= current_trait_num) {
3817 if (ce->type == ZEND_INTERNAL_CLASS) {
3818 ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3819 } else {
3820 ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
3821 }
3822 }
3823 ce->traits[ce->num_traits++] = trait;
3824 }
3825 }
3826 /* }}} */
3827
zend_traits_method_compatibility_check(zend_function * fn,zend_function * other_fn TSRMLS_DC)3828 static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
3829 {
3830 zend_uint fn_flags = fn->common.scope->ce_flags;
3831 zend_uint other_flags = other_fn->common.scope->ce_flags;
3832
3833 return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
3834 && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
3835 && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
3836 (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
3837 }
3838 /* }}} */
3839
zend_add_magic_methods(zend_class_entry * ce,const char * mname,uint mname_len,zend_function * fe TSRMLS_DC)3840 static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint mname_len, zend_function* fe TSRMLS_DC) /* {{{ */
3841 {
3842 if (!strncmp(mname, ZEND_CLONE_FUNC_NAME, mname_len)) {
3843 ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
3844 } else if (!strncmp(mname, ZEND_CONSTRUCTOR_FUNC_NAME, mname_len)) {
3845 if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
3846 zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3847 }
3848 ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
3849 } else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME, mname_len)) {
3850 ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
3851 } else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) {
3852 ce->__get = fe;
3853 } else if (!strncmp(mname, ZEND_SET_FUNC_NAME, mname_len)) {
3854 ce->__set = fe;
3855 } else if (!strncmp(mname, ZEND_CALL_FUNC_NAME, mname_len)) {
3856 ce->__call = fe;
3857 } else if (!strncmp(mname, ZEND_UNSET_FUNC_NAME, mname_len)) {
3858 ce->__unset = fe;
3859 } else if (!strncmp(mname, ZEND_ISSET_FUNC_NAME, mname_len)) {
3860 ce->__isset = fe;
3861 } else if (!strncmp(mname, ZEND_CALLSTATIC_FUNC_NAME, mname_len)) {
3862 ce->__callstatic = fe;
3863 } else if (!strncmp(mname, ZEND_TOSTRING_FUNC_NAME, mname_len)) {
3864 ce->__tostring = fe;
3865 } else if (ce->name_length + 1 == mname_len) {
3866 char *lowercase_name = emalloc(ce->name_length + 1);
3867 zend_str_tolower_copy(lowercase_name, ce->name, ce->name_length);
3868 lowercase_name = (char*)zend_new_interned_string(lowercase_name, ce->name_length + 1, 1 TSRMLS_CC);
3869 if (!memcmp(mname, lowercase_name, mname_len)) {
3870 if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
3871 zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
3872 }
3873 ce->constructor = fe;
3874 fe->common.fn_flags |= ZEND_ACC_CTOR;
3875 }
3876 str_efree(lowercase_name);
3877 }
3878 }
3879 /* }}} */
3880
zend_add_trait_method(zend_class_entry * ce,const char * name,const char * arKey,uint nKeyLength,zend_function * fn,HashTable ** overriden TSRMLS_DC)3881 static void zend_add_trait_method(zend_class_entry *ce, const char *name, const char *arKey, uint nKeyLength, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
3882 {
3883 zend_function *existing_fn = NULL;
3884 ulong h = zend_hash_func(arKey, nKeyLength);
3885
3886 if (zend_hash_quick_find(&ce->function_table, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3887 if (existing_fn->common.scope == ce) {
3888 /* members from the current class override trait methods */
3889 /* use temporary *overriden HashTable to detect hidden conflict */
3890 if (*overriden) {
3891 if (zend_hash_quick_find(*overriden, arKey, nKeyLength, h, (void**) &existing_fn) == SUCCESS) {
3892 if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3893 /* Make sure the trait method is compatible with previosly declared abstract method */
3894 if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3895 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3896 zend_get_function_declaration(fn TSRMLS_CC),
3897 zend_get_function_declaration(existing_fn TSRMLS_CC));
3898 }
3899 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3900 /* Make sure the abstract declaration is compatible with previous declaration */
3901 if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3902 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3903 zend_get_function_declaration(fn TSRMLS_CC),
3904 zend_get_function_declaration(existing_fn TSRMLS_CC));
3905 }
3906 return;
3907 }
3908 }
3909 } else {
3910 ALLOC_HASHTABLE(*overriden);
3911 zend_hash_init_ex(*overriden, 2, NULL, NULL, 0, 0);
3912 }
3913 zend_hash_quick_update(*overriden, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3914 return;
3915 } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT &&
3916 (existing_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0) {
3917 /* Make sure the trait method is compatible with previosly declared abstract method */
3918 if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
3919 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3920 zend_get_function_declaration(fn TSRMLS_CC),
3921 zend_get_function_declaration(existing_fn TSRMLS_CC));
3922 }
3923 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3924 /* Make sure the abstract declaration is compatible with previous declaration */
3925 if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
3926 zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
3927 zend_get_function_declaration(fn TSRMLS_CC),
3928 zend_get_function_declaration(existing_fn TSRMLS_CC));
3929 }
3930 return;
3931 } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3932 /* two trais can't define the same non-abstract method */
3933 #if 1
3934 zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
3935 name, ce->name);
3936 #else /* TODO: better errot message */
3937 zend_error(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
3938 fn->common.scope->name, fn->common.function_name,
3939 ce->name, name,
3940 existing_fn->common.scope->name, existing_fn->common.function_name);
3941 #endif
3942 } else {
3943 /* inherited members are overridden by members inserted by traits */
3944 /* check whether the trait method fulfills the inheritance requirements */
3945 do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
3946 fn->common.prototype = NULL;
3947 }
3948 }
3949
3950 function_add_ref(fn);
3951 zend_hash_quick_update(&ce->function_table, arKey, nKeyLength, h, fn, sizeof(zend_function), (void**)&fn);
3952 zend_add_magic_methods(ce, arKey, nKeyLength, fn TSRMLS_CC);
3953 }
3954 /* }}} */
3955
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce TSRMLS_DC)3956 static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRMLS_DC) /* {{{ */
3957 {
3958 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
3959
3960 fn->common.scope = ce;
3961
3962 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
3963 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
3964 }
3965 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
3966 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
3967 }
3968 }
3969 return ZEND_HASH_APPLY_KEEP;
3970 }
3971 /* }}} */
3972
zend_traits_copy_functions(zend_function * fn TSRMLS_DC,int num_args,va_list args,zend_hash_key * hash_key)3973 static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
3974 {
3975 zend_class_entry *ce;
3976 HashTable **overriden;
3977 zend_trait_alias *alias, **alias_ptr;
3978 HashTable *exclude_table;
3979 char *lcname;
3980 unsigned int fnname_len;
3981 zend_function fn_copy;
3982 void *dummy;
3983
3984 ce = va_arg(args, zend_class_entry*);
3985 overriden = va_arg(args, HashTable**);
3986 exclude_table = va_arg(args, HashTable*);
3987
3988 fnname_len = hash_key->nKeyLength - 1;
3989
3990 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
3991 if (ce->trait_aliases) {
3992 alias_ptr = ce->trait_aliases;
3993 alias = *alias_ptr;
3994 while (alias) {
3995 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
3996 if (alias->alias != NULL
3997 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
3998 && alias->trait_method->mname_len == fnname_len
3999 && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, hash_key->arKey, fnname_len) == 0)) {
4000 fn_copy = *fn;
4001
4002 /* if it is 0, no modifieres has been changed */
4003 if (alias->modifiers) {
4004 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
4005 }
4006
4007 lcname = zend_str_tolower_dup(alias->alias, alias->alias_len);
4008 zend_add_trait_method(ce, alias->alias, lcname, alias->alias_len+1, &fn_copy, overriden TSRMLS_CC);
4009 efree(lcname);
4010
4011 /* Record the trait from which this alias was resolved. */
4012 if (!alias->trait_method->ce) {
4013 alias->trait_method->ce = fn->common.scope;
4014 }
4015 }
4016 alias_ptr++;
4017 alias = *alias_ptr;
4018 }
4019 }
4020
4021 lcname = hash_key->arKey;
4022
4023 if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) {
4024 /* is not in hashtable, thus, function is not to be excluded */
4025 fn_copy = *fn;
4026
4027 /* apply aliases which have not alias name, just setting visibility */
4028 if (ce->trait_aliases) {
4029 alias_ptr = ce->trait_aliases;
4030 alias = *alias_ptr;
4031 while (alias) {
4032 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
4033 if (alias->alias == NULL && alias->modifiers != 0
4034 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
4035 && (alias->trait_method->mname_len == fnname_len)
4036 && (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, lcname, fnname_len) == 0)) {
4037
4038 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
4039
4040 /** Record the trait from which this alias was resolved. */
4041 if (!alias->trait_method->ce) {
4042 alias->trait_method->ce = fn->common.scope;
4043 }
4044 }
4045 alias_ptr++;
4046 alias = *alias_ptr;
4047 }
4048 }
4049
4050 zend_add_trait_method(ce, fn->common.function_name, lcname, fnname_len+1, &fn_copy, overriden TSRMLS_CC);
4051 }
4052
4053 return ZEND_HASH_APPLY_KEEP;
4054 }
4055 /* }}} */
4056
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait TSRMLS_DC)4057 static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
4058 {
4059 zend_uint i;
4060
4061 if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
4062 zend_error(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name);
4063 }
4064
4065 for (i = 0; i < ce->num_traits; i++) {
4066 if (ce->traits[i] == trait) {
4067 return;
4068 }
4069 }
4070 zend_error(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name, ce->name);
4071 }
4072 /* }}} */
4073
zend_traits_init_trait_structures(zend_class_entry * ce TSRMLS_DC)4074 static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4075 {
4076 size_t i, j = 0;
4077 zend_trait_precedence **precedences;
4078 zend_trait_precedence *cur_precedence;
4079 zend_trait_method_reference *cur_method_ref;
4080 char *lcname;
4081 zend_bool method_exists;
4082
4083 /* resolve class references */
4084 if (ce->trait_precedences) {
4085 i = 0;
4086 precedences = ce->trait_precedences;
4087 ce->trait_precedences = NULL;
4088 while ((cur_precedence = precedences[i])) {
4089 /** Resolve classes for all precedence operations. */
4090 if (cur_precedence->exclude_from_classes) {
4091 cur_method_ref = cur_precedence->trait_method;
4092 if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len,
4093 ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4094 zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4095 }
4096 zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
4097
4098 /** Ensure that the prefered method is actually available. */
4099 lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4100 cur_method_ref->mname_len);
4101 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4102 lcname,
4103 cur_method_ref->mname_len + 1);
4104 efree(lcname);
4105 if (!method_exists) {
4106 zend_error(E_COMPILE_ERROR,
4107 "A precedence rule was defined for %s::%s but this method does not exist",
4108 cur_method_ref->ce->name,
4109 cur_method_ref->method_name);
4110 }
4111
4112 /** With the other traits, we are more permissive.
4113 We do not give errors for those. This allows to be more
4114 defensive in such definitions.
4115 However, we want to make sure that the insteadof declaration
4116 is consistent in itself.
4117 */
4118 j = 0;
4119 while (cur_precedence->exclude_from_classes[j]) {
4120 char* class_name = (char*)cur_precedence->exclude_from_classes[j];
4121 zend_uint name_length = strlen(class_name);
4122
4123 if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4124 zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
4125 }
4126 zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
4127
4128 /* make sure that the trait method is not from a class mentioned in
4129 exclude_from_classes, for consistency */
4130 if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[j]) {
4131 zend_error(E_COMPILE_ERROR,
4132 "Inconsistent insteadof definition. "
4133 "The method %s is to be used from %s, but %s is also on the exclude list",
4134 cur_method_ref->method_name,
4135 cur_precedence->trait_method->ce->name,
4136 cur_precedence->trait_method->ce->name);
4137 }
4138
4139 efree(class_name);
4140 j++;
4141 }
4142 }
4143 i++;
4144 }
4145 ce->trait_precedences = precedences;
4146 }
4147
4148 if (ce->trait_aliases) {
4149 i = 0;
4150 while (ce->trait_aliases[i]) {
4151 /** For all aliases with an explicit class name, resolve the class now. */
4152 if (ce->trait_aliases[i]->trait_method->class_name) {
4153 cur_method_ref = ce->trait_aliases[i]->trait_method;
4154 if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
4155 zend_error(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name);
4156 }
4157 zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
4158
4159 /** And, ensure that the referenced method is resolvable, too. */
4160 lcname = zend_str_tolower_dup(cur_method_ref->method_name,
4161 cur_method_ref->mname_len);
4162 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
4163 lcname, cur_method_ref->mname_len + 1);
4164 efree(lcname);
4165
4166 if (!method_exists) {
4167 zend_error(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name, cur_method_ref->method_name);
4168 }
4169 }
4170 i++;
4171 }
4172 }
4173 }
4174 /* }}} */
4175
zend_traits_compile_exclude_table(HashTable * exclude_table,zend_trait_precedence ** precedences,zend_class_entry * trait)4176 static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
4177 {
4178 size_t i = 0, j;
4179
4180 if (!precedences) {
4181 return;
4182 }
4183 while (precedences[i]) {
4184 if (precedences[i]->exclude_from_classes) {
4185 j = 0;
4186 while (precedences[i]->exclude_from_classes[j]) {
4187 if (precedences[i]->exclude_from_classes[j] == trait) {
4188 zend_uint lcname_len = precedences[i]->trait_method->mname_len;
4189 char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len);
4190
4191 if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) {
4192 efree(lcname);
4193 zend_error(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name, trait->name);
4194 }
4195 efree(lcname);
4196 }
4197 ++j;
4198 }
4199 }
4200 ++i;
4201 }
4202 }
4203 /* }}} */
4204
zend_do_traits_method_binding(zend_class_entry * ce TSRMLS_DC)4205 static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4206 {
4207 zend_uint i;
4208 HashTable *overriden = NULL;
4209
4210 for (i = 0; i < ce->num_traits; i++) {
4211 if (ce->trait_precedences) {
4212 HashTable exclude_table;
4213 zend_trait_precedence **precedences;
4214
4215 /* TODO: revisit this start size, may be its not optimal */
4216 zend_hash_init_ex(&exclude_table, 2, NULL, NULL, 0, 0);
4217
4218 precedences = ce->trait_precedences;
4219 ce->trait_precedences = NULL;
4220 zend_traits_compile_exclude_table(&exclude_table, precedences, ce->traits[i]);
4221
4222 /* copies functions, applies defined aliasing, and excludes unused trait methods */
4223 zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, &exclude_table);
4224
4225 zend_hash_destroy(&exclude_table);
4226 ce->trait_precedences = precedences;
4227 } else {
4228 zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
4229 }
4230 }
4231
4232 zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
4233
4234 if (ce->trait_precedences) {
4235 i = 0;
4236 while (ce->trait_precedences[i]) {
4237 if (ce->trait_precedences[i]->exclude_from_classes) {
4238 efree(ce->trait_precedences[i]->exclude_from_classes);
4239 ce->trait_precedences[i]->exclude_from_classes = NULL;
4240 }
4241 i++;
4242 }
4243 }
4244
4245 if (overriden) {
4246 zend_hash_destroy(overriden);
4247 FREE_HASHTABLE(overriden);
4248 }
4249 }
4250 /* }}} */
4251
find_first_definition(zend_class_entry * ce,size_t current_trait,const char * prop_name,int prop_name_length,ulong prop_hash,zend_class_entry * coliding_ce)4252 static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, const char* prop_name, int prop_name_length, ulong prop_hash, zend_class_entry *coliding_ce) /* {{{ */
4253 {
4254 size_t i;
4255
4256 if (coliding_ce == ce) {
4257 for (i = 0; i < current_trait; i++) {
4258 if (zend_hash_quick_exists(&ce->traits[i]->properties_info, prop_name, prop_name_length+1, prop_hash)) {
4259 return ce->traits[i];
4260 }
4261 }
4262 }
4263
4264 return coliding_ce;
4265 }
4266 /* }}} */
4267
zend_do_traits_property_binding(zend_class_entry * ce TSRMLS_DC)4268 static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4269 {
4270 size_t i;
4271 zend_property_info *property_info;
4272 zend_property_info *coliding_prop;
4273 zval compare_result;
4274 const char* prop_name;
4275 int prop_name_length;
4276 ulong prop_hash;
4277 const char* class_name_unused;
4278 zend_bool not_compatible;
4279 zval* prop_value;
4280 char* doc_comment;
4281 zend_uint flags;
4282
4283 /* In the following steps the properties are inserted into the property table
4284 * for that, a very strict approach is applied:
4285 * - check for compatibility, if not compatible with any property in class -> fatal
4286 * - if compatible, then strict notice
4287 */
4288 for (i = 0; i < ce->num_traits; i++) {
4289 for (zend_hash_internal_pointer_reset(&ce->traits[i]->properties_info);
4290 zend_hash_get_current_data(&ce->traits[i]->properties_info, (void *) &property_info) == SUCCESS;
4291 zend_hash_move_forward(&ce->traits[i]->properties_info)) {
4292 /* first get the unmangeld name if necessary,
4293 * then check whether the property is already there
4294 */
4295 flags = property_info->flags;
4296 if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
4297 prop_hash = property_info->h;
4298 prop_name = property_info->name;
4299 prop_name_length = property_info->name_length;
4300 } else {
4301 /* for private and protected we need to unmangle the names */
4302 zend_unmangle_property_name_ex(property_info->name, property_info->name_length,
4303 &class_name_unused, &prop_name, &prop_name_length);
4304 prop_hash = zend_get_hash_value(prop_name, prop_name_length + 1);
4305 }
4306
4307 /* next: check for conflicts with current class */
4308 if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
4309 if (coliding_prop->flags & ZEND_ACC_SHADOW) {
4310 zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
4311 flags |= ZEND_ACC_CHANGED;
4312 } else {
4313 if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
4314 == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
4315 /* flags are identical, now the value needs to be checked */
4316 if (flags & ZEND_ACC_STATIC) {
4317 not_compatible = (FAILURE == compare_function(&compare_result,
4318 ce->default_static_members_table[coliding_prop->offset],
4319 ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
4320 || (Z_LVAL(compare_result) != 0);
4321 } else {
4322 not_compatible = (FAILURE == compare_function(&compare_result,
4323 ce->default_properties_table[coliding_prop->offset],
4324 ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
4325 || (Z_LVAL(compare_result) != 0);
4326 }
4327 } else {
4328 /* the flags are not identical, thus, we assume properties are not compatible */
4329 not_compatible = 1;
4330 }
4331
4332 if (not_compatible) {
4333 zend_error(E_COMPILE_ERROR,
4334 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
4335 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4336 property_info->ce->name,
4337 prop_name,
4338 ce->name);
4339 } else {
4340 zend_error(E_STRICT,
4341 "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
4342 find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
4343 property_info->ce->name,
4344 prop_name,
4345 ce->name);
4346 continue;
4347 }
4348 }
4349 }
4350
4351 /* property not found, so lets add it */
4352 if (flags & ZEND_ACC_STATIC) {
4353 prop_value = ce->traits[i]->default_static_members_table[property_info->offset];
4354 } else {
4355 prop_value = ce->traits[i]->default_properties_table[property_info->offset];
4356 }
4357 Z_ADDREF_P(prop_value);
4358
4359 doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
4360 zend_declare_property_ex(ce, prop_name, prop_name_length,
4361 prop_value, flags,
4362 doc_comment, property_info->doc_comment_len TSRMLS_CC);
4363 }
4364 }
4365 }
4366 /* }}} */
4367
zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry * ce TSRMLS_DC)4368 static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4369 {
4370 int i = 0;
4371 zend_trait_alias* cur_alias;
4372 char* lc_method_name;
4373
4374 if (ce->trait_aliases) {
4375 while (ce->trait_aliases[i]) {
4376 cur_alias = ce->trait_aliases[i];
4377 /** The trait for this alias has not been resolved, this means, this
4378 alias was not applied. Abort with an error. */
4379 if (!cur_alias->trait_method->ce) {
4380 if (cur_alias->alias) {
4381 /** Plain old inconsistency/typo/bug */
4382 zend_error(E_COMPILE_ERROR,
4383 "An alias (%s) was defined for method %s(), but this method does not exist",
4384 cur_alias->alias,
4385 cur_alias->trait_method->method_name);
4386 } else {
4387 /** Here are two possible cases:
4388 1) this is an attempt to modifiy the visibility
4389 of a method introduce as part of another alias.
4390 Since that seems to violate the DRY principle,
4391 we check against it and abort.
4392 2) it is just a plain old inconsitency/typo/bug
4393 as in the case where alias is set. */
4394
4395 lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name,
4396 cur_alias->trait_method->mname_len);
4397 if (zend_hash_exists(&ce->function_table,
4398 lc_method_name,
4399 cur_alias->trait_method->mname_len+1)) {
4400 efree(lc_method_name);
4401 zend_error(E_COMPILE_ERROR,
4402 "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
4403 cur_alias->trait_method->method_name);
4404 } else {
4405 efree(lc_method_name);
4406 zend_error(E_COMPILE_ERROR,
4407 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
4408 cur_alias->trait_method->method_name);
4409
4410 }
4411 }
4412 }
4413 i++;
4414 }
4415 }
4416 }
4417 /* }}} */
4418
zend_do_bind_traits(zend_class_entry * ce TSRMLS_DC)4419 ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
4420 {
4421
4422 if (ce->num_traits <= 0) {
4423 return;
4424 }
4425
4426 /* complete initialization of trait strutures in ce */
4427 zend_traits_init_trait_structures(ce TSRMLS_CC);
4428
4429 /* first care about all methods to be flattened into the class */
4430 zend_do_traits_method_binding(ce TSRMLS_CC);
4431
4432 /* Aliases which have not been applied indicate typos/bugs. */
4433 zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
4434
4435 /* then flatten the properties into it, to, mostly to notfiy developer about problems */
4436 zend_do_traits_property_binding(ce TSRMLS_CC);
4437
4438 /* verify that all abstract methods from traits have been implemented */
4439 zend_verify_abstract_class(ce TSRMLS_CC);
4440
4441 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
4442 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
4443 ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
4444 }
4445 }
4446 /* }}} */
4447
do_bind_function(const zend_op_array * op_array,zend_op * opline,HashTable * function_table,zend_bool compile_time)4448 ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */
4449 {
4450 zend_function *function;
4451 zval *op1, *op2;
4452
4453 if (compile_time) {
4454 op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4455 op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4456 } else {
4457 op1 = opline->op1.zv;
4458 op2 = opline->op2.zv;
4459 }
4460
4461 zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function);
4462 if (zend_hash_quick_add(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), function, sizeof(zend_function), NULL)==FAILURE) {
4463 int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
4464 zend_function *old_function;
4465
4466 if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), (void *) &old_function)==SUCCESS
4467 && old_function->type == ZEND_USER_FUNCTION
4468 && old_function->op_array.last > 0) {
4469 zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
4470 function->common.function_name,
4471 old_function->op_array.filename,
4472 old_function->op_array.opcodes[0].lineno);
4473 } else {
4474 zend_error(error_level, "Cannot redeclare %s()", function->common.function_name);
4475 }
4476 return FAILURE;
4477 } else {
4478 (*function->op_array.refcount)++;
4479 function->op_array.static_variables = NULL; /* NULL out the unbound function */
4480 return SUCCESS;
4481 }
4482 }
4483 /* }}} */
4484
zend_prepare_reference(znode * result,znode * class_name,znode * method_name TSRMLS_DC)4485 void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
4486 {
4487 zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
4488 method_ref->ce = NULL;
4489
4490 /* REM: There should not be a need for copying,
4491 zend_do_begin_class_declaration is also just using that string */
4492 if (class_name) {
4493 zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
4494 method_ref->class_name = Z_STRVAL(class_name->u.constant);
4495 method_ref->cname_len = Z_STRLEN(class_name->u.constant);
4496 } else {
4497 method_ref->class_name = NULL;
4498 method_ref->cname_len = 0;
4499 }
4500
4501 method_ref->method_name = Z_STRVAL(method_name->u.constant);
4502 method_ref->mname_len = Z_STRLEN(method_name->u.constant);
4503
4504 result->u.op.ptr = method_ref;
4505 result->op_type = IS_TMP_VAR;
4506 }
4507 /* }}} */
4508
zend_add_trait_alias(znode * method_reference,znode * modifiers,znode * alias TSRMLS_DC)4509 void zend_add_trait_alias(znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
4510 {
4511 zend_class_entry *ce = CG(active_class_entry);
4512 zend_trait_alias *trait_alias;
4513
4514 if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_STATIC) {
4515 zend_error(E_COMPILE_ERROR, "Cannot use 'static' as method modifier");
4516 return;
4517 } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_ABSTRACT) {
4518 zend_error(E_COMPILE_ERROR, "Cannot use 'abstract' as method modifier");
4519 return;
4520 } else if (Z_LVAL(modifiers->u.constant) == ZEND_ACC_FINAL) {
4521 zend_error(E_COMPILE_ERROR, "Cannot use 'final' as method modifier");
4522 return;
4523 }
4524
4525 trait_alias = emalloc(sizeof(zend_trait_alias));
4526 trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4527 trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
4528 if (alias) {
4529 trait_alias->alias = Z_STRVAL(alias->u.constant);
4530 trait_alias->alias_len = Z_STRLEN(alias->u.constant);
4531 } else {
4532 trait_alias->alias = NULL;
4533 }
4534 zend_add_to_list(&ce->trait_aliases, trait_alias TSRMLS_CC);
4535 }
4536 /* }}} */
4537
zend_add_trait_precedence(znode * method_reference,znode * trait_list TSRMLS_DC)4538 void zend_add_trait_precedence(znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
4539 {
4540 zend_class_entry *ce = CG(active_class_entry);
4541 zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
4542
4543 trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.op.ptr;
4544 trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.op.ptr;
4545
4546 zend_add_to_list(&ce->trait_precedences, trait_precedence TSRMLS_CC);
4547 }
4548 /* }}} */
4549
do_bind_class(const zend_op_array * op_array,const zend_op * opline,HashTable * class_table,zend_bool compile_time TSRMLS_DC)4550 ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
4551 {
4552 zend_class_entry *ce, **pce;
4553 zval *op1, *op2;
4554
4555 if (compile_time) {
4556 op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4557 op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4558 } else {
4559 op1 = opline->op1.zv;
4560 op2 = opline->op2.zv;
4561 }
4562 if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) {
4563 zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
4564 return NULL;
4565 } else {
4566 ce = *pce;
4567 }
4568 ce->refcount++;
4569 if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
4570 ce->refcount--;
4571 if (!compile_time) {
4572 /* If we're in compile time, in practice, it's quite possible
4573 * that we'll never reach this class declaration at runtime,
4574 * so we shut up about it. This allows the if (!defined('FOO')) { return; }
4575 * approach to work.
4576 */
4577 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4578 }
4579 return NULL;
4580 } else {
4581 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
4582 zend_verify_abstract_class(ce TSRMLS_CC);
4583 }
4584 return ce;
4585 }
4586 }
4587 /* }}} */
4588
do_bind_inherited_class(const zend_op_array * op_array,const zend_op * opline,HashTable * class_table,zend_class_entry * parent_ce,zend_bool compile_time TSRMLS_DC)4589 ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */
4590 {
4591 zend_class_entry *ce, **pce;
4592 int found_ce;
4593 zval *op1, *op2;
4594
4595 if (compile_time) {
4596 op1 = &CONSTANT_EX(op_array, opline->op1.constant);
4597 op2 = &CONSTANT_EX(op_array, opline->op2.constant);
4598 } else {
4599 op1 = opline->op1.zv;
4600 op2 = opline->op2.zv;
4601 }
4602
4603 found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce);
4604
4605 if (found_ce == FAILURE) {
4606 if (!compile_time) {
4607 /* If we're in compile time, in practice, it's quite possible
4608 * that we'll never reach this class declaration at runtime,
4609 * so we shut up about it. This allows the if (!defined('FOO')) { return; }
4610 * approach to work.
4611 */
4612 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
4613 }
4614 return NULL;
4615 } else {
4616 ce = *pce;
4617 }
4618
4619 if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
4620 zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name);
4621 } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
4622 zend_error(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name, parent_ce->name);
4623 }
4624
4625 zend_do_inheritance(ce, parent_ce TSRMLS_CC);
4626
4627 ce->refcount++;
4628
4629 /* Register the derived class */
4630 if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), pce, sizeof(zend_class_entry *), NULL)==FAILURE) {
4631 zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
4632 }
4633 return ce;
4634 }
4635 /* }}} */
4636
zend_do_early_binding(TSRMLS_D)4637 void zend_do_early_binding(TSRMLS_D) /* {{{ */
4638 {
4639 zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
4640 HashTable *table;
4641
4642 while (opline->opcode == ZEND_TICKS && opline > CG(active_op_array)->opcodes) {
4643 opline--;
4644 }
4645
4646 switch (opline->opcode) {
4647 case ZEND_DECLARE_FUNCTION:
4648 if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1) == FAILURE) {
4649 return;
4650 }
4651 table = CG(function_table);
4652 break;
4653 case ZEND_DECLARE_CLASS:
4654 if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) {
4655 return;
4656 }
4657 table = CG(class_table);
4658 break;
4659 case ZEND_DECLARE_INHERITED_CLASS:
4660 {
4661 zend_op *fetch_class_opline = opline-1;
4662 zval *parent_name;
4663 zend_class_entry **pce;
4664
4665 parent_name = &CONSTANT(fetch_class_opline->op2.constant);
4666 if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) ||
4667 ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) &&
4668 ((*pce)->type == ZEND_INTERNAL_CLASS))) {
4669 if (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING) {
4670 zend_uint *opline_num = &CG(active_op_array)->early_binding;
4671
4672 while (*opline_num != -1) {
4673 opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num;
4674 }
4675 *opline_num = opline - CG(active_op_array)->opcodes;
4676 opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED;
4677 opline->result_type = IS_UNUSED;
4678 opline->result.opline_num = -1;
4679 }
4680 return;
4681 }
4682 if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) {
4683 return;
4684 }
4685 /* clear unnecessary ZEND_FETCH_CLASS opcode */
4686 zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant);
4687 MAKE_NOP(fetch_class_opline);
4688
4689 table = CG(class_table);
4690 break;
4691 }
4692 case ZEND_VERIFY_ABSTRACT_CLASS:
4693 case ZEND_ADD_INTERFACE:
4694 case ZEND_ADD_TRAIT:
4695 case ZEND_BIND_TRAITS:
4696 /* We currently don't early-bind classes that implement interfaces */
4697 /* Classes with traits are handled exactly the same, no early-bind here */
4698 return;
4699 default:
4700 zend_error(E_COMPILE_ERROR, "Invalid binding type");
4701 return;
4702 }
4703
4704 zend_hash_quick_del(table, Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)), Z_HASH_P(&CONSTANT(opline->op1.constant)));
4705 zend_del_literal(CG(active_op_array), opline->op1.constant);
4706 zend_del_literal(CG(active_op_array), opline->op2.constant);
4707 MAKE_NOP(opline);
4708 }
4709 /* }}} */
4710
zend_do_delayed_early_binding(const zend_op_array * op_array TSRMLS_DC)4711 ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC) /* {{{ */
4712 {
4713 if (op_array->early_binding != -1) {
4714 zend_bool orig_in_compilation = CG(in_compilation);
4715 zend_uint opline_num = op_array->early_binding;
4716 zend_class_entry **pce;
4717
4718 CG(in_compilation) = 1;
4719 while (opline_num != -1) {
4720 if (zend_lookup_class(Z_STRVAL_P(op_array->opcodes[opline_num-1].op2.zv), Z_STRLEN_P(op_array->opcodes[opline_num-1].op2.zv), &pce TSRMLS_CC) == SUCCESS) {
4721 do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), *pce, 0 TSRMLS_CC);
4722 }
4723 opline_num = op_array->opcodes[opline_num].result.opline_num;
4724 }
4725 CG(in_compilation) = orig_in_compilation;
4726 }
4727 }
4728 /* }}} */
4729
zend_do_boolean_or_begin(znode * expr1,znode * op_token TSRMLS_DC)4730 void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC) /* {{{ */
4731 {
4732 int next_op_number = get_next_op_number(CG(active_op_array));
4733 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4734
4735 opline->opcode = ZEND_JMPNZ_EX;
4736 if (expr1->op_type == IS_TMP_VAR) {
4737 SET_NODE(opline->result, expr1);
4738 } else {
4739 opline->result.var = get_temporary_variable(CG(active_op_array));
4740 opline->result_type = IS_TMP_VAR;
4741 }
4742 SET_NODE(opline->op1, expr1);
4743 SET_UNUSED(opline->op2);
4744
4745 op_token->u.op.opline_num = next_op_number;
4746
4747 GET_NODE(expr1, opline->result);
4748 }
4749 /* }}} */
4750
zend_do_boolean_or_end(znode * result,const znode * expr1,const znode * expr2,znode * op_token TSRMLS_DC)4751 void zend_do_boolean_or_end(znode *result, const znode *expr1, const znode *expr2, znode *op_token TSRMLS_DC) /* {{{ */
4752 {
4753 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4754
4755 *result = *expr1; /* we saved the original result in expr1 */
4756 opline->opcode = ZEND_BOOL;
4757 SET_NODE(opline->result, result);
4758 SET_NODE(opline->op1, expr2);
4759 SET_UNUSED(opline->op2);
4760
4761 CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
4762 }
4763 /* }}} */
4764
zend_do_boolean_and_begin(znode * expr1,znode * op_token TSRMLS_DC)4765 void zend_do_boolean_and_begin(znode *expr1, znode *op_token TSRMLS_DC) /* {{{ */
4766 {
4767 int next_op_number = get_next_op_number(CG(active_op_array));
4768 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4769
4770 opline->opcode = ZEND_JMPZ_EX;
4771 if (expr1->op_type == IS_TMP_VAR) {
4772 SET_NODE(opline->result, expr1);
4773 } else {
4774 opline->result.var = get_temporary_variable(CG(active_op_array));
4775 opline->result_type = IS_TMP_VAR;
4776 }
4777 SET_NODE(opline->op1, expr1);
4778 SET_UNUSED(opline->op2);
4779
4780 op_token->u.op.opline_num = next_op_number;
4781
4782 GET_NODE(expr1, opline->result);
4783 }
4784 /* }}} */
4785
zend_do_boolean_and_end(znode * result,const znode * expr1,const znode * expr2,const znode * op_token TSRMLS_DC)4786 void zend_do_boolean_and_end(znode *result, const znode *expr1, const znode *expr2, const znode *op_token TSRMLS_DC) /* {{{ */
4787 {
4788 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4789
4790 *result = *expr1; /* we saved the original result in expr1 */
4791 opline->opcode = ZEND_BOOL;
4792 SET_NODE(opline->result, result);
4793 SET_NODE(opline->op1, expr2);
4794 SET_UNUSED(opline->op2);
4795
4796 CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
4797 }
4798 /* }}} */
4799
zend_do_do_while_begin(TSRMLS_D)4800 void zend_do_do_while_begin(TSRMLS_D) /* {{{ */
4801 {
4802 do_begin_loop(TSRMLS_C);
4803 INC_BPC(CG(active_op_array));
4804 }
4805 /* }}} */
4806
zend_do_do_while_end(const znode * do_token,const znode * expr_open_bracket,const znode * expr TSRMLS_DC)4807 void zend_do_do_while_end(const znode *do_token, const znode *expr_open_bracket, const znode *expr TSRMLS_DC) /* {{{ */
4808 {
4809 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4810
4811 opline->opcode = ZEND_JMPNZ;
4812 SET_NODE(opline->op1, expr);
4813 opline->op2.opline_num = do_token->u.op.opline_num;
4814 SET_UNUSED(opline->op2);
4815
4816 do_end_loop(expr_open_bracket->u.op.opline_num, 0 TSRMLS_CC);
4817
4818 DEC_BPC(CG(active_op_array));
4819 }
4820 /* }}} */
4821
zend_do_brk_cont(zend_uchar op,const znode * expr TSRMLS_DC)4822 void zend_do_brk_cont(zend_uchar op, const znode *expr TSRMLS_DC) /* {{{ */
4823 {
4824 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4825
4826 opline->opcode = op;
4827 opline->op1.opline_num = CG(context).current_brk_cont;
4828 SET_UNUSED(opline->op1);
4829 if (expr) {
4830 if (expr->op_type != IS_CONST) {
4831 zend_error(E_COMPILE_ERROR, "'%s' operator with non-constant operand is no longer supported", op == ZEND_BRK ? "break" : "continue");
4832 } else if (Z_TYPE(expr->u.constant) != IS_LONG || Z_LVAL(expr->u.constant) < 1) {
4833 zend_error(E_COMPILE_ERROR, "'%s' operator accepts only positive numbers", op == ZEND_BRK ? "break" : "continue");
4834 }
4835 SET_NODE(opline->op2, expr);
4836 } else {
4837 LITERAL_LONG(opline->op2, 1);
4838 opline->op2_type = IS_CONST;
4839 }
4840 }
4841 /* }}} */
4842
zend_do_switch_cond(const znode * cond TSRMLS_DC)4843 void zend_do_switch_cond(const znode *cond TSRMLS_DC) /* {{{ */
4844 {
4845 zend_switch_entry switch_entry;
4846
4847 switch_entry.cond = *cond;
4848 switch_entry.default_case = -1;
4849 switch_entry.control_var = -1;
4850 zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));
4851
4852 do_begin_loop(TSRMLS_C);
4853
4854 INC_BPC(CG(active_op_array));
4855 }
4856 /* }}} */
4857
zend_do_switch_end(const znode * case_list TSRMLS_DC)4858 void zend_do_switch_end(const znode *case_list TSRMLS_DC) /* {{{ */
4859 {
4860 zend_op *opline;
4861 zend_switch_entry *switch_entry_ptr;
4862
4863 zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
4864
4865 /* add code to jmp to default case */
4866 if (switch_entry_ptr->default_case != -1) {
4867 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4868 opline->opcode = ZEND_JMP;
4869 SET_UNUSED(opline->op1);
4870 SET_UNUSED(opline->op2);
4871 opline->op1.opline_num = switch_entry_ptr->default_case;
4872 }
4873
4874 if (case_list->op_type != IS_UNUSED) { /* non-empty switch */
4875 int next_op_number = get_next_op_number(CG(active_op_array));
4876
4877 CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number;
4878 }
4879
4880 /* remember break/continue loop information */
4881 CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array));
4882 CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent;
4883
4884 if (switch_entry_ptr->cond.op_type==IS_VAR || switch_entry_ptr->cond.op_type==IS_TMP_VAR) {
4885 /* emit free for the switch condition*/
4886 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4887 opline->opcode = (switch_entry_ptr->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE;
4888 SET_NODE(opline->op1, &switch_entry_ptr->cond);
4889 SET_UNUSED(opline->op2);
4890 }
4891 if (switch_entry_ptr->cond.op_type == IS_CONST) {
4892 zval_dtor(&switch_entry_ptr->cond.u.constant);
4893 }
4894
4895 zend_stack_del_top(&CG(switch_cond_stack));
4896
4897 DEC_BPC(CG(active_op_array));
4898 }
4899 /* }}} */
4900
zend_do_case_before_statement(const znode * case_list,znode * case_token,const znode * case_expr TSRMLS_DC)4901 void zend_do_case_before_statement(const znode *case_list, znode *case_token, const znode *case_expr TSRMLS_DC) /* {{{ */
4902 {
4903 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4904 int next_op_number;
4905 zend_switch_entry *switch_entry_ptr;
4906 znode result;
4907
4908 zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
4909
4910 if (switch_entry_ptr->control_var == -1) {
4911 switch_entry_ptr->control_var = get_temporary_variable(CG(active_op_array));
4912 }
4913 opline->opcode = ZEND_CASE;
4914 opline->result.var = switch_entry_ptr->control_var;
4915 opline->result_type = IS_TMP_VAR;
4916 SET_NODE(opline->op1, &switch_entry_ptr->cond);
4917 SET_NODE(opline->op2, case_expr);
4918 if (opline->op1_type == IS_CONST) {
4919 zval_copy_ctor(&CONSTANT(opline->op1.constant));
4920 }
4921 GET_NODE(&result, opline->result);
4922
4923 next_op_number = get_next_op_number(CG(active_op_array));
4924 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4925 opline->opcode = ZEND_JMPZ;
4926 SET_NODE(opline->op1, &result);
4927 SET_UNUSED(opline->op2);
4928 case_token->u.op.opline_num = next_op_number;
4929
4930 if (case_list->op_type==IS_UNUSED) {
4931 return;
4932 }
4933 next_op_number = get_next_op_number(CG(active_op_array));
4934 CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number;
4935 }
4936 /* }}} */
4937
zend_do_case_after_statement(znode * result,const znode * case_token TSRMLS_DC)4938 void zend_do_case_after_statement(znode *result, const znode *case_token TSRMLS_DC) /* {{{ */
4939 {
4940 int next_op_number = get_next_op_number(CG(active_op_array));
4941 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4942
4943 opline->opcode = ZEND_JMP;
4944 SET_UNUSED(opline->op1);
4945 SET_UNUSED(opline->op2);
4946 result->u.op.opline_num = next_op_number;
4947
4948 switch (CG(active_op_array)->opcodes[case_token->u.op.opline_num].opcode) {
4949 case ZEND_JMP:
4950 CG(active_op_array)->opcodes[case_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
4951 break;
4952 case ZEND_JMPZ:
4953 CG(active_op_array)->opcodes[case_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
4954 break;
4955 }
4956 }
4957 /* }}} */
4958
zend_do_default_before_statement(const znode * case_list,znode * default_token TSRMLS_DC)4959 void zend_do_default_before_statement(const znode *case_list, znode *default_token TSRMLS_DC) /* {{{ */
4960 {
4961 int next_op_number = get_next_op_number(CG(active_op_array));
4962 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
4963 zend_switch_entry *switch_entry_ptr;
4964
4965 zend_stack_top(&CG(switch_cond_stack), (void **) &switch_entry_ptr);
4966
4967 opline->opcode = ZEND_JMP;
4968 SET_UNUSED(opline->op1);
4969 SET_UNUSED(opline->op2);
4970 default_token->u.op.opline_num = next_op_number;
4971
4972 next_op_number = get_next_op_number(CG(active_op_array));
4973 switch_entry_ptr->default_case = next_op_number;
4974
4975 if (case_list->op_type==IS_UNUSED) {
4976 return;
4977 }
4978 CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number;
4979 }
4980 /* }}} */
4981
zend_do_begin_class_declaration(const znode * class_token,znode * class_name,const znode * parent_class_name TSRMLS_DC)4982 void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */
4983 {
4984 zend_op *opline;
4985 int doing_inheritance = 0;
4986 zend_class_entry *new_class_entry;
4987 char *lcname;
4988 int error = 0;
4989 zval **ns_name, key;
4990
4991 if (CG(active_class_entry)) {
4992 zend_error(E_COMPILE_ERROR, "Class declarations may not be nested");
4993 return;
4994 }
4995
4996 lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
4997
4998 if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) {
4999 efree(lcname);
5000 zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant));
5001 }
5002
5003 /* Class name must not conflict with import names */
5004 if (CG(current_import) &&
5005 zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) {
5006 error = 1;
5007 }
5008
5009 if (CG(current_namespace)) {
5010 /* Prefix class name with name of current namespace */
5011 znode tmp;
5012
5013 tmp.op_type = IS_CONST;
5014 tmp.u.constant = *CG(current_namespace);
5015 zval_copy_ctor(&tmp.u.constant);
5016 zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
5017 *class_name = tmp;
5018 efree(lcname);
5019 lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
5020 }
5021
5022 if (error) {
5023 char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name));
5024
5025 if (Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||
5026 memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {
5027 zend_error(E_COMPILE_ERROR, "Cannot declare class %s because the name is already in use", Z_STRVAL(class_name->u.constant));
5028 }
5029 efree(tmp);
5030 }
5031
5032 new_class_entry = emalloc(sizeof(zend_class_entry));
5033 new_class_entry->type = ZEND_USER_CLASS;
5034 new_class_entry->name = zend_new_interned_string(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + 1, 1 TSRMLS_CC);
5035 new_class_entry->name_length = Z_STRLEN(class_name->u.constant);
5036
5037 zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
5038 new_class_entry->info.user.filename = zend_get_compiled_filename(TSRMLS_C);
5039 new_class_entry->info.user.line_start = class_token->u.op.opline_num;
5040 new_class_entry->ce_flags |= class_token->EA;
5041
5042 if (parent_class_name && parent_class_name->op_type != IS_UNUSED) {
5043 switch (parent_class_name->EA) {
5044 case ZEND_FETCH_CLASS_SELF:
5045 zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved");
5046 break;
5047 case ZEND_FETCH_CLASS_PARENT:
5048 zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved");
5049 break;
5050 case ZEND_FETCH_CLASS_STATIC:
5051 zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved");
5052 break;
5053 default:
5054 break;
5055 }
5056 doing_inheritance = 1;
5057 }
5058
5059 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5060 opline->op1_type = IS_CONST;
5061 build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);
5062 opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
5063 Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
5064
5065 opline->op2_type = IS_CONST;
5066
5067 if (doing_inheritance) {
5068 /* Make sure a trait does not try to extend a class */
5069 if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
5070 zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);
5071 }
5072
5073 opline->extended_value = parent_class_name->u.op.var;
5074 opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
5075 } else {
5076 opline->opcode = ZEND_DECLARE_CLASS;
5077 }
5078
5079 LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0);
5080 CALCULATE_LITERAL_HASH(opline->op2.constant);
5081
5082 zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL);
5083 CG(active_class_entry) = new_class_entry;
5084
5085 opline->result.var = get_temporary_variable(CG(active_op_array));
5086 opline->result_type = IS_VAR;
5087 GET_NODE(&CG(implementing_class), opline->result);
5088
5089 if (CG(doc_comment)) {
5090 CG(active_class_entry)->info.user.doc_comment = CG(doc_comment);
5091 CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len);
5092 CG(doc_comment) = NULL;
5093 CG(doc_comment_len) = 0;
5094 }
5095 }
5096 /* }}} */
5097
do_verify_abstract_class(TSRMLS_D)5098 static void do_verify_abstract_class(TSRMLS_D) /* {{{ */
5099 {
5100 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5101
5102 opline->opcode = ZEND_VERIFY_ABSTRACT_CLASS;
5103 SET_NODE(opline->op1, &CG(implementing_class));
5104 SET_UNUSED(opline->op2);
5105 }
5106 /* }}} */
5107
zend_do_end_class_declaration(const znode * class_token,const znode * parent_token TSRMLS_DC)5108 void zend_do_end_class_declaration(const znode *class_token, const znode *parent_token TSRMLS_DC) /* {{{ */
5109 {
5110 zend_class_entry *ce = CG(active_class_entry);
5111
5112 if (ce->constructor) {
5113 ce->constructor->common.fn_flags |= ZEND_ACC_CTOR;
5114 if (ce->constructor->common.fn_flags & ZEND_ACC_STATIC) {
5115 zend_error(E_COMPILE_ERROR, "Constructor %s::%s() cannot be static", ce->name, ce->constructor->common.function_name);
5116 }
5117 }
5118 if (ce->destructor) {
5119 ce->destructor->common.fn_flags |= ZEND_ACC_DTOR;
5120 if (ce->destructor->common.fn_flags & ZEND_ACC_STATIC) {
5121 zend_error(E_COMPILE_ERROR, "Destructor %s::%s() cannot be static", ce->name, ce->destructor->common.function_name);
5122 }
5123 }
5124 if (ce->clone) {
5125 ce->clone->common.fn_flags |= ZEND_ACC_CLONE;
5126 if (ce->clone->common.fn_flags & ZEND_ACC_STATIC) {
5127 zend_error(E_COMPILE_ERROR, "Clone method %s::%s() cannot be static", ce->name, ce->clone->common.function_name);
5128 }
5129 }
5130
5131 ce->info.user.line_end = zend_get_compiled_lineno(TSRMLS_C);
5132
5133 /* Check for traits and proceed like with interfaces.
5134 * The only difference will be a combined handling of them in the end.
5135 * Thus, we need another opcode here. */
5136 if (ce->num_traits > 0) {
5137 zend_op *opline;
5138
5139 ce->traits = NULL;
5140 ce->num_traits = 0;
5141 ce->ce_flags |= ZEND_ACC_IMPLEMENT_TRAITS;
5142
5143 /* opcode generation: */
5144 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5145 opline->opcode = ZEND_BIND_TRAITS;
5146 SET_NODE(opline->op1, &CG(implementing_class));
5147 }
5148
5149 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
5150 && (parent_token || (ce->num_interfaces > 0))) {
5151 zend_verify_abstract_class(ce TSRMLS_CC);
5152 if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
5153 do_verify_abstract_class(TSRMLS_C);
5154 }
5155 }
5156 /* Inherit interfaces; reset number to zero, we need it for above check and
5157 * will restore it during actual implementation.
5158 * The ZEND_ACC_IMPLEMENT_INTERFACES flag disables double call to
5159 * zend_verify_abstract_class() */
5160 if (ce->num_interfaces > 0) {
5161 ce->interfaces = NULL;
5162 ce->num_interfaces = 0;
5163 ce->ce_flags |= ZEND_ACC_IMPLEMENT_INTERFACES;
5164 }
5165
5166 CG(active_class_entry) = NULL;
5167 }
5168 /* }}} */
5169
zend_do_implements_interface(znode * interface_name TSRMLS_DC)5170 void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */
5171 {
5172 zend_op *opline;
5173
5174 /* Traits can not implement interfaces */
5175 if ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
5176 zend_error(E_COMPILE_ERROR, "Cannot use '%s' as interface on '%s' since it is a Trait",
5177 Z_STRVAL(interface_name->u.constant),
5178 CG(active_class_entry)->name);
5179 }
5180
5181 switch (zend_get_class_fetch_type(Z_STRVAL(interface_name->u.constant), Z_STRLEN(interface_name->u.constant))) {
5182 case ZEND_FETCH_CLASS_SELF:
5183 case ZEND_FETCH_CLASS_PARENT:
5184 case ZEND_FETCH_CLASS_STATIC:
5185 zend_error(E_COMPILE_ERROR, "Cannot use '%s' as interface name as it is reserved", Z_STRVAL(interface_name->u.constant));
5186 break;
5187 default:
5188 break;
5189 }
5190
5191 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5192 opline->opcode = ZEND_ADD_INTERFACE;
5193 SET_NODE(opline->op1, &CG(implementing_class));
5194 zend_resolve_class_name(interface_name, opline->extended_value, 0 TSRMLS_CC);
5195 opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;
5196 opline->op2_type = IS_CONST;
5197 opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), &interface_name->u.constant TSRMLS_CC);
5198 CG(active_class_entry)->num_interfaces++;
5199 }
5200 /* }}} */
5201
zend_do_use_trait(znode * trait_name TSRMLS_DC)5202 void zend_do_use_trait(znode *trait_name TSRMLS_DC) /* {{{ */
5203 {
5204 zend_op *opline;
5205
5206 if ((CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
5207 zend_error(E_COMPILE_ERROR,
5208 "Cannot use traits inside of interfaces. %s is used in %s",
5209 Z_STRVAL(trait_name->u.constant), CG(active_class_entry)->name);
5210 }
5211
5212
5213 switch (zend_get_class_fetch_type(Z_STRVAL(trait_name->u.constant), Z_STRLEN(trait_name->u.constant))) {
5214 case ZEND_FETCH_CLASS_SELF:
5215 case ZEND_FETCH_CLASS_PARENT:
5216 case ZEND_FETCH_CLASS_STATIC:
5217 zend_error(E_COMPILE_ERROR, "Cannot use '%s' as trait name as it is reserved", Z_STRVAL(trait_name->u.constant));
5218 break;
5219 default:
5220 break;
5221 }
5222
5223 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5224 opline->opcode = ZEND_ADD_TRAIT;
5225 SET_NODE(opline->op1, &CG(implementing_class));
5226 zend_resolve_class_name(trait_name, opline->extended_value, 0 TSRMLS_CC);
5227 opline->extended_value = ZEND_FETCH_CLASS_TRAIT;
5228 opline->op2_type = IS_CONST;
5229 opline->op2.constant = zend_add_class_name_literal(CG(active_op_array), &trait_name->u.constant TSRMLS_CC);
5230 CG(active_class_entry)->num_traits++;
5231 }
5232 /* }}} */
5233
zend_mangle_property_name(char ** dest,int * dest_length,const char * src1,int src1_length,const char * src2,int src2_length,int internal)5234 ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, const char *src1, int src1_length, const char *src2, int src2_length, int internal) /* {{{ */
5235 {
5236 char *prop_name;
5237 int prop_name_length;
5238
5239 prop_name_length = 1 + src1_length + 1 + src2_length;
5240 prop_name = pemalloc(prop_name_length + 1, internal);
5241 prop_name[0] = '\0';
5242 memcpy(prop_name + 1, src1, src1_length+1);
5243 memcpy(prop_name + 1 + src1_length + 1, src2, src2_length+1);
5244
5245 *dest = prop_name;
5246 *dest_length = prop_name_length;
5247 }
5248 /* }}} */
5249
zend_strnlen(const char * s,int maxlen)5250 static int zend_strnlen(const char* s, int maxlen) /* {{{ */
5251 {
5252 int len = 0;
5253 while (*s++ && maxlen--) len++;
5254 return len;
5255 }
5256 /* }}} */
5257
zend_unmangle_property_name_ex(const char * mangled_property,int len,const char ** class_name,const char ** prop_name,int * prop_len)5258 ZEND_API int zend_unmangle_property_name_ex(const char *mangled_property, int len, const char **class_name, const char **prop_name, int *prop_len) /* {{{ */
5259 {
5260 int class_name_len;
5261
5262 *class_name = NULL;
5263
5264 if (mangled_property[0]!=0) {
5265 *prop_name = mangled_property;
5266 if (prop_len) {
5267 *prop_len = len;
5268 }
5269 return SUCCESS;
5270 }
5271 if (len < 3 || mangled_property[1]==0) {
5272 zend_error(E_NOTICE, "Illegal member variable name");
5273 *prop_name = mangled_property;
5274 if (prop_len) {
5275 *prop_len = len;
5276 }
5277 return FAILURE;
5278 }
5279
5280 class_name_len = zend_strnlen(mangled_property + 1, --len - 1) + 1;
5281 if (class_name_len >= len || mangled_property[class_name_len]!=0) {
5282 zend_error(E_NOTICE, "Corrupt member variable name");
5283 *prop_name = mangled_property;
5284 if (prop_len) {
5285 *prop_len = len + 1;
5286 }
5287 return FAILURE;
5288 }
5289 *class_name = mangled_property + 1;
5290 *prop_name = (*class_name) + class_name_len;
5291 if (prop_len) {
5292 *prop_len = len - class_name_len;
5293 }
5294 return SUCCESS;
5295 }
5296 /* }}} */
5297
zend_do_declare_property(const znode * var_name,const znode * value,zend_uint access_type TSRMLS_DC)5298 void zend_do_declare_property(const znode *var_name, const znode *value, zend_uint access_type TSRMLS_DC) /* {{{ */
5299 {
5300 zval *property;
5301 zend_property_info *existing_property_info;
5302 char *comment = NULL;
5303 int comment_len = 0;
5304
5305 if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
5306 zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables");
5307 }
5308
5309 if (access_type & ZEND_ACC_ABSTRACT) {
5310 zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract");
5311 }
5312
5313 if (access_type & ZEND_ACC_FINAL) {
5314 zend_error(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, the final modifier is allowed only for methods and classes",
5315 CG(active_class_entry)->name, var_name->u.constant.value.str.val);
5316 }
5317
5318 if (zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, (void **) &existing_property_info)==SUCCESS) {
5319 zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
5320 }
5321 ALLOC_ZVAL(property);
5322
5323 if (value) {
5324 *property = value->u.constant;
5325 } else {
5326 INIT_PZVAL(property);
5327 Z_TYPE_P(property) = IS_NULL;
5328 }
5329
5330 if (CG(doc_comment)) {
5331 comment = CG(doc_comment);
5332 comment_len = CG(doc_comment_len);
5333 CG(doc_comment) = NULL;
5334 CG(doc_comment_len) = 0;
5335 }
5336
5337 zend_declare_property_ex(CG(active_class_entry), zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + 1, 0 TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC);
5338 efree(var_name->u.constant.value.str.val);
5339 }
5340 /* }}} */
5341
zend_do_declare_class_constant(znode * var_name,const znode * value TSRMLS_DC)5342 void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_DC) /* {{{ */
5343 {
5344 zval *property;
5345 const char *cname = NULL;
5346 int result;
5347
5348 if(Z_TYPE(value->u.constant) == IS_CONSTANT_ARRAY) {
5349 zend_error(E_COMPILE_ERROR, "Arrays are not allowed in class constants");
5350 return;
5351 }
5352 if ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
5353 zend_error(E_COMPILE_ERROR, "Traits cannot have constants");
5354 return;
5355 }
5356
5357 ALLOC_ZVAL(property);
5358 *property = value->u.constant;
5359
5360 cname = zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, 0 TSRMLS_CC);
5361
5362 if (IS_INTERNED(cname)) {
5363 result = zend_hash_quick_add(&CG(active_class_entry)->constants_table, cname, var_name->u.constant.value.str.len+1, INTERNED_HASH(cname), &property, sizeof(zval *), NULL);
5364 } else {
5365 result = zend_hash_add(&CG(active_class_entry)->constants_table, cname, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
5366 }
5367 if (result == FAILURE) {
5368 FREE_ZVAL(property);
5369 zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
5370 }
5371 FREE_PNODE(var_name);
5372
5373 if (CG(doc_comment)) {
5374 efree(CG(doc_comment));
5375 CG(doc_comment) = NULL;
5376 CG(doc_comment_len) = 0;
5377 }
5378 }
5379 /* }}} */
5380
zend_do_fetch_property(znode * result,znode * object,const znode * property TSRMLS_DC)5381 void zend_do_fetch_property(znode *result, znode *object, const znode *property TSRMLS_DC) /* {{{ */
5382 {
5383 zend_op opline;
5384 zend_llist *fetch_list_ptr;
5385
5386 zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
5387
5388 if (object->op_type == IS_CV) {
5389 if (object->u.op.var == CG(active_op_array)->this_var) {
5390 object->op_type = IS_UNUSED; /* this means $this for objects */
5391 }
5392 } else if (fetch_list_ptr->count == 1) {
5393 zend_llist_element *le = fetch_list_ptr->head;
5394 zend_op *opline_ptr = (zend_op *) le->data;
5395
5396 if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
5397 zend_del_literal(CG(active_op_array), opline_ptr->op1.constant);
5398 SET_UNUSED(opline_ptr->op1); /* this means $this for objects */
5399 SET_NODE(opline_ptr->op2, property);
5400 /* if it was usual fetch, we change it to object fetch */
5401 switch (opline_ptr->opcode) {
5402 case ZEND_FETCH_W:
5403 opline_ptr->opcode = ZEND_FETCH_OBJ_W;
5404 break;
5405 case ZEND_FETCH_R:
5406 opline_ptr->opcode = ZEND_FETCH_OBJ_R;
5407 break;
5408 case ZEND_FETCH_RW:
5409 opline_ptr->opcode = ZEND_FETCH_OBJ_RW;
5410 break;
5411 case ZEND_FETCH_IS:
5412 opline_ptr->opcode = ZEND_FETCH_OBJ_IS;
5413 break;
5414 case ZEND_FETCH_UNSET:
5415 opline_ptr->opcode = ZEND_FETCH_OBJ_UNSET;
5416 break;
5417 case ZEND_FETCH_FUNC_ARG:
5418 opline_ptr->opcode = ZEND_FETCH_OBJ_FUNC_ARG;
5419 break;
5420 }
5421 if (opline_ptr->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline_ptr->op2.constant)) == IS_STRING) {
5422 CALCULATE_LITERAL_HASH(opline_ptr->op2.constant);
5423 GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op2.constant);
5424 }
5425 GET_NODE(result, opline_ptr->result);
5426 return;
5427 }
5428 }
5429
5430 if (zend_is_function_or_method_call(object)) {
5431 init_op(&opline TSRMLS_CC);
5432 opline.opcode = ZEND_SEPARATE;
5433 SET_NODE(opline.op1, object);
5434 SET_UNUSED(opline.op2);
5435 opline.result_type = IS_VAR;
5436 opline.result.var = opline.op1.var;
5437 zend_llist_add_element(fetch_list_ptr, &opline);
5438 }
5439
5440 init_op(&opline TSRMLS_CC);
5441 opline.opcode = ZEND_FETCH_OBJ_W; /* the backpatching routine assumes W */
5442 opline.result_type = IS_VAR;
5443 opline.result.var = get_temporary_variable(CG(active_op_array));
5444 SET_NODE(opline.op1, object);
5445 SET_NODE(opline.op2, property);
5446 if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) {
5447 CALCULATE_LITERAL_HASH(opline.op2.constant);
5448 GET_POLYMORPHIC_CACHE_SLOT(opline.op2.constant);
5449 }
5450 GET_NODE(result, opline.result);
5451
5452 zend_llist_add_element(fetch_list_ptr, &opline);
5453 }
5454 /* }}} */
5455
zend_do_halt_compiler_register(TSRMLS_D)5456 void zend_do_halt_compiler_register(TSRMLS_D) /* {{{ */
5457 {
5458 char *name, *cfilename;
5459 char haltoff[] = "__COMPILER_HALT_OFFSET__";
5460 int len, clen;
5461
5462 if (CG(has_bracketed_namespaces) && CG(in_namespace)) {
5463 zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope");
5464 }
5465
5466 cfilename = zend_get_compiled_filename(TSRMLS_C);
5467 clen = strlen(cfilename);
5468 zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
5469 zend_register_long_constant(name, len+1, zend_get_scanned_file_offset(TSRMLS_C), CONST_CS, 0 TSRMLS_CC);
5470 pefree(name, 0);
5471
5472 if (CG(in_namespace)) {
5473 zend_do_end_namespace(TSRMLS_C);
5474 }
5475 }
5476 /* }}} */
5477
zend_do_push_object(const znode * object TSRMLS_DC)5478 void zend_do_push_object(const znode *object TSRMLS_DC) /* {{{ */
5479 {
5480 zend_stack_push(&CG(object_stack), object, sizeof(znode));
5481 }
5482 /* }}} */
5483
zend_do_pop_object(znode * object TSRMLS_DC)5484 void zend_do_pop_object(znode *object TSRMLS_DC) /* {{{ */
5485 {
5486 if (object) {
5487 znode *tmp;
5488
5489 zend_stack_top(&CG(object_stack), (void **) &tmp);
5490 *object = *tmp;
5491 }
5492 zend_stack_del_top(&CG(object_stack));
5493 }
5494 /* }}} */
5495
zend_do_begin_new_object(znode * new_token,znode * class_type TSRMLS_DC)5496 void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* {{{ */
5497 {
5498 zend_op *opline;
5499 unsigned char *ptr = NULL;
5500
5501 new_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
5502 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5503 opline->opcode = ZEND_NEW;
5504 opline->extended_value = CG(context).nested_calls;
5505 opline->result_type = IS_VAR;
5506 opline->result.var = get_temporary_variable(CG(active_op_array));
5507 SET_NODE(opline->op1, class_type);
5508 SET_UNUSED(opline->op2);
5509
5510 zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *));
5511 if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) {
5512 CG(active_op_array)->nested_calls = CG(context).nested_calls;
5513 }
5514 }
5515 /* }}} */
5516
zend_do_end_new_object(znode * result,const znode * new_token,const znode * argument_list TSRMLS_DC)5517 void zend_do_end_new_object(znode *result, const znode *new_token, const znode *argument_list TSRMLS_DC) /* {{{ */
5518 {
5519 znode ctor_result;
5520
5521 zend_do_end_function_call(NULL, &ctor_result, argument_list, 1, 0 TSRMLS_CC);
5522 zend_do_free(&ctor_result TSRMLS_CC);
5523
5524 CG(active_op_array)->opcodes[new_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
5525 GET_NODE(result, CG(active_op_array)->opcodes[new_token->u.op.opline_num].result);
5526 }
5527 /* }}} */
5528
zend_get_ct_const(const zval * const_name,int all_internal_constants_substitution TSRMLS_DC)5529 static zend_constant* zend_get_ct_const(const zval *const_name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
5530 {
5531 zend_constant *c = NULL;
5532
5533 if (Z_STRVAL_P(const_name)[0] == '\\') {
5534 if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name)+1, Z_STRLEN_P(const_name), (void **) &c) == FAILURE) {
5535 char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name)+1, Z_STRLEN_P(const_name)-1);
5536
5537 if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name), (void **) &c)==SUCCESS) {
5538 if ((c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
5539 efree(lookup_name);
5540 return c;
5541 }
5542 }
5543 efree(lookup_name);
5544 return NULL;
5545 }
5546 } else if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)+1, (void **) &c) == FAILURE) {
5547 char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name), Z_STRLEN_P(const_name));
5548
5549 if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name)+1, (void **) &c)==SUCCESS) {
5550 if ((c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
5551 efree(lookup_name);
5552 return c;
5553 }
5554 }
5555 efree(lookup_name);
5556 return NULL;
5557 }
5558 if (c->flags & CONST_CT_SUBST) {
5559 return c;
5560 }
5561 if (all_internal_constants_substitution &&
5562 (c->flags & CONST_PERSISTENT) &&
5563 !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) &&
5564 Z_TYPE(c->value) != IS_CONSTANT &&
5565 Z_TYPE(c->value) != IS_CONSTANT_ARRAY) {
5566 return c;
5567 }
5568 return NULL;
5569 }
5570 /* }}} */
5571
zend_constant_ct_subst(znode * result,zval * const_name,int all_internal_constants_substitution TSRMLS_DC)5572 static int zend_constant_ct_subst(znode *result, zval *const_name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
5573 {
5574 zend_constant *c = zend_get_ct_const(const_name, all_internal_constants_substitution TSRMLS_CC);
5575
5576 if (c) {
5577 zval_dtor(const_name);
5578 result->op_type = IS_CONST;
5579 result->u.constant = c->value;
5580 zval_copy_ctor(&result->u.constant);
5581 INIT_PZVAL(&result->u.constant);
5582 return 1;
5583 }
5584 return 0;
5585 }
5586 /* }}} */
5587
zend_do_fetch_constant(znode * result,znode * constant_container,znode * constant_name,int mode,zend_bool check_namespace TSRMLS_DC)5588 void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode, zend_bool check_namespace TSRMLS_DC) /* {{{ */
5589 {
5590 znode tmp;
5591 zend_op *opline;
5592 int type;
5593 char *compound;
5594 ulong fetch_type = 0;
5595
5596 if (constant_container) {
5597 switch (mode) {
5598 case ZEND_CT:
5599 /* this is a class constant */
5600 type = zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant));
5601
5602 if (ZEND_FETCH_CLASS_STATIC == type) {
5603 zend_error(E_ERROR, "\"static::\" is not allowed in compile-time constants");
5604 } else if (ZEND_FETCH_CLASS_DEFAULT == type) {
5605 zend_resolve_class_name(constant_container, fetch_type, 1 TSRMLS_CC);
5606 }
5607 zend_do_build_full_name(NULL, constant_container, constant_name, 1 TSRMLS_CC);
5608 *result = *constant_container;
5609 result->u.constant.type = IS_CONSTANT | fetch_type;
5610 break;
5611 case ZEND_RT:
5612 if (constant_container->op_type == IS_CONST &&
5613 ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant))) {
5614 zend_resolve_class_name(constant_container, fetch_type, 1 TSRMLS_CC);
5615 } else {
5616 zend_do_fetch_class(&tmp, constant_container TSRMLS_CC);
5617 constant_container = &tmp;
5618 }
5619 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5620 opline->opcode = ZEND_FETCH_CONSTANT;
5621 opline->result_type = IS_TMP_VAR;
5622 opline->result.var = get_temporary_variable(CG(active_op_array));
5623 if (constant_container->op_type == IS_CONST) {
5624 opline->op1_type = IS_CONST;
5625 opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &constant_container->u.constant TSRMLS_CC);
5626 } else {
5627 SET_NODE(opline->op1, constant_container);
5628 }
5629 SET_NODE(opline->op2, constant_name);
5630 CALCULATE_LITERAL_HASH(opline->op2.constant);
5631 if (opline->op1_type == IS_CONST) {
5632 GET_CACHE_SLOT(opline->op2.constant);
5633 } else {
5634 GET_POLYMORPHIC_CACHE_SLOT(opline->op2.constant);
5635 }
5636 GET_NODE(result, opline->result);
5637 break;
5638 }
5639 return;
5640 }
5641 /* namespace constant */
5642 /* only one that did not contain \ from the start can be converted to string if unknown */
5643 switch (mode) {
5644 case ZEND_CT:
5645 compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
5646 /* this is a namespace constant, or an unprefixed constant */
5647
5648 if (zend_constant_ct_subst(result, &constant_name->u.constant, 0 TSRMLS_CC)) {
5649 break;
5650 }
5651
5652 zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
5653
5654 if(!compound) {
5655 fetch_type |= IS_CONSTANT_UNQUALIFIED;
5656 }
5657
5658 *result = *constant_name;
5659 result->u.constant.type = IS_CONSTANT | fetch_type;
5660 break;
5661 case ZEND_RT:
5662 compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
5663
5664 zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
5665
5666 if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) {
5667 break;
5668 }
5669
5670 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5671 opline->opcode = ZEND_FETCH_CONSTANT;
5672 opline->result_type = IS_TMP_VAR;
5673 opline->result.var = get_temporary_variable(CG(active_op_array));
5674 GET_NODE(result, opline->result);
5675 SET_UNUSED(opline->op1);
5676 opline->op2_type = IS_CONST;
5677 if (compound) {
5678 /* the name is unambiguous */
5679 opline->extended_value = 0;
5680 opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
5681 } else {
5682 opline->extended_value = IS_CONSTANT_UNQUALIFIED;
5683 if (CG(current_namespace)) {
5684 opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
5685 opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 1 TSRMLS_CC);
5686 } else {
5687 opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
5688 }
5689 }
5690 GET_CACHE_SLOT(opline->op2.constant);
5691 break;
5692 }
5693 }
5694 /* }}} */
5695
zend_do_shell_exec(znode * result,const znode * cmd TSRMLS_DC)5696 void zend_do_shell_exec(znode *result, const znode *cmd TSRMLS_DC) /* {{{ */
5697 {
5698 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5699
5700 switch (cmd->op_type) {
5701 case IS_CONST:
5702 case IS_TMP_VAR:
5703 opline->opcode = ZEND_SEND_VAL;
5704 break;
5705 default:
5706 opline->opcode = ZEND_SEND_VAR;
5707 break;
5708 }
5709 SET_NODE(opline->op1, cmd);
5710 opline->op2.opline_num = 1;
5711 opline->extended_value = ZEND_DO_FCALL;
5712 SET_UNUSED(opline->op2);
5713
5714 /* FIXME: exception support not added to this op2 */
5715 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5716 opline->opcode = ZEND_DO_FCALL;
5717 opline->result.var = get_temporary_variable(CG(active_op_array));
5718 opline->result_type = IS_VAR;
5719 LITERAL_STRINGL(opline->op1, estrndup("shell_exec", sizeof("shell_exec")-1), sizeof("shell_exec")-1, 0);
5720 CALCULATE_LITERAL_HASH(opline->op1.constant);
5721 opline->op1_type = IS_CONST;
5722 GET_CACHE_SLOT(opline->op1.constant);
5723 opline->extended_value = 1;
5724 SET_UNUSED(opline->op2);
5725 opline->op2.num = CG(context).nested_calls;
5726 GET_NODE(result, opline->result);
5727
5728 if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
5729 CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
5730 }
5731 if (CG(context).used_stack + 2 > CG(active_op_array)->used_stack) {
5732 CG(active_op_array)->used_stack = CG(context).used_stack + 2;
5733 }
5734 }
5735 /* }}} */
5736
zend_do_init_array(znode * result,const znode * expr,const znode * offset,zend_bool is_ref TSRMLS_DC)5737 void zend_do_init_array(znode *result, const znode *expr, const znode *offset, zend_bool is_ref TSRMLS_DC) /* {{{ */
5738 {
5739 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5740
5741 opline->opcode = ZEND_INIT_ARRAY;
5742 opline->result.var = get_temporary_variable(CG(active_op_array));
5743 opline->result_type = IS_TMP_VAR;
5744 GET_NODE(result, opline->result);
5745 if (expr) {
5746 SET_NODE(opline->op1, expr);
5747 if (offset) {
5748 SET_NODE(opline->op2, offset);
5749 if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
5750 ulong index;
5751 int numeric = 0;
5752
5753 ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
5754 if (numeric) {
5755 zval_dtor(&CONSTANT(opline->op2.constant));
5756 ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
5757 } else {
5758 CALCULATE_LITERAL_HASH(opline->op2.constant);
5759 }
5760 }
5761 } else {
5762 SET_UNUSED(opline->op2);
5763 }
5764 } else {
5765 SET_UNUSED(opline->op1);
5766 SET_UNUSED(opline->op2);
5767 }
5768 opline->extended_value = is_ref;
5769 }
5770 /* }}} */
5771
zend_do_add_array_element(znode * result,const znode * expr,const znode * offset,zend_bool is_ref TSRMLS_DC)5772 void zend_do_add_array_element(znode *result, const znode *expr, const znode *offset, zend_bool is_ref TSRMLS_DC) /* {{{ */
5773 {
5774 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5775
5776 opline->opcode = ZEND_ADD_ARRAY_ELEMENT;
5777 SET_NODE(opline->result, result);
5778 SET_NODE(opline->op1, expr);
5779 if (offset) {
5780 SET_NODE(opline->op2, offset);
5781 if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) {
5782 ulong index;
5783 int numeric = 0;
5784
5785 ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
5786 if (numeric) {
5787 zval_dtor(&CONSTANT(opline->op2.constant));
5788 ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
5789 } else {
5790 CALCULATE_LITERAL_HASH(opline->op2.constant);
5791 }
5792 }
5793 } else {
5794 SET_UNUSED(opline->op2);
5795 }
5796 opline->extended_value = is_ref;
5797 }
5798 /* }}} */
5799
zend_do_add_static_array_element(znode * result,znode * offset,const znode * expr)5800 void zend_do_add_static_array_element(znode *result, znode *offset, const znode *expr) /* {{{ */
5801 {
5802 zval *element;
5803
5804 ALLOC_ZVAL(element);
5805 *element = expr->u.constant;
5806 if (offset) {
5807 switch (offset->u.constant.type & IS_CONSTANT_TYPE_MASK) {
5808 case IS_CONSTANT:
5809 /* Ugly hack to denote that this value has a constant index */
5810 Z_TYPE_P(element) |= IS_CONSTANT_INDEX;
5811 Z_STRVAL(offset->u.constant) = erealloc(Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3);
5812 Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+1] = Z_TYPE(offset->u.constant);
5813 Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+2] = 0;
5814 zend_symtable_update(result->u.constant.value.ht, Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3, &element, sizeof(zval *), NULL);
5815 zval_dtor(&offset->u.constant);
5816 break;
5817 case IS_STRING:
5818 zend_symtable_update(result->u.constant.value.ht, offset->u.constant.value.str.val, offset->u.constant.value.str.len+1, &element, sizeof(zval *), NULL);
5819 zval_dtor(&offset->u.constant);
5820 break;
5821 case IS_NULL:
5822 zend_symtable_update(Z_ARRVAL(result->u.constant), "", 1, &element, sizeof(zval *), NULL);
5823 break;
5824 case IS_LONG:
5825 case IS_BOOL:
5826 zend_hash_index_update(Z_ARRVAL(result->u.constant), Z_LVAL(offset->u.constant), &element, sizeof(zval *), NULL);
5827 break;
5828 case IS_DOUBLE:
5829 zend_hash_index_update(Z_ARRVAL(result->u.constant), zend_dval_to_lval(Z_DVAL(offset->u.constant)), &element, sizeof(zval *), NULL);
5830 break;
5831 case IS_CONSTANT_ARRAY:
5832 zend_error(E_ERROR, "Illegal offset type");
5833 break;
5834 }
5835 } else {
5836 zend_hash_next_index_insert(Z_ARRVAL(result->u.constant), &element, sizeof(zval *), NULL);
5837 }
5838 }
5839 /* }}} */
5840
zend_do_add_list_element(const znode * element TSRMLS_DC)5841 void zend_do_add_list_element(const znode *element TSRMLS_DC) /* {{{ */
5842 {
5843 list_llist_element lle;
5844
5845 if (element) {
5846 zend_check_writable_variable(element);
5847
5848 lle.var = *element;
5849 zend_llist_copy(&lle.dimensions, &CG(dimension_llist));
5850 zend_llist_prepend_element(&CG(list_llist), &lle);
5851 }
5852 (*((int *)CG(dimension_llist).tail->data))++;
5853 }
5854 /* }}} */
5855
zend_do_new_list_begin(TSRMLS_D)5856 void zend_do_new_list_begin(TSRMLS_D) /* {{{ */
5857 {
5858 int current_dimension = 0;
5859 zend_llist_add_element(&CG(dimension_llist), ¤t_dimension);
5860 }
5861 /* }}} */
5862
zend_do_new_list_end(TSRMLS_D)5863 void zend_do_new_list_end(TSRMLS_D) /* {{{ */
5864 {
5865 zend_llist_remove_tail(&CG(dimension_llist));
5866 (*((int *)CG(dimension_llist).tail->data))++;
5867 }
5868 /* }}} */
5869
zend_do_list_init(TSRMLS_D)5870 void zend_do_list_init(TSRMLS_D) /* {{{ */
5871 {
5872 zend_stack_push(&CG(list_stack), &CG(list_llist), sizeof(zend_llist));
5873 zend_stack_push(&CG(list_stack), &CG(dimension_llist), sizeof(zend_llist));
5874 zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
5875 zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
5876 zend_do_new_list_begin(TSRMLS_C);
5877 }
5878 /* }}} */
5879
zend_do_list_end(znode * result,znode * expr TSRMLS_DC)5880 void zend_do_list_end(znode *result, znode *expr TSRMLS_DC) /* {{{ */
5881 {
5882 zend_llist_element *le;
5883 zend_llist_element *dimension;
5884 zend_op *opline;
5885 znode last_container;
5886
5887 le = CG(list_llist).head;
5888 while (le) {
5889 zend_llist *tmp_dimension_llist = &((list_llist_element *)le->data)->dimensions;
5890 dimension = tmp_dimension_llist->head;
5891 while (dimension) {
5892 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
5893 if (dimension == tmp_dimension_llist->head) { /* first */
5894 last_container = *expr;
5895 switch (expr->op_type) {
5896 case IS_VAR:
5897 case IS_CV:
5898 opline->opcode = ZEND_FETCH_DIM_R;
5899 break;
5900 case IS_TMP_VAR:
5901 opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
5902 break;
5903 case IS_CONST: /* fetch_dim_tmp_var will handle this bogus fetch */
5904 zval_copy_ctor(&expr->u.constant);
5905 opline->opcode = ZEND_FETCH_DIM_TMP_VAR;
5906 break;
5907 }
5908 opline->extended_value |= ZEND_FETCH_ADD_LOCK;
5909 } else {
5910 opline->opcode = ZEND_FETCH_DIM_R;
5911 }
5912 opline->result_type = IS_VAR;
5913 opline->result.var = get_temporary_variable(CG(active_op_array));
5914 SET_NODE(opline->op1, &last_container);
5915 opline->op2_type = IS_CONST;
5916 LITERAL_LONG(opline->op2, *((int *) dimension->data));
5917 GET_NODE(&last_container, opline->result);
5918 dimension = dimension->next;
5919 }
5920 ((list_llist_element *) le->data)->value = last_container;
5921 zend_llist_destroy(&((list_llist_element *) le->data)->dimensions);
5922 zend_do_assign(result, &((list_llist_element *) le->data)->var, &((list_llist_element *) le->data)->value TSRMLS_CC);
5923 zend_do_free(result TSRMLS_CC);
5924 le = le->next;
5925 }
5926 zend_llist_destroy(&CG(dimension_llist));
5927 zend_llist_destroy(&CG(list_llist));
5928 *result = *expr;
5929 {
5930 zend_llist *p;
5931
5932 /* restore previous lists */
5933 zend_stack_top(&CG(list_stack), (void **) &p);
5934 CG(dimension_llist) = *p;
5935 zend_stack_del_top(&CG(list_stack));
5936 zend_stack_top(&CG(list_stack), (void **) &p);
5937 CG(list_llist) = *p;
5938 zend_stack_del_top(&CG(list_stack));
5939 }
5940 }
5941 /* }}} */
5942
zend_init_list(void * result,void * item TSRMLS_DC)5943 void zend_init_list(void *result, void *item TSRMLS_DC) /* {{{ */
5944 {
5945 void** list = emalloc(sizeof(void*) * 2);
5946
5947 list[0] = item;
5948 list[1] = NULL;
5949
5950 *(void**)result = list;
5951 }
5952 /* }}} */
5953
zend_add_to_list(void * result,void * item TSRMLS_DC)5954 void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
5955 {
5956 void** list = *(void**)result;
5957 size_t n = 0;
5958
5959 if (list) {
5960 while (list[n]) {
5961 n++;
5962 }
5963 }
5964
5965 list = erealloc(list, sizeof(void*) * (n+2));
5966
5967 list[n] = item;
5968 list[n+1] = NULL;
5969
5970 *(void**)result = list;
5971 }
5972 /* }}} */
5973
zend_do_fetch_static_variable(znode * varname,const znode * static_assignment,int fetch_type TSRMLS_DC)5974 void zend_do_fetch_static_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC) /* {{{ */
5975 {
5976 zval *tmp;
5977 zend_op *opline;
5978 znode lval;
5979 znode result;
5980
5981 ALLOC_ZVAL(tmp);
5982
5983 if (static_assignment) {
5984 *tmp = static_assignment->u.constant;
5985 } else {
5986 INIT_ZVAL(*tmp);
5987 }
5988 if (!CG(active_op_array)->static_variables) {
5989 if (CG(active_op_array)->scope) {
5990 CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
5991 }
5992 ALLOC_HASHTABLE(CG(active_op_array)->static_variables);
5993 zend_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
5994 }
5995 zend_hash_update(CG(active_op_array)->static_variables, varname->u.constant.value.str.val, varname->u.constant.value.str.len+1, &tmp, sizeof(zval *), NULL);
5996
5997 if (varname->op_type == IS_CONST) {
5998 if (Z_TYPE(varname->u.constant) != IS_STRING) {
5999 convert_to_string(&varname->u.constant);
6000 }
6001 }
6002
6003 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6004 opline->opcode = (fetch_type == ZEND_FETCH_LEXICAL) ? ZEND_FETCH_R : ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
6005 opline->result_type = IS_VAR;
6006 opline->result.var = get_temporary_variable(CG(active_op_array));
6007 SET_NODE(opline->op1, varname);
6008 if (opline->op1_type == IS_CONST) {
6009 CALCULATE_LITERAL_HASH(opline->op1.constant);
6010 }
6011 SET_UNUSED(opline->op2);
6012 opline->extended_value = ZEND_FETCH_STATIC;
6013 GET_NODE(&result, opline->result);
6014
6015 if (varname->op_type == IS_CONST) {
6016 zval_copy_ctor(&varname->u.constant);
6017 }
6018 fetch_simple_variable(&lval, varname, 0 TSRMLS_CC); /* Relies on the fact that the default fetch is BP_VAR_W */
6019
6020 if (fetch_type == ZEND_FETCH_LEXICAL) {
6021 znode dummy;
6022
6023 zend_do_begin_variable_parse(TSRMLS_C);
6024 zend_do_assign(&dummy, &lval, &result TSRMLS_CC);
6025 zend_do_free(&dummy TSRMLS_CC);
6026 } else {
6027 zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC);
6028 }
6029 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result_type |= EXT_TYPE_UNUSED;
6030 }
6031 /* }}} */
6032
zend_do_fetch_lexical_variable(znode * varname,zend_bool is_ref TSRMLS_DC)6033 void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC) /* {{{ */
6034 {
6035 znode value;
6036
6037 if (Z_STRLEN(varname->u.constant) == sizeof("this") - 1 &&
6038 memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this") - 1) == 0) {
6039 zend_error(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
6040 return;
6041 }
6042
6043 value.op_type = IS_CONST;
6044 ZVAL_NULL(&value.u.constant);
6045 Z_TYPE(value.u.constant) |= is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
6046 Z_SET_REFCOUNT_P(&value.u.constant, 1);
6047 Z_UNSET_ISREF_P(&value.u.constant);
6048
6049 zend_do_fetch_static_variable(varname, &value, is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC);
6050 }
6051 /* }}} */
6052
zend_do_fetch_global_variable(znode * varname,const znode * static_assignment,int fetch_type TSRMLS_DC)6053 void zend_do_fetch_global_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC) /* {{{ */
6054 {
6055 zend_op *opline;
6056 znode lval;
6057 znode result;
6058
6059 if (varname->op_type == IS_CONST) {
6060 if (Z_TYPE(varname->u.constant) != IS_STRING) {
6061 convert_to_string(&varname->u.constant);
6062 }
6063 }
6064
6065 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6066 opline->opcode = ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */
6067 opline->result_type = IS_VAR;
6068 opline->result.var = get_temporary_variable(CG(active_op_array));
6069 SET_NODE(opline->op1, varname);
6070 if (opline->op1_type == IS_CONST) {
6071 CALCULATE_LITERAL_HASH(opline->op1.constant);
6072 }
6073 SET_UNUSED(opline->op2);
6074 opline->extended_value = fetch_type;
6075 GET_NODE(&result, opline->result);
6076
6077 if (varname->op_type == IS_CONST) {
6078 zval_copy_ctor(&varname->u.constant);
6079 }
6080 fetch_simple_variable(&lval, varname, 0 TSRMLS_CC); /* Relies on the fact that the default fetch is BP_VAR_W */
6081
6082 zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC);
6083 CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result_type |= EXT_TYPE_UNUSED;
6084 }
6085 /* }}} */
6086
zend_do_cast(znode * result,const znode * expr,int type TSRMLS_DC)6087 void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC) /* {{{ */
6088 {
6089 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6090
6091 opline->opcode = ZEND_CAST;
6092 opline->result_type = IS_TMP_VAR;
6093 opline->result.var = get_temporary_variable(CG(active_op_array));
6094 SET_NODE(opline->op1, expr);
6095 SET_UNUSED(opline->op2);
6096 opline->extended_value = type;
6097 GET_NODE(result, opline->result);
6098 }
6099 /* }}} */
6100
zend_do_include_or_eval(int type,znode * result,const znode * op1 TSRMLS_DC)6101 void zend_do_include_or_eval(int type, znode *result, const znode *op1 TSRMLS_DC) /* {{{ */
6102 {
6103 zend_do_extended_fcall_begin(TSRMLS_C);
6104 {
6105 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6106
6107 opline->opcode = ZEND_INCLUDE_OR_EVAL;
6108 opline->result_type = IS_VAR;
6109 opline->result.var = get_temporary_variable(CG(active_op_array));
6110 SET_NODE(opline->op1, op1);
6111 SET_UNUSED(opline->op2);
6112 opline->extended_value = type;
6113 GET_NODE(result, opline->result);
6114 }
6115 zend_do_extended_fcall_end(TSRMLS_C);
6116 }
6117 /* }}} */
6118
zend_do_indirect_references(znode * result,const znode * num_references,znode * variable TSRMLS_DC)6119 void zend_do_indirect_references(znode *result, const znode *num_references, znode *variable TSRMLS_DC) /* {{{ */
6120 {
6121 int i;
6122
6123 zend_do_end_variable_parse(variable, BP_VAR_R, 0 TSRMLS_CC);
6124 for (i=1; i<num_references->u.constant.value.lval; i++) {
6125 fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R TSRMLS_CC);
6126 *variable = *result;
6127 }
6128 zend_do_begin_variable_parse(TSRMLS_C);
6129 fetch_simple_variable(result, variable, 1 TSRMLS_CC);
6130 /* there is a chance someone is accessing $this */
6131 if (CG(active_op_array)->scope && CG(active_op_array)->this_var == -1) {
6132 CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1, THIS_HASHVAL TSRMLS_CC);
6133 }
6134 }
6135 /* }}} */
6136
zend_do_unset(const znode * variable TSRMLS_DC)6137 void zend_do_unset(const znode *variable TSRMLS_DC) /* {{{ */
6138 {
6139 zend_op *last_op;
6140
6141 zend_check_writable_variable(variable);
6142
6143 if (variable->op_type == IS_CV) {
6144 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6145 opline->opcode = ZEND_UNSET_VAR;
6146 SET_NODE(opline->op1, variable);
6147 SET_UNUSED(opline->op2);
6148 SET_UNUSED(opline->result);
6149 opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
6150 } else {
6151 last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1];
6152
6153 switch (last_op->opcode) {
6154 case ZEND_FETCH_UNSET:
6155 last_op->opcode = ZEND_UNSET_VAR;
6156 SET_UNUSED(last_op->result);
6157 break;
6158 case ZEND_FETCH_DIM_UNSET:
6159 last_op->opcode = ZEND_UNSET_DIM;
6160 SET_UNUSED(last_op->result);
6161 break;
6162 case ZEND_FETCH_OBJ_UNSET:
6163 last_op->opcode = ZEND_UNSET_OBJ;
6164 SET_UNUSED(last_op->result);
6165 break;
6166
6167 }
6168 }
6169 }
6170 /* }}} */
6171
zend_do_isset_or_isempty(int type,znode * result,znode * variable TSRMLS_DC)6172 void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC) /* {{{ */
6173 {
6174 zend_op *last_op;
6175
6176 zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC);
6177
6178 if (zend_is_function_or_method_call(variable)) {
6179 if (type == ZEND_ISEMPTY) {
6180 /* empty(func()) can be transformed to !func() */
6181 zend_do_unary_op(ZEND_BOOL_NOT, result, variable TSRMLS_CC);
6182 } else {
6183 zend_error(E_COMPILE_ERROR, "Cannot use isset() on the result of a function call (you can use \"null !== func()\" instead)");
6184 }
6185
6186 return;
6187 }
6188
6189 if (variable->op_type == IS_CV) {
6190 last_op = get_next_op(CG(active_op_array) TSRMLS_CC);
6191 last_op->opcode = ZEND_ISSET_ISEMPTY_VAR;
6192 SET_NODE(last_op->op1, variable);
6193 SET_UNUSED(last_op->op2);
6194 last_op->result.var = get_temporary_variable(CG(active_op_array));
6195 last_op->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET;
6196 } else {
6197 last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1];
6198
6199 switch (last_op->opcode) {
6200 case ZEND_FETCH_IS:
6201 last_op->opcode = ZEND_ISSET_ISEMPTY_VAR;
6202 break;
6203 case ZEND_FETCH_DIM_IS:
6204 last_op->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
6205 break;
6206 case ZEND_FETCH_OBJ_IS:
6207 last_op->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
6208 break;
6209 }
6210 }
6211 last_op->result_type = IS_TMP_VAR;
6212 last_op->extended_value |= type;
6213
6214 GET_NODE(result, last_op->result);
6215 }
6216 /* }}} */
6217
zend_do_instanceof(znode * result,const znode * expr,const znode * class_znode,int type TSRMLS_DC)6218 void zend_do_instanceof(znode *result, const znode *expr, const znode *class_znode, int type TSRMLS_DC) /* {{{ */
6219 {
6220 int last_op_number = get_next_op_number(CG(active_op_array));
6221 zend_op *opline;
6222
6223 if (last_op_number > 0) {
6224 opline = &CG(active_op_array)->opcodes[last_op_number-1];
6225 if (opline->opcode == ZEND_FETCH_CLASS) {
6226 opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD;
6227 }
6228 }
6229
6230 if (expr->op_type == IS_CONST) {
6231 zend_error(E_COMPILE_ERROR, "instanceof expects an object instance, constant given");
6232 }
6233
6234 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6235 opline->opcode = ZEND_INSTANCEOF;
6236 opline->result_type = IS_TMP_VAR;
6237 opline->result.var = get_temporary_variable(CG(active_op_array));
6238 SET_NODE(opline->op1, expr);
6239
6240 SET_NODE(opline->op2, class_znode);
6241
6242 GET_NODE(result, opline->result);
6243 }
6244 /* }}} */
6245
zend_do_foreach_begin(znode * foreach_token,znode * open_brackets_token,znode * array,znode * as_token,int variable TSRMLS_DC)6246 void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, znode *as_token, int variable TSRMLS_DC) /* {{{ */
6247 {
6248 zend_op *opline;
6249 zend_bool is_variable;
6250 zend_op dummy_opline;
6251
6252 if (variable) {
6253 if (zend_is_function_or_method_call(array)) {
6254 is_variable = 0;
6255 } else {
6256 is_variable = 1;
6257 }
6258 /* save the location of FETCH_W instruction(s) */
6259 open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
6260 zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC);
6261
6262 if (zend_is_function_or_method_call(array)) {
6263 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6264 opline->opcode = ZEND_SEPARATE;
6265 SET_NODE(opline->op1, array);
6266 SET_UNUSED(opline->op2);
6267 opline->result_type = IS_VAR;
6268 opline->result.var = opline->op1.var;
6269 }
6270 } else {
6271 is_variable = 0;
6272 open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
6273 }
6274
6275 /* save the location of FE_RESET */
6276 foreach_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
6277
6278 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6279
6280 /* Preform array reset */
6281 opline->opcode = ZEND_FE_RESET;
6282 opline->result_type = IS_VAR;
6283 opline->result.var = get_temporary_variable(CG(active_op_array));
6284 SET_NODE(opline->op1, array);
6285 SET_UNUSED(opline->op2);
6286 opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0;
6287
6288 COPY_NODE(dummy_opline.result, opline->result);
6289 zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
6290
6291 /* save the location of FE_FETCH */
6292 as_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
6293
6294 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6295 opline->opcode = ZEND_FE_FETCH;
6296 opline->result_type = IS_VAR;
6297 opline->result.var = get_temporary_variable(CG(active_op_array));
6298 COPY_NODE(opline->op1, dummy_opline.result);
6299 opline->extended_value = 0;
6300 SET_UNUSED(opline->op2);
6301
6302 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6303 opline->opcode = ZEND_OP_DATA;
6304 SET_UNUSED(opline->op1);
6305 SET_UNUSED(opline->op2);
6306 SET_UNUSED(opline->result);
6307 }
6308 /* }}} */
6309
zend_do_foreach_cont(znode * foreach_token,const znode * open_brackets_token,const znode * as_token,znode * value,znode * key TSRMLS_DC)6310 void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token, const znode *as_token, znode *value, znode *key TSRMLS_DC) /* {{{ */
6311 {
6312 zend_op *opline;
6313 znode dummy, value_node;
6314 zend_bool assign_by_ref=0;
6315
6316 opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num];
6317 if (key->op_type != IS_UNUSED) {
6318 znode *tmp;
6319
6320 /* switch between the key and value... */
6321 tmp = key;
6322 key = value;
6323 value = tmp;
6324
6325 /* Mark extended_value in case both key and value are being used */
6326 opline->extended_value |= ZEND_FE_FETCH_WITH_KEY;
6327 }
6328
6329 if ((key->op_type != IS_UNUSED)) {
6330 if (key->EA & ZEND_PARSED_REFERENCE_VARIABLE) {
6331 zend_error(E_COMPILE_ERROR, "Key element cannot be a reference");
6332 }
6333 if (key->EA & ZEND_PARSED_LIST_EXPR) {
6334 zend_error(E_COMPILE_ERROR, "Cannot use list as key element");
6335 }
6336 }
6337
6338 if (value->EA & ZEND_PARSED_REFERENCE_VARIABLE) {
6339 assign_by_ref = 1;
6340
6341 /* Mark extended_value for assign-by-reference */
6342 opline->extended_value |= ZEND_FE_FETCH_BYREF;
6343 CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE;
6344 } else {
6345 zend_op *fetch = &CG(active_op_array)->opcodes[foreach_token->u.op.opline_num];
6346 zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.op.opline_num];
6347
6348 /* Change "write context" into "read context" */
6349 fetch->extended_value = 0; /* reset ZEND_FE_RESET_VARIABLE */
6350 while (fetch != end) {
6351 --fetch;
6352 if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) {
6353 zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
6354 }
6355 if (fetch->opcode == ZEND_SEPARATE) {
6356 MAKE_NOP(fetch);
6357 } else {
6358 fetch->opcode -= 3; /* FETCH_W -> FETCH_R */
6359 }
6360 }
6361 }
6362
6363 GET_NODE(&value_node, opline->result);
6364
6365 if (value->EA & ZEND_PARSED_LIST_EXPR) {
6366 if (!CG(list_llist).head) {
6367 zend_error(E_COMPILE_ERROR, "Cannot use empty list");
6368 }
6369 zend_do_list_end(&dummy, &value_node TSRMLS_CC);
6370 zend_do_free(&dummy TSRMLS_CC);
6371 } else {
6372 if (assign_by_ref) {
6373 zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC);
6374 /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */
6375 zend_do_assign_ref(NULL, value, &value_node TSRMLS_CC);
6376 } else {
6377 zend_do_assign(&dummy, value, &value_node TSRMLS_CC);
6378 zend_do_free(&dummy TSRMLS_CC);
6379 }
6380 }
6381
6382 if (key->op_type != IS_UNUSED) {
6383 znode key_node;
6384
6385 opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num+1];
6386 opline->result_type = IS_TMP_VAR;
6387 opline->result.opline_num = get_temporary_variable(CG(active_op_array));
6388 GET_NODE(&key_node, opline->result);
6389
6390 zend_do_assign(&dummy, key, &key_node TSRMLS_CC);
6391 zend_do_free(&dummy TSRMLS_CC);
6392 }
6393
6394 do_begin_loop(TSRMLS_C);
6395 INC_BPC(CG(active_op_array));
6396 }
6397 /* }}} */
6398
zend_do_foreach_end(const znode * foreach_token,const znode * as_token TSRMLS_DC)6399 void zend_do_foreach_end(const znode *foreach_token, const znode *as_token TSRMLS_DC) /* {{{ */
6400 {
6401 zend_op *container_ptr;
6402 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6403
6404 opline->opcode = ZEND_JMP;
6405 opline->op1.opline_num = as_token->u.op.opline_num;
6406 SET_UNUSED(opline->op1);
6407 SET_UNUSED(opline->op2);
6408
6409 CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_RESET */
6410 CG(active_op_array)->opcodes[as_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_FETCH */
6411
6412 do_end_loop(as_token->u.op.opline_num, 1 TSRMLS_CC);
6413
6414 zend_stack_top(&CG(foreach_copy_stack), (void **) &container_ptr);
6415 generate_free_foreach_copy(container_ptr TSRMLS_CC);
6416 zend_stack_del_top(&CG(foreach_copy_stack));
6417
6418 DEC_BPC(CG(active_op_array));
6419 }
6420 /* }}} */
6421
zend_do_declare_begin(TSRMLS_D)6422 void zend_do_declare_begin(TSRMLS_D) /* {{{ */
6423 {
6424 zend_stack_push(&CG(declare_stack), &CG(declarables), sizeof(zend_declarables));
6425 }
6426 /* }}} */
6427
zend_do_declare_stmt(znode * var,znode * val TSRMLS_DC)6428 void zend_do_declare_stmt(znode *var, znode *val TSRMLS_DC) /* {{{ */
6429 {
6430 if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "ticks", sizeof("ticks")-1)) {
6431 convert_to_long(&val->u.constant);
6432 CG(declarables).ticks = val->u.constant;
6433 } else if (!zend_binary_strcasecmp(var->u.constant.value.str.val, var->u.constant.value.str.len, "encoding", sizeof("encoding")-1)) {
6434 if ((Z_TYPE(val->u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) {
6435 zend_error(E_COMPILE_ERROR, "Cannot use constants as encoding");
6436 }
6437
6438 /*
6439 * Check that the pragma comes before any opcodes. If the compilation
6440 * got as far as this, the previous portion of the script must have been
6441 * parseable according to the .ini script_encoding setting. We still
6442 * want to tell them to put declare() at the top.
6443 */
6444 {
6445 int num = CG(active_op_array)->last;
6446 /* ignore ZEND_EXT_STMT and ZEND_TICKS */
6447 while (num > 0 &&
6448 (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
6449 CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
6450 --num;
6451 }
6452
6453 if (num > 0) {
6454 zend_error(E_COMPILE_ERROR, "Encoding declaration pragma must be the very first statement in the script");
6455 }
6456 }
6457
6458 if (CG(multibyte)) {
6459 const zend_encoding *new_encoding, *old_encoding;
6460 zend_encoding_filter old_input_filter;
6461
6462 CG(encoding_declared) = 1;
6463
6464 convert_to_string(&val->u.constant);
6465 new_encoding = zend_multibyte_fetch_encoding(val->u.constant.value.str.val TSRMLS_CC);
6466 if (!new_encoding) {
6467 zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", val->u.constant.value.str.val);
6468 } else {
6469 old_input_filter = LANG_SCNG(input_filter);
6470 old_encoding = LANG_SCNG(script_encoding);
6471 zend_multibyte_set_filter(new_encoding TSRMLS_CC);
6472
6473 /* need to re-scan if input filter changed */
6474 if (old_input_filter != LANG_SCNG(input_filter) ||
6475 (old_input_filter && new_encoding != old_encoding)) {
6476 zend_multibyte_yyinput_again(old_input_filter, old_encoding TSRMLS_CC);
6477 }
6478 }
6479 } else {
6480 zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because Zend multibyte feature is turned off by settings");
6481 }
6482 zval_dtor(&val->u.constant);
6483 } else {
6484 zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", var->u.constant.value.str.val);
6485 zval_dtor(&val->u.constant);
6486 }
6487 zval_dtor(&var->u.constant);
6488 }
6489 /* }}} */
6490
zend_do_declare_end(const znode * declare_token TSRMLS_DC)6491 void zend_do_declare_end(const znode *declare_token TSRMLS_DC) /* {{{ */
6492 {
6493 zend_declarables *declarables;
6494
6495 zend_stack_top(&CG(declare_stack), (void **) &declarables);
6496 /* We should restore if there was more than (current - start) - (ticks?1:0) opcodes */
6497 if ((get_next_op_number(CG(active_op_array)) - declare_token->u.op.opline_num) - ((Z_LVAL(CG(declarables).ticks))?1:0)) {
6498 CG(declarables) = *declarables;
6499 }
6500 }
6501 /* }}} */
6502
zend_do_exit(znode * result,const znode * message TSRMLS_DC)6503 void zend_do_exit(znode *result, const znode *message TSRMLS_DC) /* {{{ */
6504 {
6505 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6506
6507 opline->opcode = ZEND_EXIT;
6508 SET_NODE(opline->op1, message);
6509 SET_UNUSED(opline->op2);
6510
6511 result->op_type = IS_CONST;
6512 Z_TYPE(result->u.constant) = IS_BOOL;
6513 Z_LVAL(result->u.constant) = 1;
6514 }
6515 /* }}} */
6516
zend_do_begin_silence(znode * strudel_token TSRMLS_DC)6517 void zend_do_begin_silence(znode *strudel_token TSRMLS_DC) /* {{{ */
6518 {
6519 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6520
6521 opline->opcode = ZEND_BEGIN_SILENCE;
6522 opline->result_type = IS_TMP_VAR;
6523 opline->result.var = get_temporary_variable(CG(active_op_array));
6524 SET_UNUSED(opline->op1);
6525 SET_UNUSED(opline->op2);
6526 GET_NODE(strudel_token, opline->result);
6527 }
6528 /* }}} */
6529
zend_do_end_silence(const znode * strudel_token TSRMLS_DC)6530 void zend_do_end_silence(const znode *strudel_token TSRMLS_DC) /* {{{ */
6531 {
6532 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6533
6534 opline->opcode = ZEND_END_SILENCE;
6535 SET_NODE(opline->op1, strudel_token);
6536 SET_UNUSED(opline->op2);
6537 }
6538 /* }}} */
6539
zend_do_jmp_set(const znode * value,znode * jmp_token,znode * colon_token TSRMLS_DC)6540 void zend_do_jmp_set(const znode *value, znode *jmp_token, znode *colon_token TSRMLS_DC) /* {{{ */
6541 {
6542 int op_number = get_next_op_number(CG(active_op_array));
6543 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6544
6545 if (value->op_type == IS_VAR || value->op_type == IS_CV) {
6546 opline->opcode = ZEND_JMP_SET_VAR;
6547 opline->result_type = IS_VAR;
6548 } else {
6549 opline->opcode = ZEND_JMP_SET;
6550 opline->result_type = IS_TMP_VAR;
6551 }
6552 opline->result.var = get_temporary_variable(CG(active_op_array));
6553 SET_NODE(opline->op1, value);
6554 SET_UNUSED(opline->op2);
6555
6556 GET_NODE(colon_token, opline->result);
6557
6558 jmp_token->u.op.opline_num = op_number;
6559
6560 INC_BPC(CG(active_op_array));
6561 }
6562 /* }}} */
6563
zend_do_jmp_set_else(znode * result,const znode * false_value,const znode * jmp_token,const znode * colon_token TSRMLS_DC)6564 void zend_do_jmp_set_else(znode *result, const znode *false_value, const znode *jmp_token, const znode *colon_token TSRMLS_DC) /* {{{ */
6565 {
6566 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6567
6568 SET_NODE(opline->result, colon_token);
6569 if (colon_token->op_type == IS_TMP_VAR) {
6570 if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) {
6571 CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].opcode = ZEND_JMP_SET_VAR;
6572 CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].result_type = IS_VAR;
6573 opline->opcode = ZEND_QM_ASSIGN_VAR;
6574 opline->result_type = IS_VAR;
6575 } else {
6576 opline->opcode = ZEND_QM_ASSIGN;
6577 }
6578 } else {
6579 opline->opcode = ZEND_QM_ASSIGN_VAR;
6580 }
6581 opline->extended_value = 0;
6582 SET_NODE(opline->op1, false_value);
6583 SET_UNUSED(opline->op2);
6584
6585 GET_NODE(result, opline->result);
6586
6587 CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
6588
6589 DEC_BPC(CG(active_op_array));
6590 }
6591 /* }}} */
6592
zend_do_begin_qm_op(const znode * cond,znode * qm_token TSRMLS_DC)6593 void zend_do_begin_qm_op(const znode *cond, znode *qm_token TSRMLS_DC) /* {{{ */
6594 {
6595 int jmpz_op_number = get_next_op_number(CG(active_op_array));
6596 zend_op *opline;
6597
6598 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6599
6600 opline->opcode = ZEND_JMPZ;
6601 SET_NODE(opline->op1, cond);
6602 SET_UNUSED(opline->op2);
6603 opline->op2.opline_num = jmpz_op_number;
6604 GET_NODE(qm_token, opline->op2);
6605
6606 INC_BPC(CG(active_op_array));
6607 }
6608 /* }}} */
6609
zend_do_qm_true(const znode * true_value,znode * qm_token,znode * colon_token TSRMLS_DC)6610 void zend_do_qm_true(const znode *true_value, znode *qm_token, znode *colon_token TSRMLS_DC) /* {{{ */
6611 {
6612 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6613
6614 CG(active_op_array)->opcodes[qm_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */
6615
6616 if (true_value->op_type == IS_VAR || true_value->op_type == IS_CV) {
6617 opline->opcode = ZEND_QM_ASSIGN_VAR;
6618 opline->result_type = IS_VAR;
6619 } else {
6620 opline->opcode = ZEND_QM_ASSIGN;
6621 opline->result_type = IS_TMP_VAR;
6622 }
6623 opline->result.var = get_temporary_variable(CG(active_op_array));
6624 SET_NODE(opline->op1, true_value);
6625 SET_UNUSED(opline->op2);
6626
6627 GET_NODE(qm_token, opline->result);
6628 colon_token->u.op.opline_num = get_next_op_number(CG(active_op_array));
6629
6630 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6631 opline->opcode = ZEND_JMP;
6632 SET_UNUSED(opline->op1);
6633 SET_UNUSED(opline->op2);
6634 }
6635 /* }}} */
6636
zend_do_qm_false(znode * result,const znode * false_value,const znode * qm_token,const znode * colon_token TSRMLS_DC)6637 void zend_do_qm_false(znode *result, const znode *false_value, const znode *qm_token, const znode *colon_token TSRMLS_DC) /* {{{ */
6638 {
6639 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6640
6641 SET_NODE(opline->result, qm_token);
6642 if (qm_token->op_type == IS_TMP_VAR) {
6643 if (false_value->op_type == IS_VAR || false_value->op_type == IS_CV) {
6644 CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].opcode = ZEND_QM_ASSIGN_VAR;
6645 CG(active_op_array)->opcodes[colon_token->u.op.opline_num - 1].result_type = IS_VAR;
6646 opline->opcode = ZEND_QM_ASSIGN_VAR;
6647 opline->result_type = IS_VAR;
6648 } else {
6649 opline->opcode = ZEND_QM_ASSIGN;
6650 }
6651 } else {
6652 opline->opcode = ZEND_QM_ASSIGN_VAR;
6653 }
6654 SET_NODE(opline->op1, false_value);
6655 SET_UNUSED(opline->op2);
6656
6657 CG(active_op_array)->opcodes[colon_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
6658
6659 GET_NODE(result, opline->result);
6660
6661 DEC_BPC(CG(active_op_array));
6662 }
6663 /* }}} */
6664
zend_do_extended_info(TSRMLS_D)6665 void zend_do_extended_info(TSRMLS_D) /* {{{ */
6666 {
6667 zend_op *opline;
6668
6669 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
6670 return;
6671 }
6672
6673 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6674
6675 opline->opcode = ZEND_EXT_STMT;
6676 SET_UNUSED(opline->op1);
6677 SET_UNUSED(opline->op2);
6678 }
6679 /* }}} */
6680
zend_do_extended_fcall_begin(TSRMLS_D)6681 void zend_do_extended_fcall_begin(TSRMLS_D) /* {{{ */
6682 {
6683 zend_op *opline;
6684
6685 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
6686 return;
6687 }
6688
6689 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6690
6691 opline->opcode = ZEND_EXT_FCALL_BEGIN;
6692 SET_UNUSED(opline->op1);
6693 SET_UNUSED(opline->op2);
6694 }
6695 /* }}} */
6696
zend_do_extended_fcall_end(TSRMLS_D)6697 void zend_do_extended_fcall_end(TSRMLS_D) /* {{{ */
6698 {
6699 zend_op *opline;
6700
6701 if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO)) {
6702 return;
6703 }
6704
6705 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6706
6707 opline->opcode = ZEND_EXT_FCALL_END;
6708 SET_UNUSED(opline->op1);
6709 SET_UNUSED(opline->op2);
6710 }
6711 /* }}} */
6712
zend_do_ticks(TSRMLS_D)6713 void zend_do_ticks(TSRMLS_D) /* {{{ */
6714 {
6715 zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
6716
6717 opline->opcode = ZEND_TICKS;
6718 SET_UNUSED(opline->op1);
6719 SET_UNUSED(opline->op2);
6720 opline->extended_value = Z_LVAL(CG(declarables).ticks);
6721 }
6722 /* }}} */
6723
zend_is_auto_global_quick(const char * name,uint name_len,ulong hashval TSRMLS_DC)6724 zend_bool zend_is_auto_global_quick(const char *name, uint name_len, ulong hashval TSRMLS_DC) /* {{{ */
6725 {
6726 zend_auto_global *auto_global;
6727 ulong hash = hashval ? hashval : zend_hash_func(name, name_len+1);
6728
6729 if (zend_hash_quick_find(CG(auto_globals), name, name_len+1, hash, (void **) &auto_global)==SUCCESS) {
6730 if (auto_global->armed) {
6731 auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
6732 }
6733 return 1;
6734 }
6735 return 0;
6736 }
6737 /* }}} */
6738
zend_is_auto_global(const char * name,uint name_len TSRMLS_DC)6739 zend_bool zend_is_auto_global(const char *name, uint name_len TSRMLS_DC) /* {{{ */
6740 {
6741 return zend_is_auto_global_quick(name, name_len, 0 TSRMLS_CC);
6742 }
6743 /* }}} */
6744
zend_register_auto_global(const char * name,uint name_len,zend_bool jit,zend_auto_global_callback auto_global_callback TSRMLS_DC)6745 int zend_register_auto_global(const char *name, uint name_len, zend_bool jit, zend_auto_global_callback auto_global_callback TSRMLS_DC) /* {{{ */
6746 {
6747 zend_auto_global auto_global;
6748
6749 auto_global.name = zend_new_interned_string((char*)name, name_len + 1, 0 TSRMLS_CC);
6750 auto_global.name_len = name_len;
6751 auto_global.auto_global_callback = auto_global_callback;
6752 auto_global.jit = jit;
6753
6754 return zend_hash_add(CG(auto_globals), name, name_len+1, &auto_global, sizeof(zend_auto_global), NULL);
6755 }
6756 /* }}} */
6757
zend_auto_global_init(zend_auto_global * auto_global TSRMLS_DC)6758 static int zend_auto_global_init(zend_auto_global *auto_global TSRMLS_DC) /* {{{ */
6759 {
6760 if (auto_global->jit) {
6761 auto_global->armed = 1;
6762 } else if (auto_global->auto_global_callback) {
6763 auto_global->armed = auto_global->auto_global_callback(auto_global->name, auto_global->name_len TSRMLS_CC);
6764 } else {
6765 auto_global->armed = 0;
6766 }
6767 return 0;
6768 }
6769 /* }}} */
6770
zend_activate_auto_globals(TSRMLS_D)6771 ZEND_API void zend_activate_auto_globals(TSRMLS_D) /* {{{ */
6772 {
6773 zend_hash_apply(CG(auto_globals), (apply_func_t) zend_auto_global_init TSRMLS_CC);
6774 }
6775 /* }}} */
6776
zendlex(znode * zendlval TSRMLS_DC)6777 int zendlex(znode *zendlval TSRMLS_DC) /* {{{ */
6778 {
6779 int retval;
6780
6781 if (CG(increment_lineno)) {
6782 CG(zend_lineno)++;
6783 CG(increment_lineno) = 0;
6784 }
6785
6786 again:
6787 Z_TYPE(zendlval->u.constant) = IS_LONG;
6788 retval = lex_scan(&zendlval->u.constant TSRMLS_CC);
6789 switch (retval) {
6790 case T_COMMENT:
6791 case T_DOC_COMMENT:
6792 case T_OPEN_TAG:
6793 case T_WHITESPACE:
6794 goto again;
6795
6796 case T_CLOSE_TAG:
6797 if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') {
6798 CG(increment_lineno) = 1;
6799 }
6800 if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
6801 goto again;
6802 }
6803 retval = ';'; /* implicit ; */
6804 break;
6805 case T_OPEN_TAG_WITH_ECHO:
6806 retval = T_ECHO;
6807 break;
6808 }
6809
6810 INIT_PZVAL(&zendlval->u.constant);
6811 zendlval->op_type = IS_CONST;
6812 return retval;
6813 }
6814 /* }}} */
6815
zend_initialize_class_data(zend_class_entry * ce,zend_bool nullify_handlers TSRMLS_DC)6816 ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers TSRMLS_DC) /* {{{ */
6817 {
6818 zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
6819 dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR);
6820
6821 ce->refcount = 1;
6822 ce->ce_flags = 0;
6823
6824 ce->default_properties_table = NULL;
6825 ce->default_static_members_table = NULL;
6826 zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0);
6827 zend_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
6828 zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
6829
6830 if (ce->type == ZEND_INTERNAL_CLASS) {
6831 #ifdef ZTS
6832 int n = zend_hash_num_elements(CG(class_table));
6833
6834 if (CG(static_members_table) && n >= CG(last_static_member)) {
6835 /* Support for run-time declaration: dl() */
6836 CG(last_static_member) = n+1;
6837 CG(static_members_table) = realloc(CG(static_members_table), (n+1)*sizeof(zval**));
6838 CG(static_members_table)[n] = NULL;
6839 }
6840 ce->static_members_table = (zval**)(zend_intptr_t)n;
6841 #else
6842 ce->static_members_table = NULL;
6843 #endif
6844 } else {
6845 ce->static_members_table = ce->default_static_members_table;
6846 ce->info.user.doc_comment = NULL;
6847 ce->info.user.doc_comment_len = 0;
6848 }
6849
6850 ce->default_properties_count = 0;
6851 ce->default_static_members_count = 0;
6852
6853 if (nullify_handlers) {
6854 ce->constructor = NULL;
6855 ce->destructor = NULL;
6856 ce->clone = NULL;
6857 ce->__get = NULL;
6858 ce->__set = NULL;
6859 ce->__unset = NULL;
6860 ce->__isset = NULL;
6861 ce->__call = NULL;
6862 ce->__callstatic = NULL;
6863 ce->__tostring = NULL;
6864 ce->create_object = NULL;
6865 ce->get_iterator = NULL;
6866 ce->iterator_funcs.funcs = NULL;
6867 ce->interface_gets_implemented = NULL;
6868 ce->get_static_method = NULL;
6869 ce->parent = NULL;
6870 ce->num_interfaces = 0;
6871 ce->interfaces = NULL;
6872 ce->num_traits = 0;
6873 ce->traits = NULL;
6874 ce->trait_aliases = NULL;
6875 ce->trait_precedences = NULL;
6876 ce->serialize = NULL;
6877 ce->unserialize = NULL;
6878 ce->serialize_func = NULL;
6879 ce->unserialize_func = NULL;
6880 if (ce->type == ZEND_INTERNAL_CLASS) {
6881 ce->info.internal.module = NULL;
6882 ce->info.internal.builtin_functions = NULL;
6883 }
6884 }
6885 }
6886 /* }}} */
6887
zend_get_class_fetch_type(const char * class_name,uint class_name_len)6888 int zend_get_class_fetch_type(const char *class_name, uint class_name_len) /* {{{ */
6889 {
6890 if ((class_name_len == sizeof("self")-1) &&
6891 !strncasecmp(class_name, "self", sizeof("self")-1)) {
6892 return ZEND_FETCH_CLASS_SELF;
6893 } else if ((class_name_len == sizeof("parent")-1) &&
6894 !strncasecmp(class_name, "parent", sizeof("parent")-1)) {
6895 return ZEND_FETCH_CLASS_PARENT;
6896 } else if ((class_name_len == sizeof("static")-1) &&
6897 !strncasecmp(class_name, "static", sizeof("static")-1)) {
6898 return ZEND_FETCH_CLASS_STATIC;
6899 } else {
6900 return ZEND_FETCH_CLASS_DEFAULT;
6901 }
6902 }
6903 /* }}} */
6904
zend_get_compiled_variable_name(const zend_op_array * op_array,zend_uint var,int * name_len)6905 ZEND_API const char* zend_get_compiled_variable_name(const zend_op_array *op_array, zend_uint var, int* name_len) /* {{{ */
6906 {
6907 if (name_len) {
6908 *name_len = op_array->vars[var].name_len;
6909 }
6910 return op_array->vars[var].name;
6911 }
6912 /* }}} */
6913
zend_do_build_namespace_name(znode * result,znode * prefix,znode * name TSRMLS_DC)6914 void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC) /* {{{ */
6915 {
6916 if (prefix) {
6917 *result = *prefix;
6918 if (Z_TYPE(result->u.constant) == IS_STRING &&
6919 Z_STRLEN(result->u.constant) == 0) {
6920 /* namespace\ */
6921 if (CG(current_namespace)) {
6922 znode tmp;
6923
6924 zval_dtor(&result->u.constant);
6925 tmp.op_type = IS_CONST;
6926 tmp.u.constant = *CG(current_namespace);
6927 zval_copy_ctor(&tmp.u.constant);
6928 zend_do_build_namespace_name(result, NULL, &tmp TSRMLS_CC);
6929 }
6930 }
6931 } else {
6932 result->op_type = IS_CONST;
6933 Z_TYPE(result->u.constant) = IS_STRING;
6934 Z_STRVAL(result->u.constant) = NULL;
6935 Z_STRLEN(result->u.constant) = 0;
6936 }
6937 /* prefix = result */
6938 zend_do_build_full_name(NULL, result, name, 0 TSRMLS_CC);
6939 }
6940 /* }}} */
6941
zend_do_begin_namespace(const znode * name,zend_bool with_bracket TSRMLS_DC)6942 void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC) /* {{{ */
6943 {
6944 char *lcname;
6945
6946 /* handle mixed syntax declaration or nested namespaces */
6947 if (!CG(has_bracketed_namespaces)) {
6948 if (CG(current_namespace)) {
6949 /* previous namespace declarations were unbracketed */
6950 if (with_bracket) {
6951 zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations");
6952 }
6953 }
6954 } else {
6955 /* previous namespace declarations were bracketed */
6956 if (!with_bracket) {
6957 zend_error(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations with unbracketed namespace declarations");
6958 } else if (CG(current_namespace) || CG(in_namespace)) {
6959 zend_error(E_COMPILE_ERROR, "Namespace declarations cannot be nested");
6960 }
6961 }
6962
6963 if (((!with_bracket && !CG(current_namespace)) || (with_bracket && !CG(has_bracketed_namespaces))) && CG(active_op_array)->last > 0) {
6964 /* ignore ZEND_EXT_STMT and ZEND_TICKS */
6965 int num = CG(active_op_array)->last;
6966 while (num > 0 &&
6967 (CG(active_op_array)->opcodes[num-1].opcode == ZEND_EXT_STMT ||
6968 CG(active_op_array)->opcodes[num-1].opcode == ZEND_TICKS)) {
6969 --num;
6970 }
6971 if (num > 0) {
6972 zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script");
6973 }
6974 }
6975
6976 CG(in_namespace) = 1;
6977 if (with_bracket) {
6978 CG(has_bracketed_namespaces) = 1;
6979 }
6980
6981 if (name) {
6982 lcname = zend_str_tolower_dup(Z_STRVAL(name->u.constant), Z_STRLEN(name->u.constant));
6983 if (((Z_STRLEN(name->u.constant) == sizeof("self")-1) &&
6984 !memcmp(lcname, "self", sizeof("self")-1)) ||
6985 ((Z_STRLEN(name->u.constant) == sizeof("parent")-1) &&
6986 !memcmp(lcname, "parent", sizeof("parent")-1))) {
6987 zend_error(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", Z_STRVAL(name->u.constant));
6988 }
6989 efree(lcname);
6990
6991 if (CG(current_namespace)) {
6992 zval_dtor(CG(current_namespace));
6993 } else {
6994 ALLOC_ZVAL(CG(current_namespace));
6995 }
6996 *CG(current_namespace) = name->u.constant;
6997 } else {
6998 if (CG(current_namespace)) {
6999 zval_dtor(CG(current_namespace));
7000 FREE_ZVAL(CG(current_namespace));
7001 CG(current_namespace) = NULL;
7002 }
7003 }
7004
7005 if (CG(current_import)) {
7006 zend_hash_destroy(CG(current_import));
7007 efree(CG(current_import));
7008 CG(current_import) = NULL;
7009 }
7010
7011 if (CG(doc_comment)) {
7012 efree(CG(doc_comment));
7013 CG(doc_comment) = NULL;
7014 CG(doc_comment_len) = 0;
7015 }
7016 }
7017 /* }}} */
7018
zend_do_use(znode * ns_name,znode * new_name TSRMLS_DC)7019 void zend_do_use(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */
7020 {
7021 char *lcname;
7022 zval *name, *ns, tmp;
7023 zend_bool warn = 0;
7024 zend_class_entry **pce;
7025
7026 if (!CG(current_import)) {
7027 CG(current_import) = emalloc(sizeof(HashTable));
7028 zend_hash_init(CG(current_import), 0, NULL, ZVAL_PTR_DTOR, 0);
7029 }
7030
7031 ALLOC_ZVAL(ns);
7032 *ns = ns_name->u.constant;
7033 if (new_name) {
7034 name = &new_name->u.constant;
7035 } else {
7036 const char *p;
7037
7038 /* The form "use A\B" is eqivalent to "use A\B as B".
7039 So we extract the last part of compound name to use as a new_name */
7040 name = &tmp;
7041 p = zend_memrchr(Z_STRVAL_P(ns), '\\', Z_STRLEN_P(ns));
7042 if (p) {
7043 ZVAL_STRING(name, p+1, 1);
7044 } else {
7045 *name = *ns;
7046 zval_copy_ctor(name);
7047 warn = !CG(current_namespace);
7048 }
7049 }
7050
7051 lcname = zend_str_tolower_dup(Z_STRVAL_P(name), Z_STRLEN_P(name));
7052
7053 if (((Z_STRLEN_P(name) == sizeof("self")-1) &&
7054 !memcmp(lcname, "self", sizeof("self")-1)) ||
7055 ((Z_STRLEN_P(name) == sizeof("parent")-1) &&
7056 !memcmp(lcname, "parent", sizeof("parent")-1))) {
7057 zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' is a special class name", Z_STRVAL_P(ns), Z_STRVAL_P(name), Z_STRVAL_P(name));
7058 }
7059
7060 if (CG(current_namespace)) {
7061 /* Prefix import name with current namespace name to avoid conflicts with classes */
7062 char *c_ns_name = emalloc(Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) + 1);
7063
7064 zend_str_tolower_copy(c_ns_name, Z_STRVAL_P(CG(current_namespace)), Z_STRLEN_P(CG(current_namespace)));
7065 c_ns_name[Z_STRLEN_P(CG(current_namespace))] = '\\';
7066 memcpy(c_ns_name+Z_STRLEN_P(CG(current_namespace))+1, lcname, Z_STRLEN_P(name)+1);
7067 if (zend_hash_exists(CG(class_table), c_ns_name, Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name)+1)) {
7068 char *tmp2 = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
7069
7070 if (Z_STRLEN_P(ns) != Z_STRLEN_P(CG(current_namespace)) + 1 + Z_STRLEN_P(name) ||
7071 memcmp(tmp2, c_ns_name, Z_STRLEN_P(ns))) {
7072 zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name));
7073 }
7074 efree(tmp2);
7075 }
7076 efree(c_ns_name);
7077 } else if (zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void**)&pce) == SUCCESS &&
7078 (*pce)->type == ZEND_USER_CLASS &&
7079 (*pce)->info.user.filename == CG(compiled_filename)) {
7080 char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
7081
7082 if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) ||
7083 memcmp(c_tmp, lcname, Z_STRLEN_P(ns))) {
7084 zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name));
7085 }
7086 efree(c_tmp);
7087 }
7088
7089 if (zend_hash_add(CG(current_import), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) {
7090 zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name));
7091 }
7092 if (warn) {
7093 if (!strcmp(Z_STRVAL_P(name), "strict")) {
7094 zend_error(E_COMPILE_ERROR, "You seem to be trying to use a different language...");
7095 }
7096 zend_error(E_WARNING, "The use statement with non-compound name '%s' has no effect", Z_STRVAL_P(name));
7097 }
7098 efree(lcname);
7099 zval_dtor(name);
7100 }
7101 /* }}} */
7102
zend_do_declare_constant(znode * name,znode * value TSRMLS_DC)7103 void zend_do_declare_constant(znode *name, znode *value TSRMLS_DC) /* {{{ */
7104 {
7105 zend_op *opline;
7106
7107 if(Z_TYPE(value->u.constant) == IS_CONSTANT_ARRAY) {
7108 zend_error(E_COMPILE_ERROR, "Arrays are not allowed as constants");
7109 }
7110
7111 if (zend_get_ct_const(&name->u.constant, 0 TSRMLS_CC)) {
7112 zend_error(E_COMPILE_ERROR, "Cannot redeclare constant '%s'", Z_STRVAL(name->u.constant));
7113 }
7114
7115 if (CG(current_namespace)) {
7116 /* Prefix constant name with name of current namespace, lowercased */
7117 znode tmp;
7118
7119 tmp.op_type = IS_CONST;
7120 tmp.u.constant = *CG(current_namespace);
7121 Z_STRVAL(tmp.u.constant) = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), Z_STRLEN(tmp.u.constant));
7122 zend_do_build_namespace_name(&tmp, &tmp, name TSRMLS_CC);
7123 *name = tmp;
7124 }
7125
7126 opline = get_next_op(CG(active_op_array) TSRMLS_CC);
7127 opline->opcode = ZEND_DECLARE_CONST;
7128 SET_UNUSED(opline->result);
7129 SET_NODE(opline->op1, name);
7130 SET_NODE(opline->op2, value);
7131 }
7132 /* }}} */
7133
zend_verify_namespace(TSRMLS_D)7134 void zend_verify_namespace(TSRMLS_D) /* {{{ */
7135 {
7136 if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
7137 zend_error(E_COMPILE_ERROR, "No code may exist outside of namespace {}");
7138 }
7139 }
7140 /* }}} */
7141
zend_do_end_namespace(TSRMLS_D)7142 void zend_do_end_namespace(TSRMLS_D) /* {{{ */
7143 {
7144 CG(in_namespace) = 0;
7145 if (CG(current_namespace)) {
7146 zval_dtor(CG(current_namespace));
7147 FREE_ZVAL(CG(current_namespace));
7148 CG(current_namespace) = NULL;
7149 }
7150 if (CG(current_import)) {
7151 zend_hash_destroy(CG(current_import));
7152 efree(CG(current_import));
7153 CG(current_import) = NULL;
7154 }
7155 }
7156 /* }}} */
7157
zend_do_end_compilation(TSRMLS_D)7158 void zend_do_end_compilation(TSRMLS_D) /* {{{ */
7159 {
7160 CG(has_bracketed_namespaces) = 0;
7161 zend_do_end_namespace(TSRMLS_C);
7162 }
7163 /* }}} */
7164
7165 /* {{{ zend_dirname
7166 Returns directory name component of path */
zend_dirname(char * path,size_t len)7167 ZEND_API size_t zend_dirname(char *path, size_t len)
7168 {
7169 register char *end = path + len - 1;
7170 unsigned int len_adjust = 0;
7171
7172 #ifdef PHP_WIN32
7173 /* Note that on Win32 CWD is per drive (heritage from CP/M).
7174 * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
7175 */
7176 if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
7177 /* Skip over the drive spec (if any) so as not to change */
7178 path += 2;
7179 len_adjust += 2;
7180 if (2 == len) {
7181 /* Return "c:" on Win32 for dirname("c:").
7182 * It would be more consistent to return "c:."
7183 * but that would require making the string *longer*.
7184 */
7185 return len;
7186 }
7187 }
7188 #elif defined(NETWARE)
7189 /*
7190 * Find the first occurrence of : from the left
7191 * move the path pointer to the position just after :
7192 * increment the len_adjust to the length of path till colon character(inclusive)
7193 * If there is no character beyond : simple return len
7194 */
7195 char *colonpos = NULL;
7196 colonpos = strchr(path, ':');
7197 if (colonpos != NULL) {
7198 len_adjust = ((colonpos - path) + 1);
7199 path += len_adjust;
7200 if (len_adjust == len) {
7201 return len;
7202 }
7203 }
7204 #endif
7205
7206 if (len == 0) {
7207 /* Illegal use of this function */
7208 return 0;
7209 }
7210
7211 /* Strip trailing slashes */
7212 while (end >= path && IS_SLASH_P(end)) {
7213 end--;
7214 }
7215 if (end < path) {
7216 /* The path only contained slashes */
7217 path[0] = DEFAULT_SLASH;
7218 path[1] = '\0';
7219 return 1 + len_adjust;
7220 }
7221
7222 /* Strip filename */
7223 while (end >= path && !IS_SLASH_P(end)) {
7224 end--;
7225 }
7226 if (end < path) {
7227 /* No slash found, therefore return '.' */
7228 #ifdef NETWARE
7229 if (len_adjust == 0) {
7230 path[0] = '.';
7231 path[1] = '\0';
7232 return 1; /* only one character */
7233 } else {
7234 path[0] = '\0';
7235 return len_adjust;
7236 }
7237 #else
7238 path[0] = '.';
7239 path[1] = '\0';
7240 return 1 + len_adjust;
7241 #endif
7242 }
7243
7244 /* Strip slashes which came before the file name */
7245 while (end >= path && IS_SLASH_P(end)) {
7246 end--;
7247 }
7248 if (end < path) {
7249 path[0] = DEFAULT_SLASH;
7250 path[1] = '\0';
7251 return 1 + len_adjust;
7252 }
7253 *(end+1) = '\0';
7254
7255 return (size_t)(end + 1 - path) + len_adjust;
7256 }
7257 /* }}} */
7258
7259 /*
7260 * Local variables:
7261 * tab-width: 4
7262 * c-basic-offset: 4
7263 * indent-tabs-mode: t
7264 * End:
7265 */
7266