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