xref: /PHP-5.4/Zend/zend_compile.c (revision 0a3979e0)
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 = &current_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), &current_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