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