xref: /PHP-7.4/ext/opcache/Optimizer/sccp.c (revision 3f4bc94b)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine, SCCP - Sparse Conditional Constant Propagation          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Nikita Popov <nikic@php.net>                                |
16    |          Dmitry Stogov <dmitry@php.net>                              |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "php.h"
21 #include "zend_type_info.h"
22 #include "ZendAccelerator.h"
23 #include "Optimizer/zend_optimizer_internal.h"
24 #include "Optimizer/zend_call_graph.h"
25 #include "Optimizer/zend_inference.h"
26 #include "Optimizer/scdf.h"
27 #include "Optimizer/zend_dump.h"
28 #include "ext/standard/php_string.h"
29 
30 /* This implements sparse conditional constant propagation (SCCP) based on the SCDF framework. The
31  * used value lattice is defined as follows:
32  *
33  * BOT < {constant values} < TOP
34  *
35  * TOP indicates an underdefined value, i.e. that we do not yet know the value of variable.
36  * BOT indicates an overdefined value, i.e. that we know the variable to be non-constant.
37  *
38  * All variables are optimistically initialized to TOP, apart from the implicit variables defined
39  * at the start of the first block. Note that variables that MAY_BE_REF are *not* initialized to
40  * BOT. We rely on the fact that any operation resulting in a reference will produce a BOT anyway.
41  * This is better because such operations might never be reached due to the conditional nature of
42  * the algorithm.
43  *
44  * The meet operation for phi functions is defined as follows:
45  * BOT + any = BOT
46  * TOP + any = any
47  * C_i + C_i = C_i (i.e. two equal constants)
48  * C_i + C_j = BOT (i.e. two different constants)
49  *
50  * When evaluating instructions TOP and BOT are handled as follows:
51  * a) If any operand is BOT, the result is BOT. The main exception to this is op1 of ASSIGN, which
52  *    is ignored. However, if the op1 MAY_BE_REF we do have to propagate the BOT.
53  * b) Otherwise, if the instruction can never be evaluated (either in general, or with the
54  *    specific modifiers) the result is BOT.
55  * c) Otherwise, if any operand is TOP, the result is TOP.
56  * d) Otherwise (at this point all operands are known and constant), if we can compute the result
57  *    for these specific constants (without throwing notices or similar) then that is the result.
58  * e) Otherwise the result is BOT.
59  *
60  * It is sometimes possible to determine a result even if one argument is TOP / BOT, e.g. for things
61  * like BOT*0. Right now we don't bother with this -- the only thing that is done is evaluating
62  * TYPE_CHECKS based on the type information.
63  *
64  * Feasible successors for conditional branches are determined as follows:
65  * a) If we don't support the branch type or branch on BOT, all successors are feasible.
66  * b) Otherwise, if we branch on TOP none of the successors are feasible.
67  * c) Otherwise (we branch on a constant), the feasible successors are marked based on the constant
68  *    (usually only one successor will be feasible).
69  *
70  * The original SCCP algorithm is extended with ability to propagate constant array
71  * elements and object properties. The extension is based on a variation of Array
72  * SSA form and its application to Spare Constant Propagation, described at
73  * "Array SSA Form" by Vivek Sarkar, Kathleen Knobe and Stephen Fink in chapter
74  * 16 of the SSA book.
75  */
76 
77 #define SCP_DEBUG 0
78 
79 typedef struct _sccp_ctx {
80 	scdf_ctx scdf;
81 	zend_call_info **call_map;
82 	zval *values;
83 	zval top;
84 	zval bot;
85 } sccp_ctx;
86 
87 #define TOP ((zend_uchar)-1)
88 #define BOT ((zend_uchar)-2)
89 #define PARTIAL_ARRAY ((zend_uchar)-3)
90 #define PARTIAL_OBJECT ((zend_uchar)-4)
91 #define IS_TOP(zv) (Z_TYPE_P(zv) == TOP)
92 #define IS_BOT(zv) (Z_TYPE_P(zv) == BOT)
93 #define IS_PARTIAL_ARRAY(zv) (Z_TYPE_P(zv) == PARTIAL_ARRAY)
94 #define IS_PARTIAL_OBJECT(zv) (Z_TYPE_P(zv) == PARTIAL_OBJECT)
95 
96 #define MAKE_PARTIAL_ARRAY(zv) (Z_TYPE_INFO_P(zv) = PARTIAL_ARRAY | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT))
97 #define MAKE_PARTIAL_OBJECT(zv) (Z_TYPE_INFO_P(zv) = PARTIAL_OBJECT | (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT))
98 
99 #define MAKE_TOP(zv) (Z_TYPE_INFO_P(zv) = TOP)
100 #define MAKE_BOT(zv) (Z_TYPE_INFO_P(zv) = BOT)
101 
scp_dump_value(zval * zv)102 static void scp_dump_value(zval *zv) {
103 	if (IS_TOP(zv)) {
104 		fprintf(stderr, " top");
105 	} else if (IS_BOT(zv)) {
106 		fprintf(stderr, " bot");
107 	} else if (Z_TYPE_P(zv) == IS_ARRAY || IS_PARTIAL_ARRAY(zv)) {
108 		fprintf(stderr, " %s[", IS_PARTIAL_ARRAY(zv) ? "partial " : "");
109 		zend_dump_ht(Z_ARRVAL_P(zv));
110 		fprintf(stderr, "]");
111 	} else if (IS_PARTIAL_OBJECT(zv)) {
112 		fprintf(stderr, " {");
113 		zend_dump_ht(Z_ARRVAL_P(zv));
114 		fprintf(stderr, "}");
115 	} else {
116 		zend_dump_const(zv);
117 	}
118 }
119 
empty_partial_array(zval * zv)120 static void empty_partial_array(zval *zv)
121 {
122 	MAKE_PARTIAL_ARRAY(zv);
123 	Z_ARR_P(zv) = zend_new_array(8);
124 }
125 
dup_partial_array(zval * dst,zval * src)126 static void dup_partial_array(zval *dst, zval *src)
127 {
128 	MAKE_PARTIAL_ARRAY(dst);
129 	Z_ARR_P(dst) = zend_array_dup(Z_ARR_P(src));
130 }
131 
empty_partial_object(zval * zv)132 static void empty_partial_object(zval *zv)
133 {
134 	MAKE_PARTIAL_OBJECT(zv);
135 	Z_ARR_P(zv) = zend_new_array(8);
136 }
137 
dup_partial_object(zval * dst,zval * src)138 static void dup_partial_object(zval *dst, zval *src)
139 {
140 	MAKE_PARTIAL_OBJECT(dst);
141 	Z_ARR_P(dst) = zend_array_dup(Z_ARR_P(src));
142 }
143 
value_known(zval * zv)144 static inline zend_bool value_known(zval *zv) {
145 	return !IS_TOP(zv) && !IS_BOT(zv);
146 }
147 
148 /* Sets new value for variable and ensures that it is lower or equal
149  * the previous one in the constant propagation lattice. */
set_value(scdf_ctx * scdf,sccp_ctx * ctx,int var,zval * new)150 static void set_value(scdf_ctx *scdf, sccp_ctx *ctx, int var, zval *new) {
151 	zval *value = &ctx->values[var];
152 	if (IS_BOT(value) || IS_TOP(new)) {
153 		return;
154 	}
155 
156 #if SCP_DEBUG
157 	fprintf(stderr, "Lowering #%d.", var);
158 	zend_dump_var(scdf->op_array, IS_CV, scdf->ssa->vars[var].var);
159 	fprintf(stderr, " from");
160 	scp_dump_value(value);
161 	fprintf(stderr, " to");
162 	scp_dump_value(new);
163 	fprintf(stderr, "\n");
164 #endif
165 
166 	if (IS_TOP(value) || IS_BOT(new)) {
167 		zval_ptr_dtor_nogc(value);
168 		ZVAL_COPY(value, new);
169 		scdf_add_to_worklist(scdf, var);
170 		return;
171 	}
172 
173 	/* Always replace PARTIAL_(ARRAY|OBJECT), as new maybe changed by join_partial_(arrays|object) */
174 	if (IS_PARTIAL_ARRAY(new) || IS_PARTIAL_OBJECT(new)) {
175 		if (Z_TYPE_P(value) != Z_TYPE_P(new)
176 			|| zend_hash_num_elements(Z_ARR_P(new)) != zend_hash_num_elements(Z_ARR_P(value))) {
177 			zval_ptr_dtor_nogc(value);
178 			ZVAL_COPY(value, new);
179 			scdf_add_to_worklist(scdf, var);
180 		}
181 		return;
182 	}
183 
184 #if ZEND_DEBUG
185 	ZEND_ASSERT(zend_is_identical(value, new));
186 #endif
187 }
188 
get_op1_value(sccp_ctx * ctx,zend_op * opline,zend_ssa_op * ssa_op)189 static zval *get_op1_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
190 	if (opline->op1_type == IS_CONST) {
191 		return CT_CONSTANT_EX(ctx->scdf.op_array, opline->op1.constant);
192 	} else if (ssa_op->op1_use != -1) {
193 		return &ctx->values[ssa_op->op1_use];
194 	} else {
195 		return NULL;
196 	}
197 }
198 
get_op2_value(sccp_ctx * ctx,zend_op * opline,zend_ssa_op * ssa_op)199 static zval *get_op2_value(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op) {
200 	if (opline->op2_type == IS_CONST) {
201 		return CT_CONSTANT_EX(ctx->scdf.op_array, opline->op2.constant);
202 	} else if (ssa_op->op2_use != -1) {
203 		return &ctx->values[ssa_op->op2_use];
204 	} else {
205 		return NULL;
206 	}
207 }
208 
can_replace_op1(const zend_op_array * op_array,zend_op * opline,zend_ssa_op * ssa_op)209 static zend_bool can_replace_op1(
210 		const zend_op_array *op_array, zend_op *opline, zend_ssa_op *ssa_op) {
211 	switch (opline->opcode) {
212 		case ZEND_PRE_INC:
213 		case ZEND_PRE_DEC:
214 		case ZEND_PRE_INC_OBJ:
215 		case ZEND_PRE_DEC_OBJ:
216 		case ZEND_POST_INC:
217 		case ZEND_POST_DEC:
218 		case ZEND_POST_INC_OBJ:
219 		case ZEND_POST_DEC_OBJ:
220 		case ZEND_ASSIGN:
221 		case ZEND_ASSIGN_REF:
222 		case ZEND_ASSIGN_DIM:
223 		case ZEND_ASSIGN_OBJ:
224 		case ZEND_ASSIGN_OBJ_REF:
225 		case ZEND_ASSIGN_OP:
226 		case ZEND_ASSIGN_DIM_OP:
227 		case ZEND_ASSIGN_OBJ_OP:
228 		case ZEND_ASSIGN_STATIC_PROP_OP:
229 		case ZEND_FETCH_DIM_W:
230 		case ZEND_FETCH_DIM_RW:
231 		case ZEND_FETCH_DIM_UNSET:
232 		case ZEND_FETCH_DIM_FUNC_ARG:
233 		case ZEND_FETCH_OBJ_W:
234 		case ZEND_FETCH_OBJ_RW:
235 		case ZEND_FETCH_OBJ_UNSET:
236 		case ZEND_FETCH_OBJ_FUNC_ARG:
237 		case ZEND_FETCH_LIST_W:
238 		case ZEND_UNSET_DIM:
239 		case ZEND_UNSET_OBJ:
240 		case ZEND_SEND_REF:
241 		case ZEND_SEND_VAR_EX:
242 		case ZEND_SEND_FUNC_ARG:
243 		case ZEND_SEND_UNPACK:
244 		case ZEND_SEND_ARRAY:
245 		case ZEND_SEND_USER:
246 		case ZEND_FE_RESET_RW:
247 			return 0;
248 		/* Do not accept CONST */
249 		case ZEND_ROPE_ADD:
250 		case ZEND_ROPE_END:
251 		case ZEND_BIND_STATIC:
252 		case ZEND_BIND_GLOBAL:
253 		case ZEND_MAKE_REF:
254 		case ZEND_UNSET_CV:
255 		case ZEND_ISSET_ISEMPTY_CV:
256 			return 0;
257 		case ZEND_INIT_ARRAY:
258 		case ZEND_ADD_ARRAY_ELEMENT:
259 			return !(opline->extended_value & ZEND_ARRAY_ELEMENT_REF);
260 		case ZEND_YIELD:
261 			return !(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE);
262 		case ZEND_VERIFY_RETURN_TYPE:
263 			// TODO: This would require a non-local change ???
264 			return 0;
265 		case ZEND_OP_DATA:
266 			return (opline - 1)->opcode != ZEND_ASSIGN_OBJ_REF &&
267 				(opline - 1)->opcode != ZEND_ASSIGN_STATIC_PROP_REF;
268 		default:
269 			if (ssa_op->op1_def != -1) {
270 				ZEND_ASSERT(0);
271 				return 0;
272 			}
273 	}
274 
275 	return 1;
276 }
277 
can_replace_op2(const zend_op_array * op_array,zend_op * opline,zend_ssa_op * ssa_op)278 static zend_bool can_replace_op2(
279 		const zend_op_array *op_array, zend_op *opline, zend_ssa_op *ssa_op) {
280 	switch (opline->opcode) {
281 		/* Do not accept CONST */
282 		case ZEND_DECLARE_CLASS_DELAYED:
283 		case ZEND_BIND_LEXICAL:
284 		case ZEND_FE_FETCH_R:
285 		case ZEND_FE_FETCH_RW:
286 			return 0;
287 	}
288 	return 1;
289 }
290 
try_replace_op1(sccp_ctx * ctx,zend_op * opline,zend_ssa_op * ssa_op,int var,zval * value)291 static zend_bool try_replace_op1(
292 		sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op, int var, zval *value) {
293 	if (ssa_op->op1_use == var && can_replace_op1(ctx->scdf.op_array, opline, ssa_op)) {
294 		zval zv;
295 		ZVAL_COPY(&zv, value);
296 		if (zend_optimizer_update_op1_const(ctx->scdf.op_array, opline, &zv)) {
297 			return 1;
298 		} else {
299 			// TODO: check the following special cases ???
300 			switch (opline->opcode) {
301 				case ZEND_CASE:
302 					opline->opcode = ZEND_IS_EQUAL;
303 					/* break missing intentionally */
304 				case ZEND_FETCH_LIST_R:
305 				case ZEND_SWITCH_STRING:
306 				case ZEND_SWITCH_LONG:
307 					if (Z_TYPE(zv) == IS_STRING) {
308 						zend_string_hash_val(Z_STR(zv));
309 					}
310 					opline->op1.constant = zend_optimizer_add_literal(ctx->scdf.op_array, &zv);
311 					opline->op1_type = IS_CONST;
312 					return 1;
313 				case ZEND_INSTANCEOF:
314 					zval_ptr_dtor_nogc(&zv);
315 					ZVAL_FALSE(&zv);
316 					opline->opcode = ZEND_QM_ASSIGN;
317 					opline->op1_type = IS_CONST;
318 					opline->op1.constant = zend_optimizer_add_literal(ctx->scdf.op_array, &zv);
319 					opline->op2_type = IS_UNUSED;
320 					if (ssa_op->op2_use >= 0) {
321 						ZEND_ASSERT(ssa_op->op2_def == -1);
322 						zend_ssa_unlink_use_chain(ctx->scdf.ssa, ssa_op - ctx->scdf.ssa->ops, ssa_op->op2_use);
323 						ssa_op->op2_use = -1;
324 						ssa_op->op2_use_chain = -1;
325 					}
326 					return 1;
327 				default:
328 					break;
329 			}
330 			zval_ptr_dtor_nogc(&zv);
331 		}
332 	}
333 	return 0;
334 }
335 
try_replace_op2(sccp_ctx * ctx,zend_op * opline,zend_ssa_op * ssa_op,int var,zval * value)336 static zend_bool try_replace_op2(
337 		sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op, int var, zval *value) {
338 	if (ssa_op->op2_use == var && can_replace_op2(ctx->scdf.op_array, opline, ssa_op)) {
339 		zval zv;
340 		ZVAL_COPY(&zv, value);
341 		if (zend_optimizer_update_op2_const(ctx->scdf.op_array, opline, &zv)) {
342 			return 1;
343 		} else {
344 			switch (opline->opcode) {
345 				case ZEND_FETCH_CLASS:
346 					if (Z_TYPE(zv) == IS_STRING) {
347 						ZEND_ASSERT((opline + 1)->opcode == ZEND_INSTANCEOF);
348 						ZEND_ASSERT(ssa_op->result_def == (ssa_op + 1)->op2_use);
349 						if (zend_optimizer_update_op2_const(ctx->scdf.op_array, opline + 1, &zv)) {
350 							zend_ssa_op *next_op = ssa_op + 1;
351 							zend_ssa_unlink_use_chain(ctx->scdf.ssa, next_op - ctx->scdf.ssa->ops, next_op->op2_use);
352 							next_op->op2_use = -1;
353 							next_op->op2_use_chain = -1;
354 							zend_ssa_remove_result_def(ctx->scdf.ssa, ssa_op);
355 							MAKE_NOP(opline);
356 							return 1;
357 						}
358 					}
359 				default:
360 					break;
361 			}
362 			zval_ptr_dtor_nogc(&zv);
363 		}
364 	}
365 	return 0;
366 }
367 
ct_eval_binary_op(zval * result,zend_uchar binop,zval * op1,zval * op2)368 static inline int ct_eval_binary_op(zval *result, zend_uchar binop, zval *op1, zval *op2) {
369 	/* TODO: We could implement support for evaluation of + on partial arrays. */
370 	if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_ARRAY(op2)) {
371 		return FAILURE;
372 	}
373 
374 	return zend_optimizer_eval_binary_op(result, binop, op1, op2);
375 }
376 
ct_eval_bool_cast(zval * result,zval * op)377 static inline int ct_eval_bool_cast(zval *result, zval *op) {
378 	if (IS_PARTIAL_ARRAY(op)) {
379 		if (zend_hash_num_elements(Z_ARRVAL_P(op)) == 0) {
380 			/* An empty partial array may be non-empty at runtime, we don't know whether the
381 			 * result will be true or false. */
382 			return FAILURE;
383 		}
384 
385 		ZVAL_TRUE(result);
386 		return SUCCESS;
387 	}
388 
389 	ZVAL_BOOL(result, zend_is_true(op));
390 	return SUCCESS;
391 }
392 
zval_to_string_offset(zend_long * result,zval * op)393 static inline int zval_to_string_offset(zend_long *result, zval *op) {
394 	switch (Z_TYPE_P(op)) {
395 		case IS_LONG:
396 			*result = Z_LVAL_P(op);
397 			return SUCCESS;
398 		case IS_STRING:
399 			if (IS_LONG == is_numeric_string(
400 					Z_STRVAL_P(op), Z_STRLEN_P(op), result, NULL, 0)) {
401 				return SUCCESS;
402 			}
403 			return FAILURE;
404 		default:
405 			return FAILURE;
406 	}
407 }
408 
fetch_array_elem(zval ** result,zval * op1,zval * op2)409 static inline int fetch_array_elem(zval **result, zval *op1, zval *op2) {
410 	switch (Z_TYPE_P(op2)) {
411 		case IS_NULL:
412 			*result = zend_hash_find(Z_ARR_P(op1), ZSTR_EMPTY_ALLOC());
413 			return SUCCESS;
414 		case IS_FALSE:
415 			*result = zend_hash_index_find(Z_ARR_P(op1), 0);
416 			return SUCCESS;
417 		case IS_TRUE:
418 			*result = zend_hash_index_find(Z_ARR_P(op1), 1);
419 			return SUCCESS;
420 		case IS_LONG:
421 			*result = zend_hash_index_find(Z_ARR_P(op1), Z_LVAL_P(op2));
422 			return SUCCESS;
423 		case IS_DOUBLE:
424 			*result = zend_hash_index_find(Z_ARR_P(op1), zend_dval_to_lval(Z_DVAL_P(op2)));
425 			return SUCCESS;
426 		case IS_STRING:
427 			*result = zend_symtable_find(Z_ARR_P(op1), Z_STR_P(op2));
428 			return SUCCESS;
429 		default:
430 			return FAILURE;
431 	}
432 }
433 
ct_eval_fetch_dim(zval * result,zval * op1,zval * op2,int support_strings)434 static inline int ct_eval_fetch_dim(zval *result, zval *op1, zval *op2, int support_strings) {
435 	if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) {
436 		zval *value;
437 		if (fetch_array_elem(&value, op1, op2) == SUCCESS && value && !IS_BOT(value)) {
438 			ZVAL_COPY(result, value);
439 			return SUCCESS;
440 		}
441 	} else if (support_strings && Z_TYPE_P(op1) == IS_STRING) {
442 		zend_long index;
443 		if (zval_to_string_offset(&index, op2) == FAILURE) {
444 			return FAILURE;
445 		}
446 		if (index >= 0 && index < Z_STRLEN_P(op1)) {
447 			ZVAL_STR(result, zend_string_init(&Z_STRVAL_P(op1)[index], 1, 0));
448 			return SUCCESS;
449 		}
450 	}
451 	return FAILURE;
452 }
453 
454 /* op1 may be NULL here to indicate an unset value */
ct_eval_isset_isempty(zval * result,uint32_t extended_value,zval * op1)455 static inline int ct_eval_isset_isempty(zval *result, uint32_t extended_value, zval *op1) {
456 	zval zv;
457 	if (!(extended_value & ZEND_ISEMPTY)) {
458 		ZVAL_BOOL(result, op1 && Z_TYPE_P(op1) != IS_NULL);
459 		return SUCCESS;
460 	} else if (!op1) {
461 		ZVAL_TRUE(result);
462 		return SUCCESS;
463 	} else if (ct_eval_bool_cast(&zv, op1) == SUCCESS) {
464 		ZVAL_BOOL(result, Z_TYPE(zv) == IS_FALSE);
465 		return SUCCESS;
466 	} else {
467 		return FAILURE;
468 	}
469 }
470 
ct_eval_isset_dim(zval * result,uint32_t extended_value,zval * op1,zval * op2)471 static inline int ct_eval_isset_dim(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
472 	if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) {
473 		zval *value;
474 		if (fetch_array_elem(&value, op1, op2) == FAILURE) {
475 			return FAILURE;
476 		}
477 		if (IS_PARTIAL_ARRAY(op1) && (!value || IS_BOT(value))) {
478 			return FAILURE;
479 		}
480 		return ct_eval_isset_isempty(result, extended_value, value);
481 	} else if (Z_TYPE_P(op1) == IS_STRING) {
482 		// TODO
483 		return FAILURE;
484 	} else {
485 		ZVAL_BOOL(result, (extended_value & ZEND_ISEMPTY));
486 		return SUCCESS;
487 	}
488 }
489 
ct_eval_del_array_elem(zval * result,zval * key)490 static inline int ct_eval_del_array_elem(zval *result, zval *key) {
491 	ZEND_ASSERT(IS_PARTIAL_ARRAY(result));
492 
493 	switch (Z_TYPE_P(key)) {
494 		case IS_NULL:
495 			zend_hash_del(Z_ARR_P(result), ZSTR_EMPTY_ALLOC());
496 			break;
497 		case IS_FALSE:
498 			zend_hash_index_del(Z_ARR_P(result), 0);
499 			break;
500 		case IS_TRUE:
501 			zend_hash_index_del(Z_ARR_P(result), 1);
502 			break;
503 		case IS_LONG:
504 			zend_hash_index_del(Z_ARR_P(result), Z_LVAL_P(key));
505 			break;
506 		case IS_DOUBLE:
507 			zend_hash_index_del(Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)));
508 			break;
509 		case IS_STRING:
510 			zend_symtable_del(Z_ARR_P(result), Z_STR_P(key));
511 			break;
512 		default:
513 			return FAILURE;
514 	}
515 
516 	return SUCCESS;
517 }
518 
ct_eval_add_array_elem(zval * result,zval * value,zval * key)519 static inline int ct_eval_add_array_elem(zval *result, zval *value, zval *key) {
520 	if (!key) {
521 		SEPARATE_ARRAY(result);
522 		if ((value = zend_hash_next_index_insert(Z_ARR_P(result), value))) {
523 			Z_TRY_ADDREF_P(value);
524 			return SUCCESS;
525 		}
526 		return FAILURE;
527 	}
528 
529 	switch (Z_TYPE_P(key)) {
530 		case IS_NULL:
531 			SEPARATE_ARRAY(result);
532 			value = zend_hash_update(Z_ARR_P(result), ZSTR_EMPTY_ALLOC(), value);
533 			break;
534 		case IS_FALSE:
535 			SEPARATE_ARRAY(result);
536 			value = zend_hash_index_update(Z_ARR_P(result), 0, value);
537 			break;
538 		case IS_TRUE:
539 			SEPARATE_ARRAY(result);
540 			value = zend_hash_index_update(Z_ARR_P(result), 1, value);
541 			break;
542 		case IS_LONG:
543 			SEPARATE_ARRAY(result);
544 			value = zend_hash_index_update(Z_ARR_P(result), Z_LVAL_P(key), value);
545 			break;
546 		case IS_DOUBLE:
547 			SEPARATE_ARRAY(result);
548 			value = zend_hash_index_update(
549 				Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)), value);
550 			break;
551 		case IS_STRING:
552 			SEPARATE_ARRAY(result);
553 			value = zend_symtable_update(Z_ARR_P(result), Z_STR_P(key), value);
554 			break;
555 		default:
556 			return FAILURE;
557 	}
558 
559 	Z_TRY_ADDREF_P(value);
560 	return SUCCESS;
561 }
562 
ct_eval_add_array_unpack(zval * result,zval * array)563 static inline int ct_eval_add_array_unpack(zval *result, zval *array) {
564 	zend_string *key;
565 	zval *value;
566 	if (Z_TYPE_P(array) != IS_ARRAY) {
567 		return FAILURE;
568 	}
569 
570 	SEPARATE_ARRAY(result);
571 	ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(array), key, value) {
572 		if (key) {
573 			return FAILURE;
574 		}
575 		value = zend_hash_next_index_insert(Z_ARR_P(result), value);
576 		if (!value) {
577 			return FAILURE;
578 		}
579 		Z_TRY_ADDREF_P(value);
580 	} ZEND_HASH_FOREACH_END();
581 	return SUCCESS;
582 }
583 
ct_eval_assign_dim(zval * result,zval * value,zval * key)584 static inline int ct_eval_assign_dim(zval *result, zval *value, zval *key) {
585 	switch (Z_TYPE_P(result)) {
586 		case IS_NULL:
587 		case IS_FALSE:
588 			array_init(result);
589 			/* break missing intentionally */
590 		case IS_ARRAY:
591 		case PARTIAL_ARRAY:
592 			return ct_eval_add_array_elem(result, value, key);
593 		case IS_STRING:
594 			// TODO Before enabling this case, make sure ARRAY_DIM result op is correct
595 #if 0
596 			zend_long index;
597 			zend_string *new_str, *value_str;
598 			if (!key || Z_TYPE_P(value) == IS_ARRAY
599 					|| zval_to_string_offset(&index, key) == FAILURE || index < 0) {
600 				return FAILURE;
601 			}
602 
603 			if (index >= Z_STRLEN_P(result)) {
604 				new_str = zend_string_alloc(index + 1, 0);
605 				memcpy(ZSTR_VAL(new_str), Z_STRVAL_P(result), Z_STRLEN_P(result));
606 				memset(ZSTR_VAL(new_str) + Z_STRLEN_P(result), ' ', index - Z_STRLEN_P(result));
607 				ZSTR_VAL(new_str)[index + 1] = 0;
608 			} else {
609 				new_str = zend_string_init(Z_STRVAL_P(result), Z_STRLEN_P(result), 0);
610 			}
611 
612 			value_str = zval_get_string(value);
613 			ZVAL_STR(result, new_str);
614 			Z_STRVAL_P(result)[index] = ZSTR_VAL(value_str)[0];
615 			zend_string_release_ex(value_str, 0);
616 #endif
617 			return FAILURE;
618 		default:
619 			return FAILURE;
620 	}
621 }
622 
fetch_obj_prop(zval ** result,zval * op1,zval * op2)623 static inline int fetch_obj_prop(zval **result, zval *op1, zval *op2) {
624 	switch (Z_TYPE_P(op2)) {
625 		case IS_STRING:
626 			*result = zend_symtable_find(Z_ARR_P(op1), Z_STR_P(op2));
627 			return SUCCESS;
628 		default:
629 			return FAILURE;
630 	}
631 }
632 
ct_eval_fetch_obj(zval * result,zval * op1,zval * op2)633 static inline int ct_eval_fetch_obj(zval *result, zval *op1, zval *op2) {
634 	if (IS_PARTIAL_OBJECT(op1)) {
635 		zval *value;
636 		if (fetch_obj_prop(&value, op1, op2) == SUCCESS && value && !IS_BOT(value)) {
637 			ZVAL_COPY(result, value);
638 			return SUCCESS;
639 		}
640 	}
641 	return FAILURE;
642 }
643 
ct_eval_isset_obj(zval * result,uint32_t extended_value,zval * op1,zval * op2)644 static inline int ct_eval_isset_obj(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
645 	if (IS_PARTIAL_OBJECT(op1)) {
646 		zval *value;
647 		if (fetch_obj_prop(&value, op1, op2) == FAILURE) {
648 			return FAILURE;
649 		}
650 		if (!value || IS_BOT(value)) {
651 			return FAILURE;
652 		}
653 		return ct_eval_isset_isempty(result, extended_value, value);
654 	} else {
655 		ZVAL_BOOL(result, (extended_value & ZEND_ISEMPTY));
656 		return SUCCESS;
657 	}
658 }
659 
ct_eval_del_obj_prop(zval * result,zval * key)660 static inline int ct_eval_del_obj_prop(zval *result, zval *key) {
661 	ZEND_ASSERT(IS_PARTIAL_OBJECT(result));
662 
663 	switch (Z_TYPE_P(key)) {
664 		case IS_STRING:
665 			zend_symtable_del(Z_ARR_P(result), Z_STR_P(key));
666 			break;
667 		default:
668 			return FAILURE;
669 	}
670 
671 	return SUCCESS;
672 }
673 
ct_eval_add_obj_prop(zval * result,zval * value,zval * key)674 static inline int ct_eval_add_obj_prop(zval *result, zval *value, zval *key) {
675 	switch (Z_TYPE_P(key)) {
676 		case IS_STRING:
677 			value = zend_symtable_update(Z_ARR_P(result), Z_STR_P(key), value);
678 			break;
679 		default:
680 			return FAILURE;
681 	}
682 
683 	Z_TRY_ADDREF_P(value);
684 	return SUCCESS;
685 }
686 
ct_eval_assign_obj(zval * result,zval * value,zval * key)687 static inline int ct_eval_assign_obj(zval *result, zval *value, zval *key) {
688 	switch (Z_TYPE_P(result)) {
689 		case IS_NULL:
690 		case IS_FALSE:
691 			empty_partial_object(result);
692 			/* break missing intentionally */
693 		case PARTIAL_OBJECT:
694 			return ct_eval_add_obj_prop(result, value, key);
695 		default:
696 			return FAILURE;
697 	}
698 }
699 
ct_eval_incdec(zval * result,zend_uchar opcode,zval * op1)700 static inline int ct_eval_incdec(zval *result, zend_uchar opcode, zval *op1) {
701 	ZVAL_COPY(result, op1);
702 	if (opcode == ZEND_PRE_INC
703 			|| opcode == ZEND_POST_INC
704 			|| opcode == ZEND_PRE_INC_OBJ
705 			|| opcode == ZEND_POST_INC_OBJ) {
706 		increment_function(result);
707 	} else {
708 		decrement_function(result);
709 	}
710 	return SUCCESS;
711 }
712 
ct_eval_type_check(zval * result,uint32_t type_mask,zval * op1)713 static inline void ct_eval_type_check(zval *result, uint32_t type_mask, zval *op1) {
714 	uint32_t type = Z_TYPE_P(op1);
715 	if (type == PARTIAL_ARRAY) {
716 		type = IS_ARRAY;
717 	} else if (type == PARTIAL_OBJECT) {
718 		type = IS_OBJECT;
719 	}
720 	ZVAL_BOOL(result, (type_mask >> type) & 1);
721 }
722 
ct_eval_in_array(zval * result,uint32_t extended_value,zval * op1,zval * op2)723 static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
724 	HashTable *ht;
725 	zend_bool res;
726 
727 	if (Z_TYPE_P(op2) != IS_ARRAY) {
728 		return FAILURE;
729 	}
730 	ht = Z_ARRVAL_P(op2);
731 	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
732 		res = zend_hash_exists(ht, Z_STR_P(op1));
733 	} else if (extended_value) {
734 		if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
735 			res = zend_hash_index_exists(ht, Z_LVAL_P(op1));
736 		} else {
737 			res = 0;
738 		}
739 	} else if (Z_TYPE_P(op1) <= IS_FALSE) {
740 		res = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
741 	} else {
742 		zend_string *key;
743 		zval key_tmp, result_tmp;
744 
745 		res = 0;
746 		ZEND_HASH_FOREACH_STR_KEY(ht, key) {
747 			ZVAL_STR(&key_tmp, key);
748 			compare_function(&result_tmp, op1, &key_tmp);
749 			if (Z_LVAL(result_tmp) == 0) {
750 				res = 1;
751 				break;
752 			}
753 		} ZEND_HASH_FOREACH_END();
754 	}
755 	ZVAL_BOOL(result, res);
756 	return SUCCESS;
757 }
758 
ct_eval_array_key_exists(zval * result,zval * op1,zval * op2)759 static inline int ct_eval_array_key_exists(zval *result, zval *op1, zval *op2) {
760 	zval *value;
761 
762 	if (Z_TYPE_P(op2) != IS_ARRAY && !IS_PARTIAL_ARRAY(op2)) {
763 		return FAILURE;
764 	}
765 	if (Z_TYPE_P(op1) != IS_STRING && Z_TYPE_P(op1) != IS_LONG && Z_TYPE_P(op1) != IS_NULL) {
766 		return FAILURE;
767 	}
768 	if (fetch_array_elem(&value, op2, op1) == FAILURE) {
769 		return FAILURE;
770 	}
771 	if (IS_PARTIAL_ARRAY(op2) && (!value || IS_BOT(value))) {
772 		return FAILURE;
773 	}
774 
775 	ZVAL_BOOL(result, value != NULL);
776 	return SUCCESS;
777 }
778 
779 /* The functions chosen here are simple to implement and either likely to affect a branch,
780  * or just happened to be commonly used with constant operands in WP (need to test other
781  * applications as well, of course). */
ct_eval_func_call(zval * result,zend_string * name,uint32_t num_args,zval ** args)782 static inline int ct_eval_func_call(
783 		zval *result, zend_string *name, uint32_t num_args, zval **args) {
784 	uint32_t i;
785 	zend_execute_data *execute_data, *prev_execute_data;
786 	zend_function *func;
787 	int overflow;
788 
789 	if (num_args == 0) {
790 		if (zend_string_equals_literal(name, "get_magic_quotes_gpc")
791 				|| zend_string_equals_literal(name, "get_magic_quotes_gpc_runtime")
792 				|| zend_string_equals_literal(name, "php_sapi_name")
793 				|| zend_string_equals_literal(name, "imagetypes")
794 				|| zend_string_equals_literal(name, "phpversion")) {
795 			/* pass */
796 		} else {
797 			return FAILURE;
798 		}
799 	} else if (num_args == 1) {
800 		if (zend_string_equals_literal(name, "chr")) {
801 			zend_long c;
802 			if (Z_TYPE_P(args[0]) != IS_LONG) {
803 				return FAILURE;
804 			}
805 
806 			c = Z_LVAL_P(args[0]) & 0xff;
807 			ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
808 			return SUCCESS;
809 		} else if (zend_string_equals_literal(name, "count")) {
810 			if (Z_TYPE_P(args[0]) != IS_ARRAY) {
811 				return FAILURE;
812 			}
813 
814 			ZVAL_LONG(result, zend_hash_num_elements(Z_ARRVAL_P(args[0])));
815 			return SUCCESS;
816 		} else if (zend_string_equals_literal(name, "ini_get")) {
817 			zend_ini_entry *ini_entry;
818 
819 			if (Z_TYPE_P(args[0]) != IS_STRING) {
820 				return FAILURE;
821 			}
822 
823 			ini_entry = zend_hash_find_ptr(EG(ini_directives), Z_STR_P(args[0]));
824 			if (!ini_entry) {
825 				ZVAL_FALSE(result);
826 			} else if (ini_entry->modifiable != ZEND_INI_SYSTEM) {
827 				return FAILURE;
828 			} else if (ini_entry->value) {
829 				ZVAL_STR_COPY(result, ini_entry->value);
830 			} else {
831 				ZVAL_EMPTY_STRING(result);
832 			}
833 			return SUCCESS;
834 		} else if (zend_string_equals_literal(name, "trim")
835 				|| zend_string_equals_literal(name, "rtrim")
836 				|| zend_string_equals_literal(name, "ltrim")
837 				|| zend_string_equals_literal(name, "str_split")
838 				|| zend_string_equals_literal(name, "preg_quote")
839 				|| zend_string_equals_literal(name, "base64_encode")
840 				|| zend_string_equals_literal(name, "base64_decode")
841 				|| zend_string_equals_literal(name, "urlencode")
842 				|| zend_string_equals_literal(name, "urldecode")
843 				|| zend_string_equals_literal(name, "rawurlencode")
844 				|| zend_string_equals_literal(name, "rawurldecode")
845 				|| zend_string_equals_literal(name, "php_uname")) {
846 			if (Z_TYPE_P(args[0]) != IS_STRING) {
847 				return FAILURE;
848 			}
849 			/* pass */
850 		} else if (zend_string_equals_literal(name, "array_keys")
851 				|| zend_string_equals_literal(name, "array_values")) {
852 			if (Z_TYPE_P(args[0]) != IS_ARRAY) {
853 				return FAILURE;
854 			}
855 			/* pass */
856 		} else if (zend_string_equals_literal(name, "array_flip")) {
857 			zval *entry;
858 
859 			if (Z_TYPE_P(args[0]) != IS_ARRAY) {
860 				return FAILURE;
861 			}
862 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
863 				if (Z_TYPE_P(entry) != IS_LONG && Z_TYPE_P(entry) != IS_STRING) {
864 					return FAILURE;
865 				}
866 			} ZEND_HASH_FOREACH_END();
867 			/* pass */
868 		} else if (zend_string_equals_literal(name, "implode")) {
869 			zval *entry;
870 
871 			if (Z_TYPE_P(args[0]) != IS_ARRAY) {
872 				return FAILURE;
873 			}
874 
875 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
876 				if (Z_TYPE_P(entry) > IS_STRING) {
877 					return FAILURE;
878 				}
879 			} ZEND_HASH_FOREACH_END();
880 			/* pass */
881 		} else if (zend_string_equals_literal(name, "serialize")) {
882 			/* pass */
883 		} else {
884 			return FAILURE;
885 		}
886 	} else if (num_args == 2) {
887 		if (zend_string_equals_literal(name, "in_array")) {
888 			if (Z_TYPE_P(args[1]) != IS_ARRAY) {
889 				return FAILURE;
890 			}
891 			/* pass */
892 		} else if (zend_string_equals_literal(name, "strpos")) {
893 			if (Z_TYPE_P(args[0]) != IS_STRING
894 					|| Z_TYPE_P(args[1]) != IS_STRING
895 					|| !Z_STRLEN_P(args[1])
896 					|| (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
897 				return FAILURE;
898 			}
899 			/* pass */
900 		} else if (zend_string_equals_literal(name, "str_split")) {
901 			if (Z_TYPE_P(args[0]) != IS_STRING
902 					|| Z_TYPE_P(args[1]) != IS_LONG
903 					|| Z_LVAL_P(args[1]) <= 0) {
904 				return FAILURE;
905 			}
906 			/* pass */
907 		} else if (zend_string_equals_literal(name, "array_key_exists")) {
908 			if (Z_TYPE_P(args[1]) != IS_ARRAY
909 					|| (Z_TYPE_P(args[0]) != IS_LONG
910 						&& Z_TYPE_P(args[0]) != IS_STRING
911 						&& Z_TYPE_P(args[0]) != IS_NULL)) {
912 				return FAILURE;
913 			}
914 			/* pass */
915 		} else if (zend_string_equals_literal(name, "trim")
916 				|| zend_string_equals_literal(name, "rtrim")
917 				|| zend_string_equals_literal(name, "ltrim")
918 				|| zend_string_equals_literal(name, "preg_quote")) {
919 			if (Z_TYPE_P(args[0]) != IS_STRING
920 					|| Z_TYPE_P(args[1]) != IS_STRING) {
921 				return FAILURE;
922 			}
923 			/* pass */
924 		} else if (zend_string_equals_literal(name, "str_repeat")) {
925 			if (Z_TYPE_P(args[0]) != IS_STRING
926 					|| Z_TYPE_P(args[1]) != IS_LONG
927 					|| zend_safe_address(Z_STRLEN_P(args[0]), Z_LVAL_P(args[1]), 0, &overflow) > 64 * 1024
928 					|| overflow) {
929 				return FAILURE;
930 			}
931 			/* pass */
932 		} else if (zend_string_equals_literal(name, "array_merge")
933 				|| zend_string_equals_literal(name, "array_replace")
934 				|| zend_string_equals_literal(name, "array_merge_recursive")
935 				|| zend_string_equals_literal(name, "array_replace_recursive")
936 				|| zend_string_equals_literal(name, "array_diff")
937 				|| zend_string_equals_literal(name, "array_diff_assoc")
938 				|| zend_string_equals_literal(name, "array_diff_key")) {
939 			for (i = 0; i < num_args; i++) {
940 				if (Z_TYPE_P(args[i]) != IS_ARRAY) {
941 					return FAILURE;
942 				}
943 			}
944 			/* pass */
945 		} else if (zend_string_equals_literal(name, "implode")) {
946 			zval *entry;
947 
948 			if ((Z_TYPE_P(args[0]) != IS_STRING || Z_TYPE_P(args[1]) != IS_ARRAY)
949 					&& (Z_TYPE_P(args[0]) != IS_ARRAY || Z_TYPE_P(args[1]) != IS_STRING)) {
950 				return FAILURE;
951 			}
952 
953 			if (Z_TYPE_P(args[0]) == IS_ARRAY) {
954 				ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[0]), entry) {
955 					if (Z_TYPE_P(entry) > IS_STRING) {
956 						return FAILURE;
957 					}
958 				} ZEND_HASH_FOREACH_END();
959 			} else {
960 				ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args[1]), entry) {
961 					if (Z_TYPE_P(entry) > IS_STRING) {
962 						return FAILURE;
963 					}
964 				} ZEND_HASH_FOREACH_END();
965 			}
966 			/* pass */
967 		} else if (zend_string_equals_literal(name, "version_compare")) {
968 			if (Z_TYPE_P(args[0]) != IS_STRING
969 					|| Z_TYPE_P(args[1]) != IS_STRING) {
970 				return FAILURE;
971 			}
972 			/* pass */
973 		} else if (zend_string_equals_literal(name, "substr")) {
974 			if (Z_TYPE_P(args[0]) != IS_STRING
975 					|| Z_TYPE_P(args[1]) != IS_LONG
976 					|| (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
977 				return FAILURE;
978 			}
979 			/* pass */
980 		} else if (zend_string_equals_literal(name, "pow")) {
981 			if ((Z_TYPE_P(args[0]) != IS_LONG && Z_TYPE_P(args[0]) != IS_DOUBLE)
982 					|| (Z_TYPE_P(args[1]) != IS_LONG && Z_TYPE_P(args[1]) != IS_DOUBLE)) {
983 				return FAILURE;
984 			}
985 			/* pass */
986 		} else {
987 			return FAILURE;
988 		}
989 	} else if (num_args == 3) {
990 		if (zend_string_equals_literal(name, "in_array")) {
991 			if (Z_TYPE_P(args[1]) != IS_ARRAY
992 				|| (Z_TYPE_P(args[2]) != IS_FALSE
993 					&& Z_TYPE_P(args[2]) != IS_TRUE)) {
994 				return FAILURE;
995 			}
996 			/* pass */
997 		} else if (zend_string_equals_literal(name, "array_merge")
998 				|| zend_string_equals_literal(name, "array_replace")
999 				|| zend_string_equals_literal(name, "array_merge_recursive")
1000 				|| zend_string_equals_literal(name, "array_replace_recursive")
1001 				|| zend_string_equals_literal(name, "array_diff")
1002 				|| zend_string_equals_literal(name, "array_diff_assoc")
1003 				|| zend_string_equals_literal(name, "array_diff_key")) {
1004 			for (i = 0; i < num_args; i++) {
1005 				if (Z_TYPE_P(args[i]) != IS_ARRAY) {
1006 					return FAILURE;
1007 				}
1008 			}
1009 			/* pass */
1010 		} else if (zend_string_equals_literal(name, "version_compare")) {
1011 			if (Z_TYPE_P(args[0]) != IS_STRING
1012 					|| Z_TYPE_P(args[1]) != IS_STRING
1013 					|| Z_TYPE_P(args[2]) != IS_STRING) {
1014 				return FAILURE;
1015 			}
1016 			/* pass */
1017 		} else if (zend_string_equals_literal(name, "substr")) {
1018 			if (Z_TYPE_P(args[0]) != IS_STRING
1019 					|| Z_TYPE_P(args[1]) != IS_LONG
1020 					|| Z_TYPE_P(args[2]) != IS_LONG
1021 					|| (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
1022 				return FAILURE;
1023 			}
1024 			/* pass */
1025 		} else {
1026 			return FAILURE;
1027 		}
1028 	} else {
1029 		return FAILURE;
1030 	}
1031 
1032 	func = zend_hash_find_ptr(CG(function_table), name);
1033 	if (!func || func->type != ZEND_INTERNAL_FUNCTION
1034 			|| func->internal_function.handler == ZEND_FN(display_disabled_function)) {
1035 		return FAILURE;
1036 	}
1037 
1038 	execute_data = safe_emalloc(num_args, sizeof(zval), ZEND_CALL_FRAME_SLOT * sizeof(zval));
1039 	memset(execute_data, 0, sizeof(zend_execute_data));
1040 	prev_execute_data = EG(current_execute_data);
1041 	EG(current_execute_data) = execute_data;
1042 
1043 	EX(func) = func;
1044 	EX_NUM_ARGS() = num_args;
1045 	for (i = 0; i < num_args; i++) {
1046 		ZVAL_COPY(EX_VAR_NUM(i), args[i]);
1047 	}
1048 	func->internal_function.handler(execute_data, result);
1049 	for (i = 0; i < num_args; i++) {
1050 		zval_ptr_dtor_nogc(EX_VAR_NUM(i));
1051 	}
1052 	efree(execute_data);
1053 	EG(current_execute_data) = prev_execute_data;
1054 	return SUCCESS;
1055 }
1056 
1057 #define SET_RESULT(op, zv) do { \
1058 	if (ssa_op->op##_def >= 0) { \
1059 		set_value(scdf, ctx, ssa_op->op##_def, zv); \
1060 	} \
1061 } while (0)
1062 #define SET_RESULT_BOT(op) SET_RESULT(op, &ctx->bot)
1063 #define SET_RESULT_TOP(op) SET_RESULT(op, &ctx->top)
1064 
1065 #define SKIP_IF_TOP(op) if (IS_TOP(op)) return;
1066 
sccp_visit_instr(scdf_ctx * scdf,zend_op * opline,zend_ssa_op * ssa_op)1067 static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_op) {
1068 	sccp_ctx *ctx = (sccp_ctx *) scdf;
1069 	zval *op1, *op2, zv; /* zv is a temporary to hold result values */
1070 
1071 	op1 = get_op1_value(ctx, opline, ssa_op);
1072 	op2 = get_op2_value(ctx, opline, ssa_op);
1073 
1074 	switch (opline->opcode) {
1075 		case ZEND_ASSIGN:
1076 			/* The value of op1 is irrelevant here, because we are overwriting it
1077 			 * -- unless it can be a reference, in which case we propagate a BOT. */
1078 			if (IS_BOT(op1) && (ctx->scdf.ssa->var_info[ssa_op->op1_use].type & MAY_BE_REF)) {
1079 				SET_RESULT_BOT(op1);
1080 			} else {
1081 				SET_RESULT(op1, op2);
1082 			}
1083 
1084 			SET_RESULT(result, op2);
1085 			return;
1086 		case ZEND_TYPE_CHECK:
1087 			/* We may be able to evaluate TYPE_CHECK based on type inference info,
1088 			 * even if we don't know the precise value. */
1089 			if (!value_known(op1)) {
1090 				uint32_t type = ctx->scdf.ssa->var_info[ssa_op->op1_use].type;
1091 				uint32_t expected_type_mask = opline->extended_value;
1092 				if (!(type & expected_type_mask) && !(type & MAY_BE_UNDEF)) {
1093 					ZVAL_FALSE(&zv);
1094 					SET_RESULT(result, &zv);
1095 					return;
1096 				} else if (!(type & ((MAY_BE_ANY|MAY_BE_UNDEF) - expected_type_mask))
1097 						   && !(expected_type_mask & MAY_BE_RESOURCE)) {
1098 					ZVAL_TRUE(&zv);
1099 					SET_RESULT(result, &zv);
1100 					return;
1101 				}
1102 			}
1103 			break;
1104 		case ZEND_ASSIGN_DIM:
1105 		{
1106 			zval *data = get_op1_value(ctx, opline+1, ssa_op+1);
1107 
1108 			/* If $a in $a[$b]=$c is UNDEF, treat it like NULL. There is no warning. */
1109 			if ((ctx->scdf.ssa->var_info[ssa_op->op1_use].type & MAY_BE_ANY) == 0) {
1110 				op1 = &EG(uninitialized_zval);
1111 			}
1112 
1113 			if (IS_BOT(op1)) {
1114 				SET_RESULT_BOT(result);
1115 				SET_RESULT_BOT(op1);
1116 				return;
1117 			}
1118 
1119 			SKIP_IF_TOP(op1);
1120 			SKIP_IF_TOP(data);
1121 			if (op2) {
1122 				SKIP_IF_TOP(op2);
1123 			}
1124 
1125 			if (op2 && IS_BOT(op2)) {
1126 				/* Update of unknown index */
1127 				SET_RESULT_BOT(result);
1128 				if (ssa_op->op1_def >= 0) {
1129 					empty_partial_array(&zv);
1130 					SET_RESULT(op1, &zv);
1131 					zval_ptr_dtor_nogc(&zv);
1132 				} else {
1133 					SET_RESULT_BOT(op1);
1134 				}
1135 				return;
1136 			}
1137 
1138 			if (IS_BOT(data)) {
1139 
1140 				SET_RESULT_BOT(result);
1141 				if ((IS_PARTIAL_ARRAY(op1)
1142 						|| Z_TYPE_P(op1) == IS_NULL
1143 						|| Z_TYPE_P(op1) == IS_FALSE
1144 						|| Z_TYPE_P(op1) == IS_ARRAY)
1145 					&& ssa_op->op1_def >= 0) {
1146 
1147 					if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1148 						empty_partial_array(&zv);
1149 					} else {
1150 						dup_partial_array(&zv, op1);
1151 					}
1152 
1153 					if (!op2) {
1154 						/* We can't add NEXT element into partial array (skip it) */
1155 						SET_RESULT(op1, &zv);
1156 					} else if (ct_eval_del_array_elem(&zv, op2) == SUCCESS) {
1157 						SET_RESULT(op1, &zv);
1158 					} else {
1159 						SET_RESULT_BOT(op1);
1160 					}
1161 
1162 					zval_ptr_dtor_nogc(&zv);
1163 				} else {
1164 					SET_RESULT_BOT(op1);
1165 				}
1166 
1167 			} else {
1168 
1169 				if (IS_PARTIAL_ARRAY(op1)) {
1170 					dup_partial_array(&zv, op1);
1171 				} else {
1172 					ZVAL_COPY(&zv, op1);
1173 				}
1174 
1175 				if (!op2 && IS_PARTIAL_ARRAY(&zv)) {
1176 					/* We can't add NEXT element into partial array (skip it) */
1177 					SET_RESULT(result, data);
1178 					SET_RESULT(op1, &zv);
1179 				} else if (ct_eval_assign_dim(&zv, data, op2) == SUCCESS) {
1180 					/* Mark array containing partial array as partial */
1181 					if (IS_PARTIAL_ARRAY(data)) {
1182 						MAKE_PARTIAL_ARRAY(&zv);
1183 					}
1184 					SET_RESULT(result, data);
1185 					SET_RESULT(op1, &zv);
1186 				} else {
1187 					SET_RESULT_BOT(result);
1188 					SET_RESULT_BOT(op1);
1189 				}
1190 
1191 				zval_ptr_dtor_nogc(&zv);
1192 			}
1193 			return;
1194 		}
1195 
1196 		case ZEND_ASSIGN_OBJ:
1197 			if (ssa_op->op1_def >= 0
1198 					&& ctx->scdf.ssa->vars[ssa_op->op1_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
1199 				zval *data = get_op1_value(ctx, opline+1, ssa_op+1);
1200 				zend_ssa_var_info *var_info = &ctx->scdf.ssa->var_info[ssa_op->op1_use];
1201 
1202 				/* Don't try to propagate assignments to (potentially) typed properties. We would
1203 				 * need to deal with errors and type conversions first. */
1204 				if (!var_info->ce || (var_info->ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
1205 					SET_RESULT_BOT(result);
1206 					SET_RESULT_BOT(op1);
1207 					return;
1208 				}
1209 
1210 				/* If $a in $a->foo=$c is UNDEF, treat it like NULL. There is no warning. */
1211 				if ((var_info->type & MAY_BE_ANY) == 0) {
1212 					op1 = &EG(uninitialized_zval);
1213 				}
1214 
1215 				if (IS_BOT(op1)) {
1216 					SET_RESULT_BOT(result);
1217 					SET_RESULT_BOT(op1);
1218 					return;
1219 				}
1220 
1221 				SKIP_IF_TOP(op1);
1222 				SKIP_IF_TOP(data);
1223 				SKIP_IF_TOP(op2);
1224 
1225 				if (IS_BOT(op2)) {
1226 					/* Update of unknown property */
1227 					SET_RESULT_BOT(result);
1228 					empty_partial_object(&zv);
1229 					SET_RESULT(op1, &zv);
1230 					zval_ptr_dtor_nogc(&zv);
1231 					return;
1232 				}
1233 
1234 				if (IS_BOT(data)) {
1235 					SET_RESULT_BOT(result);
1236 					if (IS_PARTIAL_OBJECT(op1)
1237 							|| Z_TYPE_P(op1) == IS_NULL
1238 							|| Z_TYPE_P(op1) == IS_FALSE) {
1239 
1240 						if (Z_TYPE_P(op1) == IS_NULL || Z_TYPE_P(op1) == IS_FALSE) {
1241 							empty_partial_object(&zv);
1242 						} else {
1243 							dup_partial_object(&zv, op1);
1244 						}
1245 
1246 						if (ct_eval_del_obj_prop(&zv, op2) == SUCCESS) {
1247 							SET_RESULT(op1, &zv);
1248 						} else {
1249 							SET_RESULT_BOT(op1);
1250 						}
1251 						zval_ptr_dtor_nogc(&zv);
1252 					} else {
1253 						SET_RESULT_BOT(op1);
1254 					}
1255 
1256 				} else {
1257 
1258 					if (IS_PARTIAL_OBJECT(op1)) {
1259 						dup_partial_object(&zv, op1);
1260 					} else {
1261 						ZVAL_COPY(&zv, op1);
1262 					}
1263 
1264 					if (ct_eval_assign_obj(&zv, data, op2) == SUCCESS) {
1265 						SET_RESULT(result, data);
1266 						SET_RESULT(op1, &zv);
1267 					} else {
1268 						SET_RESULT_BOT(result);
1269 						SET_RESULT_BOT(op1);
1270 					}
1271 
1272 					zval_ptr_dtor_nogc(&zv);
1273 				}
1274 			} else {
1275 				SET_RESULT_BOT(result);
1276 				SET_RESULT_BOT(op1);
1277 			}
1278 			return;
1279 
1280 		case ZEND_SEND_VAL:
1281 		case ZEND_SEND_VAR:
1282 		{
1283 			/* If the value of a SEND for an ICALL changes, we need to reconsider the
1284 			 * ICALL result value. Otherwise we can ignore the opcode. */
1285 			zend_call_info *call;
1286 			if (!ctx->call_map) {
1287 				return;
1288 			}
1289 
1290 			call = ctx->call_map[opline - ctx->scdf.op_array->opcodes];
1291 			if (IS_TOP(op1) || !call || !call->caller_call_opline
1292 					|| call->caller_call_opline->opcode != ZEND_DO_ICALL) {
1293 				return;
1294 			}
1295 
1296 			opline = call->caller_call_opline;
1297 			ssa_op = &ctx->scdf.ssa->ops[opline - ctx->scdf.op_array->opcodes];
1298 			break;
1299 		}
1300 		case ZEND_INIT_ARRAY:
1301 		case ZEND_ADD_ARRAY_ELEMENT:
1302 		{
1303 			zval *result = NULL;
1304 
1305 			if (opline->opcode == ZEND_ADD_ARRAY_ELEMENT) {
1306 				result = &ctx->values[ssa_op->result_use];
1307 				if (IS_BOT(result)) {
1308 					SET_RESULT_BOT(result);
1309 					SET_RESULT_BOT(op1);
1310 					return;
1311 				}
1312 				SKIP_IF_TOP(result);
1313 			}
1314 
1315 			if (op1) {
1316 				SKIP_IF_TOP(op1);
1317 			}
1318 
1319 			if (op2) {
1320 				SKIP_IF_TOP(op2);
1321 			}
1322 
1323 			/* We want to avoid keeping around intermediate arrays for each SSA variable in the
1324 			 * ADD_ARRAY_ELEMENT chain. We do this by only keeping the array on the last opcode
1325 			 * and use a NULL value everywhere else. */
1326 			if (result && Z_TYPE_P(result) == IS_NULL) {
1327 				SET_RESULT_BOT(result);
1328 				return;
1329 			}
1330 
1331 			if (op2 && IS_BOT(op2)) {
1332 				/* Update of unknown index */
1333 				SET_RESULT_BOT(op1);
1334 				if (ssa_op->result_def >= 0) {
1335 					empty_partial_array(&zv);
1336 					SET_RESULT(result, &zv);
1337 					zval_ptr_dtor_nogc(&zv);
1338 				} else {
1339 					SET_RESULT_BOT(result);
1340 				}
1341 				return;
1342 			}
1343 
1344 			if ((op1 && IS_BOT(op1))
1345 					|| (opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
1346 
1347 				SET_RESULT_BOT(op1);
1348 				if (ssa_op->result_def >= 0) {
1349 					if (!result) {
1350 						empty_partial_array(&zv);
1351 					} else {
1352 						MAKE_PARTIAL_ARRAY(result);
1353 						ZVAL_COPY_VALUE(&zv, result);
1354 						ZVAL_NULL(result);
1355 					}
1356 					if (!op2) {
1357 						/* We can't add NEXT element into partial array (skip it) */
1358 						SET_RESULT(result, &zv);
1359 					} else if (ct_eval_del_array_elem(&zv, op2) == SUCCESS) {
1360 						SET_RESULT(result, &zv);
1361 					} else {
1362 						SET_RESULT_BOT(result);
1363 					}
1364 					zval_ptr_dtor_nogc(&zv);
1365 				} else {
1366 					/* If any operand is BOT, mark the result as BOT right away.
1367 					 * Exceptions to this rule are handled above. */
1368 					SET_RESULT_BOT(result);
1369 				}
1370 
1371 			} else {
1372 				if (result) {
1373 					ZVAL_COPY_VALUE(&zv, result);
1374 					ZVAL_NULL(result);
1375 				} else {
1376 					array_init(&zv);
1377 				}
1378 
1379 				if (op1) {
1380 					if (!op2 && IS_PARTIAL_ARRAY(&zv)) {
1381 						/* We can't add NEXT element into partial array (skip it) */
1382 						SET_RESULT(result, &zv);
1383 					} else if (ct_eval_add_array_elem(&zv, op1, op2) == SUCCESS) {
1384 						if (IS_PARTIAL_ARRAY(op1)) {
1385 							MAKE_PARTIAL_ARRAY(&zv);
1386 						}
1387 						SET_RESULT(result, &zv);
1388 					} else {
1389 						SET_RESULT_BOT(result);
1390 					}
1391 				} else {
1392 					SET_RESULT(result, &zv);
1393 				}
1394 
1395 				zval_ptr_dtor_nogc(&zv);
1396 			}
1397 			return;
1398 		}
1399 		case ZEND_ADD_ARRAY_UNPACK: {
1400 			zval *result = &ctx->values[ssa_op->result_use];
1401 			if (IS_BOT(result) || IS_BOT(op1)) {
1402 				SET_RESULT_BOT(result);
1403 				return;
1404 			}
1405 			SKIP_IF_TOP(result);
1406 			SKIP_IF_TOP(op1);
1407 
1408 			/* See comment for ADD_ARRAY_ELEMENT. */
1409 			if (Z_TYPE_P(result) == IS_NULL) {
1410 				SET_RESULT_BOT(result);
1411 				return;
1412 			}
1413 			ZVAL_COPY_VALUE(&zv, result);
1414 			ZVAL_NULL(result);
1415 
1416 			if (ct_eval_add_array_unpack(&zv, op1) == SUCCESS) {
1417 				SET_RESULT(result, &zv);
1418 			} else {
1419 				SET_RESULT_BOT(result);
1420 			}
1421 			zval_ptr_dtor_nogc(&zv);
1422 			return;
1423 		}
1424 		case ZEND_NEW:
1425 			if (ssa_op->result_def >= 0
1426 					&& ctx->scdf.ssa->vars[ssa_op->result_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
1427 				empty_partial_object(&zv);
1428 				SET_RESULT(result, &zv);
1429 				zval_ptr_dtor_nogc(&zv);
1430 			} else {
1431 				SET_RESULT_BOT(result);
1432 			}
1433 			return;
1434 		case ZEND_ASSIGN_STATIC_PROP_REF:
1435 		case ZEND_ASSIGN_OBJ_REF:
1436 			/* Handled here because we also need to BOT the OP_DATA operand, while the generic
1437 			 * code below will not do so. */
1438 			SET_RESULT_BOT(result);
1439 			SET_RESULT_BOT(op1);
1440 			SET_RESULT_BOT(op2);
1441 			opline++;
1442 			ssa_op++;
1443 			SET_RESULT_BOT(op1);
1444 			break;
1445 	}
1446 
1447 	if ((op1 && IS_BOT(op1)) || (op2 && IS_BOT(op2))) {
1448 		/* If any operand is BOT, mark the result as BOT right away.
1449 		 * Exceptions to this rule are handled above. */
1450 		SET_RESULT_BOT(result);
1451 		SET_RESULT_BOT(op1);
1452 		SET_RESULT_BOT(op2);
1453 		return;
1454 	}
1455 
1456 	switch (opline->opcode) {
1457 		case ZEND_ADD:
1458 		case ZEND_SUB:
1459 		case ZEND_MUL:
1460 		case ZEND_DIV:
1461 		case ZEND_MOD:
1462 		case ZEND_POW:
1463 		case ZEND_SL:
1464 		case ZEND_SR:
1465 		case ZEND_CONCAT:
1466 		case ZEND_FAST_CONCAT:
1467 		case ZEND_IS_EQUAL:
1468 		case ZEND_IS_NOT_EQUAL:
1469 		case ZEND_IS_SMALLER:
1470 		case ZEND_IS_SMALLER_OR_EQUAL:
1471 		case ZEND_IS_IDENTICAL:
1472 		case ZEND_IS_NOT_IDENTICAL:
1473 		case ZEND_BW_OR:
1474 		case ZEND_BW_AND:
1475 		case ZEND_BW_XOR:
1476 		case ZEND_BOOL_XOR:
1477 		case ZEND_CASE:
1478 			SKIP_IF_TOP(op1);
1479 			SKIP_IF_TOP(op2);
1480 
1481 			if (ct_eval_binary_op(&zv, opline->opcode, op1, op2) == SUCCESS) {
1482 				SET_RESULT(result, &zv);
1483 				zval_ptr_dtor_nogc(&zv);
1484 				break;
1485 			}
1486 			SET_RESULT_BOT(result);
1487 			break;
1488 		case ZEND_ASSIGN_OP:
1489 		case ZEND_ASSIGN_DIM_OP:
1490 		case ZEND_ASSIGN_OBJ_OP:
1491 		case ZEND_ASSIGN_STATIC_PROP_OP:
1492 			if (op1) {
1493 				SKIP_IF_TOP(op1);
1494 			}
1495 			if (op2) {
1496 				SKIP_IF_TOP(op2);
1497 			}
1498 			if (opline->opcode == ZEND_ASSIGN_OP) {
1499 				if (ct_eval_binary_op(&zv, opline->extended_value, op1, op2) == SUCCESS) {
1500 					SET_RESULT(op1, &zv);
1501 					SET_RESULT(result, &zv);
1502 					zval_ptr_dtor_nogc(&zv);
1503 					break;
1504 				}
1505 			} else if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
1506 				if ((IS_PARTIAL_ARRAY(op1) || Z_TYPE_P(op1) == IS_ARRAY)
1507 						&& ssa_op->op1_def >= 0 && op2) {
1508 					zval tmp;
1509 					zval *data = get_op1_value(ctx, opline+1, ssa_op+1);
1510 
1511 					SKIP_IF_TOP(data);
1512 
1513 					if (ct_eval_fetch_dim(&tmp, op1, op2, 0) == SUCCESS) {
1514 						if (IS_BOT(data)) {
1515 							dup_partial_array(&zv, op1);
1516 							ct_eval_del_array_elem(&zv, op2);
1517 							SET_RESULT_BOT(result);
1518 							SET_RESULT(op1, &zv);
1519 							zval_ptr_dtor_nogc(&tmp);
1520 							zval_ptr_dtor_nogc(&zv);
1521 							break;
1522 						}
1523 
1524 						if (ct_eval_binary_op(&tmp, opline->extended_value, &tmp, data) != SUCCESS) {
1525 							SET_RESULT_BOT(result);
1526 							SET_RESULT_BOT(op1);
1527 							zval_ptr_dtor_nogc(&tmp);
1528 							break;
1529 						}
1530 
1531 						if (IS_PARTIAL_ARRAY(op1)) {
1532 							dup_partial_array(&zv, op1);
1533 						} else {
1534 							ZVAL_COPY(&zv, op1);
1535 						}
1536 
1537 						if (ct_eval_assign_dim(&zv, &tmp, op2) == SUCCESS) {
1538 							SET_RESULT(result, &tmp);
1539 							SET_RESULT(op1, &zv);
1540 							zval_ptr_dtor_nogc(&tmp);
1541 							zval_ptr_dtor_nogc(&zv);
1542 							break;
1543 						}
1544 
1545 						zval_ptr_dtor_nogc(&tmp);
1546 						zval_ptr_dtor_nogc(&zv);
1547 					}
1548 				}
1549 			} else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1550 				if (op1 && IS_PARTIAL_OBJECT(op1)
1551 						&& ssa_op->op1_def >= 0
1552 						&& ctx->scdf.ssa->vars[ssa_op->op1_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
1553 					zval tmp;
1554 					zval *data = get_op1_value(ctx, opline+1, ssa_op+1);
1555 
1556 					SKIP_IF_TOP(data);
1557 
1558 					if (ct_eval_fetch_obj(&tmp, op1, op2) == SUCCESS) {
1559 						if (IS_BOT(data)) {
1560 							dup_partial_object(&zv, op1);
1561 							ct_eval_del_obj_prop(&zv, op2);
1562 							SET_RESULT_BOT(result);
1563 							SET_RESULT(op1, &zv);
1564 							zval_ptr_dtor_nogc(&tmp);
1565 							zval_ptr_dtor_nogc(&zv);
1566 							break;
1567 						}
1568 
1569 						if (ct_eval_binary_op(&tmp, opline->extended_value, &tmp, data) != SUCCESS) {
1570 							SET_RESULT_BOT(result);
1571 							SET_RESULT_BOT(op1);
1572 							zval_ptr_dtor_nogc(&tmp);
1573 							break;
1574 						}
1575 
1576 						dup_partial_object(&zv, op1);
1577 
1578 						if (ct_eval_assign_obj(&zv, &tmp, op2) == SUCCESS) {
1579 							SET_RESULT(result, &tmp);
1580 							SET_RESULT(op1, &zv);
1581 							zval_ptr_dtor_nogc(&tmp);
1582 							zval_ptr_dtor_nogc(&zv);
1583 							break;
1584 						}
1585 
1586 						zval_ptr_dtor_nogc(&tmp);
1587 						zval_ptr_dtor_nogc(&zv);
1588 					}
1589 				}
1590 			}
1591 			SET_RESULT_BOT(result);
1592 			SET_RESULT_BOT(op1);
1593 			break;
1594 		case ZEND_PRE_INC_OBJ:
1595 		case ZEND_PRE_DEC_OBJ:
1596 		case ZEND_POST_INC_OBJ:
1597 		case ZEND_POST_DEC_OBJ:
1598 			if (op1) {
1599 				SKIP_IF_TOP(op1);
1600 				SKIP_IF_TOP(op2);
1601 				if (IS_PARTIAL_OBJECT(op1)
1602 						&& ssa_op->op1_def >= 0
1603 						&& ctx->scdf.ssa->vars[ssa_op->op1_def].escape_state == ESCAPE_STATE_NO_ESCAPE) {
1604 					zval tmp1, tmp2;
1605 
1606 					if (ct_eval_fetch_obj(&tmp1, op1, op2) == SUCCESS
1607 							&& ct_eval_incdec(&tmp2, opline->opcode, &tmp1) == SUCCESS) {
1608 
1609 						dup_partial_object(&zv, op1);
1610 						ct_eval_assign_obj(&zv, &tmp2, op2);
1611 						if (opline->opcode == ZEND_PRE_INC_OBJ
1612 								|| opline->opcode == ZEND_PRE_DEC_OBJ) {
1613 							SET_RESULT(result, &tmp2);
1614 						} else {
1615 							SET_RESULT(result, &tmp1);
1616 						}
1617 						SET_RESULT(op1, &zv);
1618 						zval_ptr_dtor_nogc(&zv);
1619 						break;
1620 					}
1621 				}
1622 			}
1623 			SET_RESULT_BOT(op1);
1624 			SET_RESULT_BOT(result);
1625 			break;
1626 		case ZEND_PRE_INC:
1627 		case ZEND_PRE_DEC:
1628 			SKIP_IF_TOP(op1);
1629 			if (ct_eval_incdec(&zv, opline->opcode, op1) == SUCCESS) {
1630 				SET_RESULT(op1, &zv);
1631 				SET_RESULT(result, &zv);
1632 				zval_ptr_dtor_nogc(&zv);
1633 				break;
1634 			}
1635 			SET_RESULT_BOT(op1);
1636 			SET_RESULT_BOT(result);
1637 			break;
1638 		case ZEND_POST_INC:
1639 		case ZEND_POST_DEC:
1640 			SKIP_IF_TOP(op1);
1641 			SET_RESULT(result, op1);
1642 			if (ct_eval_incdec(&zv, opline->opcode, op1) == SUCCESS) {
1643 				SET_RESULT(op1, &zv);
1644 				zval_ptr_dtor_nogc(&zv);
1645 				break;
1646 			}
1647 			SET_RESULT_BOT(op1);
1648 			break;
1649 		case ZEND_BW_NOT:
1650 		case ZEND_BOOL_NOT:
1651 			SKIP_IF_TOP(op1);
1652 			if (IS_PARTIAL_ARRAY(op1)) {
1653 				SET_RESULT_BOT(result);
1654 				break;
1655 			}
1656 			if (zend_optimizer_eval_unary_op(&zv, opline->opcode, op1) == SUCCESS) {
1657 				SET_RESULT(result, &zv);
1658 				zval_ptr_dtor_nogc(&zv);
1659 				break;
1660 			}
1661 			SET_RESULT_BOT(result);
1662 			break;
1663 		case ZEND_CAST:
1664 			SKIP_IF_TOP(op1);
1665 			if (IS_PARTIAL_ARRAY(op1)) {
1666 				SET_RESULT_BOT(result);
1667 				break;
1668 			}
1669 			if (zend_optimizer_eval_cast(&zv, opline->extended_value, op1) == SUCCESS) {
1670 				SET_RESULT(result, &zv);
1671 				zval_ptr_dtor_nogc(&zv);
1672 				break;
1673 			}
1674 			SET_RESULT_BOT(result);
1675 			break;
1676 		case ZEND_BOOL:
1677 		case ZEND_JMPZ_EX:
1678 		case ZEND_JMPNZ_EX:
1679 			SKIP_IF_TOP(op1);
1680 			if (ct_eval_bool_cast(&zv, op1) == SUCCESS) {
1681 				SET_RESULT(result, &zv);
1682 				zval_ptr_dtor_nogc(&zv);
1683 				break;
1684 			}
1685 			SET_RESULT_BOT(result);
1686 			break;
1687 		case ZEND_STRLEN:
1688 			SKIP_IF_TOP(op1);
1689 			if (zend_optimizer_eval_strlen(&zv, op1) == SUCCESS) {
1690 				SET_RESULT(result, &zv);
1691 				zval_ptr_dtor_nogc(&zv);
1692 				break;
1693 			}
1694 			SET_RESULT_BOT(result);
1695 			break;
1696 		case ZEND_COUNT:
1697 			SKIP_IF_TOP(op1);
1698 			if (Z_TYPE_P(op1) == IS_ARRAY) {
1699 				ZVAL_LONG(&zv, zend_hash_num_elements(Z_ARRVAL_P(op1)));
1700 				SET_RESULT(result, &zv);
1701 				zval_ptr_dtor_nogc(&zv);
1702 				break;
1703 			}
1704 			SET_RESULT_BOT(result);
1705 			break;
1706 		case ZEND_IN_ARRAY:
1707 			SKIP_IF_TOP(op1);
1708 			SKIP_IF_TOP(op2);
1709 			if (ct_eval_in_array(&zv, opline->extended_value, op1, op2) == SUCCESS) {
1710 				SET_RESULT(result, &zv);
1711 				zval_ptr_dtor_nogc(&zv);
1712 				break;
1713 			}
1714 			SET_RESULT_BOT(result);
1715 			break;
1716 		case ZEND_ARRAY_KEY_EXISTS:
1717 			SKIP_IF_TOP(op1);
1718 			SKIP_IF_TOP(op2);
1719 			if (ct_eval_array_key_exists(&zv, op1, op2) == SUCCESS) {
1720 				SET_RESULT(result, &zv);
1721 				zval_ptr_dtor_nogc(&zv);
1722 				break;
1723 			}
1724 			SET_RESULT_BOT(result);
1725 			break;
1726 		case ZEND_FETCH_DIM_R:
1727 		case ZEND_FETCH_DIM_IS:
1728 		case ZEND_FETCH_LIST_R:
1729 			SKIP_IF_TOP(op1);
1730 			SKIP_IF_TOP(op2);
1731 
1732 			if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST_R)) == SUCCESS) {
1733 				SET_RESULT(result, &zv);
1734 				zval_ptr_dtor_nogc(&zv);
1735 				break;
1736 			}
1737 			SET_RESULT_BOT(result);
1738 			break;
1739 		case ZEND_ISSET_ISEMPTY_DIM_OBJ:
1740 			SKIP_IF_TOP(op1);
1741 			SKIP_IF_TOP(op2);
1742 
1743 			if (ct_eval_isset_dim(&zv, opline->extended_value, op1, op2) == SUCCESS) {
1744 				SET_RESULT(result, &zv);
1745 				zval_ptr_dtor_nogc(&zv);
1746 				break;
1747 			}
1748 			SET_RESULT_BOT(result);
1749 			break;
1750 		case ZEND_FETCH_OBJ_R:
1751 		case ZEND_FETCH_OBJ_IS:
1752 			if (op1) {
1753 				SKIP_IF_TOP(op1);
1754 				SKIP_IF_TOP(op2);
1755 
1756 				if (ct_eval_fetch_obj(&zv, op1, op2) == SUCCESS) {
1757 					SET_RESULT(result, &zv);
1758 					zval_ptr_dtor_nogc(&zv);
1759 					break;
1760 				}
1761 			}
1762 			SET_RESULT_BOT(result);
1763 			break;
1764 		case ZEND_ISSET_ISEMPTY_PROP_OBJ:
1765 			if (op1) {
1766 				SKIP_IF_TOP(op1);
1767 				SKIP_IF_TOP(op2);
1768 
1769 				if (ct_eval_isset_obj(&zv, opline->extended_value, op1, op2) == SUCCESS) {
1770 					SET_RESULT(result, &zv);
1771 					zval_ptr_dtor_nogc(&zv);
1772 					break;
1773 				}
1774 			}
1775 			SET_RESULT_BOT(result);
1776 			break;
1777 		case ZEND_QM_ASSIGN:
1778 		case ZEND_JMP_SET:
1779 		case ZEND_COALESCE:
1780 		case ZEND_COPY_TMP:
1781 			SET_RESULT(result, op1);
1782 			break;
1783 #if 0
1784 		case ZEND_FETCH_CLASS:
1785 			if (!op1) {
1786 				SET_RESULT_BOT(result);
1787 				break;
1788 			}
1789 			SET_RESULT(result, op1);
1790 			break;
1791 #endif
1792 		case ZEND_ISSET_ISEMPTY_CV:
1793 			SKIP_IF_TOP(op1);
1794 			if (ct_eval_isset_isempty(&zv, opline->extended_value, op1) == SUCCESS) {
1795 				SET_RESULT(result, &zv);
1796 				zval_ptr_dtor_nogc(&zv);
1797 				break;
1798 			}
1799 			SET_RESULT_BOT(result);
1800 			break;
1801 		case ZEND_TYPE_CHECK:
1802 			SKIP_IF_TOP(op1);
1803 			ct_eval_type_check(&zv, opline->extended_value, op1);
1804 			SET_RESULT(result, &zv);
1805 			zval_ptr_dtor_nogc(&zv);
1806 			break;
1807 		case ZEND_INSTANCEOF:
1808 			SKIP_IF_TOP(op1);
1809 			ZVAL_FALSE(&zv);
1810 			SET_RESULT(result, &zv);
1811 			break;
1812 		case ZEND_ROPE_INIT:
1813 			SKIP_IF_TOP(op2);
1814 			if (IS_PARTIAL_ARRAY(op2)) {
1815 				SET_RESULT_BOT(result);
1816 				break;
1817 			}
1818 			if (zend_optimizer_eval_cast(&zv, IS_STRING, op2) == SUCCESS) {
1819 				SET_RESULT(result, &zv);
1820 				zval_ptr_dtor_nogc(&zv);
1821 				break;
1822 			}
1823 			SET_RESULT_BOT(result);
1824 			break;
1825 		case ZEND_ROPE_ADD:
1826 		case ZEND_ROPE_END:
1827 			// TODO The way this is currently implemented will result in quadratic runtime
1828 			// This is not necessary, the way the algorithm works it's okay to reuse the same
1829 			// string for all SSA vars with some extra checks
1830 			SKIP_IF_TOP(op1);
1831 			SKIP_IF_TOP(op2);
1832 			if (ct_eval_binary_op(&zv, ZEND_CONCAT, op1, op2) == SUCCESS) {
1833 				SET_RESULT(result, &zv);
1834 				zval_ptr_dtor_nogc(&zv);
1835 				break;
1836 			}
1837 			SET_RESULT_BOT(result);
1838 			break;
1839 		case ZEND_DO_ICALL:
1840 		{
1841 			zend_call_info *call;
1842 			zval *name, *args[3] = {NULL};
1843 			int i;
1844 
1845 			if (!ctx->call_map) {
1846 				SET_RESULT_BOT(result);
1847 				break;
1848 			}
1849 
1850 			call = ctx->call_map[opline - ctx->scdf.op_array->opcodes];
1851 			name = CT_CONSTANT_EX(ctx->scdf.op_array, call->caller_init_opline->op2.constant);
1852 
1853 			/* We already know it can't be evaluated, don't bother checking again */
1854 			if (ssa_op->result_def < 0 || IS_BOT(&ctx->values[ssa_op->result_def])) {
1855 				break;
1856 			}
1857 
1858 			/* We're only interested in functions with up to three arguments right now */
1859 			if (call->num_args > 3) {
1860 				SET_RESULT_BOT(result);
1861 				break;
1862 			}
1863 
1864 			for (i = 0; i < call->num_args; i++) {
1865 				zend_op *opline = call->arg_info[i].opline;
1866 				if (opline->opcode != ZEND_SEND_VAL && opline->opcode != ZEND_SEND_VAR) {
1867 					SET_RESULT_BOT(result);
1868 					return;
1869 				}
1870 
1871 				args[i] = get_op1_value(ctx, opline,
1872 					&ctx->scdf.ssa->ops[opline - ctx->scdf.op_array->opcodes]);
1873 				if (args[i]) {
1874 					if (IS_BOT(args[i]) || IS_PARTIAL_ARRAY(args[i])) {
1875 						SET_RESULT_BOT(result);
1876 						return;
1877 					} else if (IS_TOP(args[i])) {
1878 						return;
1879 					}
1880 				}
1881 			}
1882 
1883 			/* We didn't get a BOT argument, so value stays the same */
1884 			if (!IS_TOP(&ctx->values[ssa_op->result_def])) {
1885 				break;
1886 			}
1887 
1888 			if (ct_eval_func_call(&zv, Z_STR_P(name), call->num_args, args) == SUCCESS) {
1889 				SET_RESULT(result, &zv);
1890 				zval_ptr_dtor_nogc(&zv);
1891 				break;
1892 			}
1893 
1894 #if 0
1895 			/* sort out | uniq -c | sort -n */
1896 			fprintf(stderr, "%s\n", Z_STRVAL_P(name));
1897 			/*if (args[1]) {
1898 				php_printf("%s %Z %Z\n", Z_STRVAL_P(name), args[0], args[1]);
1899 			} else {
1900 				php_printf("%s %Z\n", Z_STRVAL_P(name), args[0]);
1901 			}*/
1902 #endif
1903 
1904 			SET_RESULT_BOT(result);
1905 			break;
1906 		}
1907 		default:
1908 		{
1909 			/* If we have no explicit implementation return BOT */
1910 			SET_RESULT_BOT(result);
1911 			SET_RESULT_BOT(op1);
1912 			SET_RESULT_BOT(op2);
1913 			break;
1914 		}
1915 	}
1916 }
1917 
1918 /* Returns whether there is a successor */
sccp_mark_feasible_successors(scdf_ctx * scdf,int block_num,zend_basic_block * block,zend_op * opline,zend_ssa_op * ssa_op)1919 static void sccp_mark_feasible_successors(
1920 		scdf_ctx *scdf,
1921 		int block_num, zend_basic_block *block,
1922 		zend_op *opline, zend_ssa_op *ssa_op) {
1923 	sccp_ctx *ctx = (sccp_ctx *) scdf;
1924 	zval *op1, zv;
1925 	int s;
1926 
1927 	/* We can't determine the branch target at compile-time for these */
1928 	switch (opline->opcode) {
1929 		case ZEND_ASSERT_CHECK:
1930 		case ZEND_CATCH:
1931 		case ZEND_FE_FETCH_R:
1932 		case ZEND_FE_FETCH_RW:
1933 			scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1934 			scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1935 			return;
1936 	}
1937 
1938 	op1 = get_op1_value(ctx, opline, ssa_op);
1939 
1940 	/* Branch target can be either one */
1941 	if (!op1 || IS_BOT(op1)) {
1942 		for (s = 0; s < block->successors_count; s++) {
1943 			scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
1944 		}
1945 		return;
1946 	}
1947 
1948 	/* Branch target not yet known */
1949 	if (IS_TOP(op1)) {
1950 		return;
1951 	}
1952 
1953 	switch (opline->opcode) {
1954 		case ZEND_JMPZ:
1955 		case ZEND_JMPZNZ:
1956 		case ZEND_JMPZ_EX:
1957 		{
1958 			if (ct_eval_bool_cast(&zv, op1) == FAILURE) {
1959 				scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1960 				scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1961 				return;
1962 			}
1963 			s = Z_TYPE(zv) == IS_TRUE;
1964 			break;
1965 		}
1966 		case ZEND_JMPNZ:
1967 		case ZEND_JMPNZ_EX:
1968 		case ZEND_JMP_SET:
1969 		{
1970 			if (ct_eval_bool_cast(&zv, op1) == FAILURE) {
1971 				scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1972 				scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1973 				return;
1974 			}
1975 			s = Z_TYPE(zv) == IS_FALSE;
1976 			break;
1977 		}
1978 		case ZEND_COALESCE:
1979 			s = (Z_TYPE_P(op1) == IS_NULL);
1980 			break;
1981 		case ZEND_FE_RESET_R:
1982 		case ZEND_FE_RESET_RW:
1983 			/* A non-empty partial array is definitely non-empty, but an
1984 			 * empty partial array may be non-empty at runtime. */
1985 			if (Z_TYPE_P(op1) != IS_ARRAY ||
1986 					(IS_PARTIAL_ARRAY(op1) && zend_hash_num_elements(Z_ARR_P(op1)) == 0)) {
1987 				scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
1988 				scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
1989 				return;
1990 			}
1991 			s = zend_hash_num_elements(Z_ARR_P(op1)) != 0;
1992 			break;
1993 		case ZEND_SWITCH_LONG:
1994 			if (Z_TYPE_P(op1) == IS_LONG) {
1995 				zend_op_array *op_array = scdf->op_array;
1996 				zend_ssa *ssa = scdf->ssa;
1997 				HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
1998 				zval *jmp_zv = zend_hash_index_find(jmptable, Z_LVAL_P(op1));
1999 				int target;
2000 
2001 				if (jmp_zv) {
2002 					target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv))];
2003 				} else {
2004 					target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
2005 				}
2006 				scdf_mark_edge_feasible(scdf, block_num, target);
2007 				return;
2008 			}
2009 			s = block->successors_count - 1;
2010 			break;
2011 		case ZEND_SWITCH_STRING:
2012 			if (Z_TYPE_P(op1) == IS_STRING) {
2013 				zend_op_array *op_array = scdf->op_array;
2014 				zend_ssa *ssa = scdf->ssa;
2015 				HashTable *jmptable = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, opline->op2.constant));
2016 				zval *jmp_zv = zend_hash_find(jmptable, Z_STR_P(op1));
2017 				int target;
2018 
2019 				if (jmp_zv) {
2020 					target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(jmp_zv))];
2021 				} else {
2022 					target = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)];
2023 				}
2024 				scdf_mark_edge_feasible(scdf, block_num, target);
2025 				return;
2026 			}
2027 			s = block->successors_count - 1;
2028 			break;
2029 		default:
2030 			for (s = 0; s < block->successors_count; s++) {
2031 				scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
2032 			}
2033 			return;
2034 	}
2035 	scdf_mark_edge_feasible(scdf, block_num, block->successors[s]);
2036 }
2037 
join_hash_tables(HashTable * ret,HashTable * ht1,HashTable * ht2)2038 static void join_hash_tables(HashTable *ret, HashTable *ht1, HashTable *ht2)
2039 {
2040 	zend_ulong index;
2041 	zend_string *key;
2042 	zval *val1, *val2;
2043 
2044 	ZEND_HASH_FOREACH_KEY_VAL(ht1, index, key, val1) {
2045 		if (key) {
2046 			val2 = zend_hash_find(ht2, key);
2047 		} else {
2048 			val2 = zend_hash_index_find(ht2, index);
2049 		}
2050 		if (val2 && zend_is_identical(val1, val2)) {
2051 			if (key) {
2052 				val1 = zend_hash_add_new(ret, key, val1);
2053 			} else {
2054 				val1 = zend_hash_index_add_new(ret, index, val1);
2055 			}
2056 			Z_TRY_ADDREF_P(val1);
2057 		}
2058 	} ZEND_HASH_FOREACH_END();
2059 }
2060 
join_partial_arrays(zval * a,zval * b)2061 static int join_partial_arrays(zval *a, zval *b)
2062 {
2063 	zval ret;
2064 
2065 	if ((Z_TYPE_P(a) != IS_ARRAY && !IS_PARTIAL_ARRAY(a))
2066 			|| (Z_TYPE_P(b) != IS_ARRAY && !IS_PARTIAL_ARRAY(b))) {
2067 		return FAILURE;
2068 	}
2069 
2070 	empty_partial_array(&ret);
2071 	join_hash_tables(Z_ARRVAL(ret), Z_ARRVAL_P(a), Z_ARRVAL_P(b));
2072 	zval_ptr_dtor_nogc(a);
2073 	ZVAL_COPY_VALUE(a, &ret);
2074 
2075 	return SUCCESS;
2076 }
2077 
join_partial_objects(zval * a,zval * b)2078 static int join_partial_objects(zval *a, zval *b)
2079 {
2080 	zval ret;
2081 
2082 	if (!IS_PARTIAL_OBJECT(a) || !IS_PARTIAL_OBJECT(b)) {
2083 		return FAILURE;
2084 	}
2085 
2086 	empty_partial_object(&ret);
2087 	join_hash_tables(Z_ARRVAL(ret), Z_ARRVAL_P(a), Z_ARRVAL_P(b));
2088 	zval_ptr_dtor_nogc(a);
2089 	ZVAL_COPY_VALUE(a, &ret);
2090 
2091 	return SUCCESS;
2092 }
2093 
join_phi_values(zval * a,zval * b,zend_bool escape)2094 static void join_phi_values(zval *a, zval *b, zend_bool escape) {
2095 	if (IS_BOT(a) || IS_TOP(b)) {
2096 		return;
2097 	}
2098 	if (IS_TOP(a)) {
2099 		zval_ptr_dtor_nogc(a);
2100 		ZVAL_COPY(a, b);
2101 		return;
2102 	}
2103 	if (IS_BOT(b)) {
2104 		zval_ptr_dtor_nogc(a);
2105 		MAKE_BOT(a);
2106 		return;
2107 	}
2108 	if (IS_PARTIAL_ARRAY(a) || IS_PARTIAL_ARRAY(b)) {
2109 		if (join_partial_arrays(a, b) != SUCCESS) {
2110 			zval_ptr_dtor_nogc(a);
2111 			MAKE_BOT(a);
2112 		}
2113 	} else if (IS_PARTIAL_OBJECT(a) || IS_PARTIAL_OBJECT(b)) {
2114 		if (escape || join_partial_objects(a, b) != SUCCESS) {
2115 			zval_ptr_dtor_nogc(a);
2116 			MAKE_BOT(a);
2117 		}
2118 	} else if (!zend_is_identical(a, b)) {
2119 		if (join_partial_arrays(a, b) != SUCCESS) {
2120 			zval_ptr_dtor_nogc(a);
2121 			MAKE_BOT(a);
2122 		}
2123 	}
2124 }
2125 
sccp_visit_phi(scdf_ctx * scdf,zend_ssa_phi * phi)2126 static void sccp_visit_phi(scdf_ctx *scdf, zend_ssa_phi *phi) {
2127 	sccp_ctx *ctx = (sccp_ctx *) scdf;
2128 	zend_ssa *ssa = scdf->ssa;
2129 	ZEND_ASSERT(phi->ssa_var >= 0);
2130 	if (!IS_BOT(&ctx->values[phi->ssa_var])) {
2131 		zend_basic_block *block = &ssa->cfg.blocks[phi->block];
2132 		int *predecessors = &ssa->cfg.predecessors[block->predecessor_offset];
2133 
2134 		int i;
2135 		zval result;
2136 		MAKE_TOP(&result);
2137 #if SCP_DEBUG
2138 		fprintf(stderr, "Handling phi(");
2139 #endif
2140 		if (phi->pi >= 0) {
2141 			ZEND_ASSERT(phi->sources[0] >= 0);
2142 			if (scdf_is_edge_feasible(scdf, phi->pi, phi->block)) {
2143 				join_phi_values(&result, &ctx->values[phi->sources[0]], ssa->vars[phi->ssa_var].escape_state != ESCAPE_STATE_NO_ESCAPE);
2144 			}
2145 		} else {
2146 			for (i = 0; i < block->predecessors_count; i++) {
2147 				ZEND_ASSERT(phi->sources[i] >= 0);
2148 				if (scdf_is_edge_feasible(scdf, predecessors[i], phi->block)) {
2149 #if SCP_DEBUG
2150 					scp_dump_value(&ctx->values[phi->sources[i]]);
2151 					fprintf(stderr, ",");
2152 #endif
2153 					join_phi_values(&result, &ctx->values[phi->sources[i]], ssa->vars[phi->ssa_var].escape_state != ESCAPE_STATE_NO_ESCAPE);
2154 				} else {
2155 #if SCP_DEBUG
2156 					fprintf(stderr, " --,");
2157 #endif
2158 				}
2159 			}
2160 		}
2161 #if SCP_DEBUG
2162 		fprintf(stderr, ")\n");
2163 #endif
2164 
2165 		set_value(scdf, ctx, phi->ssa_var, &result);
2166 		zval_ptr_dtor_nogc(&result);
2167 	}
2168 }
2169 
value_from_type_and_range(sccp_ctx * ctx,int var_num,zval * tmp)2170 static zval *value_from_type_and_range(sccp_ctx *ctx, int var_num, zval *tmp) {
2171 	zend_ssa *ssa = ctx->scdf.ssa;
2172 	zend_ssa_var_info *info = &ssa->var_info[var_num];
2173 
2174 	if (ssa->vars[var_num].var >= ctx->scdf.op_array->last_var) {
2175 		// TODO Non-CVs may cause issues with FREEs
2176 		return NULL;
2177 	}
2178 
2179 	if (info->type & MAY_BE_UNDEF) {
2180 		return NULL;
2181 	}
2182 
2183 	if (!(info->type & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_NULL))) {
2184 		ZVAL_NULL(tmp);
2185 		return tmp;
2186 	}
2187 	if (!(info->type & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_FALSE))) {
2188 		ZVAL_FALSE(tmp);
2189 		return tmp;
2190 	}
2191 	if (!(info->type & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_TRUE))) {
2192 		ZVAL_TRUE(tmp);
2193 		return tmp;
2194 	}
2195 
2196 #if 0
2197 	/* Disabled due to bug #81096. */
2198 	if (!(info->type & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
2199 			&& info->has_range
2200 			&& !info->range.overflow && !info->range.underflow
2201 			&& info->range.min == info->range.max) {
2202 		ZVAL_LONG(tmp, info->range.min);
2203 		return tmp;
2204 	}
2205 #endif
2206 
2207 	return NULL;
2208 }
2209 
2210 /* Call instruction -> remove opcodes that are part of the call */
remove_call(sccp_ctx * ctx,zend_op * opline,zend_ssa_op * ssa_op)2211 static int remove_call(sccp_ctx *ctx, zend_op *opline, zend_ssa_op *ssa_op)
2212 {
2213 	zend_ssa *ssa = ctx->scdf.ssa;
2214 	zend_op_array *op_array = ctx->scdf.op_array;
2215 	zend_call_info *call;
2216 	int i;
2217 
2218 	ZEND_ASSERT(ctx->call_map);
2219 	call = ctx->call_map[opline - op_array->opcodes];
2220 	ZEND_ASSERT(call);
2221 	ZEND_ASSERT(call->caller_call_opline == opline);
2222 	zend_ssa_remove_instr(ssa, opline, ssa_op);
2223 	zend_ssa_remove_instr(ssa, call->caller_init_opline,
2224 		&ssa->ops[call->caller_init_opline - op_array->opcodes]);
2225 
2226 	for (i = 0; i < call->num_args; i++) {
2227 		zend_ssa_remove_instr(ssa, call->arg_info[i].opline,
2228 			&ssa->ops[call->arg_info[i].opline - op_array->opcodes]);
2229 	}
2230 
2231 	// TODO: remove call_info completely???
2232 	call->callee_func = NULL;
2233 
2234 	return call->num_args + 2;
2235 }
2236 
2237 /* This is a basic DCE pass we run after SCCP. It only works on those instructions those result
2238  * value(s) were determined by SCCP. It removes dead computational instructions and converts
2239  * CV-affecting instructions into CONST ASSIGNs. This basic DCE is performed for multiple reasons:
2240  * a) During operand replacement we eliminate FREEs. The corresponding computational instructions
2241  *    must be removed to avoid leaks. This way SCCP can run independently of the full DCE pass.
2242  * b) The main DCE pass relies on type analysis to determine whether instructions have side-effects
2243  *    and can't be DCEd. This means that it will not be able collect all instructions rendered dead
2244  *    by SCCP, because they may have potentially side-effecting types, but the actual values are
2245  *    not. As such doing DCE here will allow us to eliminate more dead code in combination.
2246  * c) The ordinary DCE pass cannot collect dead calls. However SCCP can result in dead calls, which
2247  *    we need to collect.
2248  * d) The ordinary DCE pass cannot collect construction of dead non-escaping arrays and objects.
2249  */
try_remove_definition(sccp_ctx * ctx,int var_num,zend_ssa_var * var,zval * value)2250 static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var, zval *value)
2251 {
2252 	zend_ssa *ssa = ctx->scdf.ssa;
2253 	zend_op_array *op_array = ctx->scdf.op_array;
2254 	int removed_ops = 0;
2255 
2256 	if (var->definition >= 0) {
2257 		zend_op *opline = &op_array->opcodes[var->definition];
2258 		zend_ssa_op *ssa_op = &ssa->ops[var->definition];
2259 
2260 		if (opline->opcode == ZEND_ASSIGN) {
2261 			/* Leave assigns to DCE (due to dtor effects) */
2262 			return 0;
2263 		}
2264 
2265 		if (ssa_op->result_def == var_num) {
2266 			if (ssa_op->op1_def >= 0
2267 					|| ssa_op->op2_def >= 0) {
2268 				/* we cannot remove instruction that defines other variables */
2269 				return 0;
2270 			} else if (opline->opcode == ZEND_JMPZ_EX
2271 					|| opline->opcode == ZEND_JMPNZ_EX
2272 					|| opline->opcode == ZEND_JMP_SET
2273 					|| opline->opcode == ZEND_COALESCE
2274 					|| opline->opcode == ZEND_FE_RESET_R
2275 					|| opline->opcode == ZEND_FE_RESET_RW
2276 					|| opline->opcode == ZEND_FE_FETCH_R
2277 					|| opline->opcode == ZEND_FE_FETCH_RW
2278 					|| opline->opcode == ZEND_NEW) {
2279 				/* we cannot simple remove jump instructions */
2280 				return 0;
2281 			} else if (var->use_chain >= 0
2282 					|| var->phi_use_chain != NULL) {
2283 				if (value
2284 						&& opline->result_type & (IS_VAR|IS_TMP_VAR)
2285 						&& opline->opcode != ZEND_QM_ASSIGN
2286 						&& opline->opcode != ZEND_ROPE_INIT
2287 						&& opline->opcode != ZEND_ROPE_ADD
2288 						&& opline->opcode != ZEND_INIT_ARRAY
2289 						&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
2290 						&& opline->opcode != ZEND_ADD_ARRAY_UNPACK) {
2291 					/* Replace with QM_ASSIGN */
2292 					zend_uchar old_type = opline->result_type;
2293 					uint32_t old_var = opline->result.var;
2294 
2295 					ssa_op->result_def = -1;
2296 					if (opline->opcode == ZEND_DO_ICALL) {
2297 						removed_ops = remove_call(ctx, opline, ssa_op) - 1;
2298 					} else {
2299 						zend_ssa_remove_instr(ssa, opline, ssa_op);
2300 					}
2301 					ssa_op->result_def = var_num;
2302 					opline->opcode = ZEND_QM_ASSIGN;
2303 					opline->result_type = old_type;
2304 					opline->result.var = old_var;
2305 					Z_TRY_ADDREF_P(value);
2306 					zend_optimizer_update_op1_const(ctx->scdf.op_array, opline, value);
2307 				}
2308 				return 0;
2309 			} else {
2310 				zend_ssa_remove_result_def(ssa, ssa_op);
2311 				if (opline->opcode == ZEND_DO_ICALL) {
2312 					removed_ops = remove_call(ctx, opline, ssa_op);
2313 				} else if (opline->opcode == ZEND_TYPE_CHECK
2314 						&& opline->op1_type & (IS_VAR|IS_TMP_VAR)
2315 						&& !value_known(&ctx->values[ssa_op->op1_use])) {
2316 					/* For TYPE_CHECK we may compute the result value without knowing the
2317 					 * operand, based on type inference information. Make sure the operand is
2318 					 * freed and leave further cleanup to DCE. */
2319 					opline->opcode = ZEND_FREE;
2320 					opline->result_type = IS_UNUSED;
2321 					removed_ops++;
2322 				} else {
2323 					zend_ssa_remove_instr(ssa, opline, ssa_op);
2324 					removed_ops++;
2325 				}
2326 			}
2327 		} else if (ssa_op->op1_def == var_num) {
2328 			/* Compound assign or incdec -> convert to direct ASSIGN */
2329 
2330 			if (!value) {
2331 				/* In some cases zend_may_throw() may be avoided */
2332 				switch (opline->opcode) {
2333 					case ZEND_ASSIGN_DIM:
2334 					case ZEND_ASSIGN_OBJ:
2335 					case ZEND_ASSIGN_OP:
2336 					case ZEND_ASSIGN_DIM_OP:
2337 					case ZEND_ASSIGN_OBJ_OP:
2338 					case ZEND_ASSIGN_STATIC_PROP_OP:
2339 						if ((ssa_op->op2_use >= 0 && !value_known(&ctx->values[ssa_op->op2_use]))
2340 								|| ((ssa_op+1)->op1_use >= 0 &&!value_known(&ctx->values[(ssa_op+1)->op1_use]))) {
2341 							return 0;
2342 						}
2343 						break;
2344 					case ZEND_PRE_INC_OBJ:
2345 					case ZEND_PRE_DEC_OBJ:
2346 					case ZEND_POST_INC_OBJ:
2347 					case ZEND_POST_DEC_OBJ:
2348 						if (ssa_op->op2_use >= 0 && !value_known(&ctx->values[ssa_op->op2_use])) {
2349 							return 0;
2350 						}
2351 						break;
2352 					default:
2353 						if (zend_may_throw(opline, op_array, ssa)) {
2354 							return 0;
2355 						}
2356 						break;
2357 				}
2358 			}
2359 
2360 			/* Mark result unused, if possible */
2361 			if (ssa_op->result_def >= 0) {
2362 				if (ssa->vars[ssa_op->result_def].use_chain < 0
2363 						&& ssa->vars[ssa_op->result_def].phi_use_chain == NULL) {
2364 					zend_ssa_remove_result_def(ssa, ssa_op);
2365 					opline->result_type = IS_UNUSED;
2366 				} else if (opline->opcode != ZEND_PRE_INC &&
2367 						opline->opcode != ZEND_PRE_DEC) {
2368 					/* op1_def and result_def are different */
2369 					return removed_ops;
2370 				}
2371 			}
2372 
2373 			/* Destroy previous op2 */
2374 			if (opline->op2_type == IS_CONST) {
2375 				literal_dtor(&ZEND_OP2_LITERAL(opline));
2376 			} else if (ssa_op->op2_use >= 0) {
2377 				if (ssa_op->op2_use != ssa_op->op1_use) {
2378 					zend_ssa_unlink_use_chain(ssa, var->definition, ssa_op->op2_use);
2379 				}
2380 				ssa_op->op2_use = -1;
2381 				ssa_op->op2_use_chain = -1;
2382 			}
2383 
2384 			/* Remove OP_DATA opcode */
2385 			switch (opline->opcode) {
2386 				case ZEND_ASSIGN_DIM:
2387 				case ZEND_ASSIGN_OBJ:
2388 					removed_ops++;
2389 					zend_ssa_remove_instr(ssa, opline + 1, ssa_op + 1);
2390 					break;
2391 				case ZEND_ASSIGN_DIM_OP:
2392 				case ZEND_ASSIGN_OBJ_OP:
2393 				case ZEND_ASSIGN_STATIC_PROP_OP:
2394 					removed_ops++;
2395 					zend_ssa_remove_instr(ssa, opline + 1, ssa_op + 1);
2396 					break;
2397 				default:
2398 					break;
2399 			}
2400 
2401 			if (value) {
2402 				/* Convert to ASSIGN */
2403 				opline->opcode = ZEND_ASSIGN;
2404 				opline->op2_type = IS_CONST;
2405 				opline->op2.constant = zend_optimizer_add_literal(op_array, value);
2406 				Z_TRY_ADDREF_P(value);
2407 			} else {
2408 				/* Remove dead array or object construction */
2409 				removed_ops++;
2410 				if (var->use_chain >= 0 || var->phi_use_chain != NULL) {
2411 					zend_ssa_rename_var_uses(ssa, ssa_op->op1_def, ssa_op->op1_use, 1);
2412 				}
2413 				zend_ssa_remove_op1_def(ssa, ssa_op);
2414 				zend_ssa_remove_instr(ssa, opline, ssa_op);
2415 			}
2416 		}
2417 	} else if (var->definition_phi
2418 			&& var->use_chain < 0
2419 			&& var->phi_use_chain == NULL) {
2420 		zend_ssa_remove_phi(ssa, var->definition_phi);
2421 	}
2422 	return removed_ops;
2423 }
2424 
2425 /* This will try to replace uses of SSA variables we have determined to be constant. Not all uses
2426  * can be replaced, because some instructions don't accept constant operands or only accept them
2427  * if they have a certain type. */
replace_constant_operands(sccp_ctx * ctx)2428 static int replace_constant_operands(sccp_ctx *ctx) {
2429 	zend_ssa *ssa = ctx->scdf.ssa;
2430 	zend_op_array *op_array = ctx->scdf.op_array;
2431 	int i;
2432 	zval tmp;
2433 	int removed_ops = 0;
2434 
2435 	/* We iterate the variables backwards, so we can eliminate sequences like INIT_ROPE
2436 	 * and INIT_ARRAY. */
2437 	for (i = ssa->vars_count - 1; i >= op_array->last_var; i--) {
2438 		zend_ssa_var *var = &ssa->vars[i];
2439 		zval *value;
2440 		int use;
2441 
2442 		if (IS_PARTIAL_ARRAY(&ctx->values[i])
2443 				|| IS_PARTIAL_OBJECT(&ctx->values[i])) {
2444 			if (!Z_DELREF(ctx->values[i])) {
2445 				zend_array_destroy(Z_ARR(ctx->values[i]));
2446 			}
2447 			MAKE_BOT(&ctx->values[i]);
2448 			if ((var->use_chain < 0 && var->phi_use_chain == NULL) || var->no_val) {
2449 				removed_ops += try_remove_definition(ctx, i, var, NULL);
2450 			}
2451 			continue;
2452 		} else if (value_known(&ctx->values[i])) {
2453 			value = &ctx->values[i];
2454 		} else {
2455 			value = value_from_type_and_range(ctx, i, &tmp);
2456 			if (!value) {
2457 				continue;
2458 			}
2459 		}
2460 
2461 		FOREACH_USE(var, use) {
2462 			zend_op *opline = &op_array->opcodes[use];
2463 			zend_ssa_op *ssa_op = &ssa->ops[use];
2464 			if (try_replace_op1(ctx, opline, ssa_op, i, value)) {
2465 				if (opline->opcode == ZEND_NOP) {
2466 					removed_ops++;
2467 				}
2468 				ZEND_ASSERT(ssa_op->op1_def == -1);
2469 				if (ssa_op->op1_use != ssa_op->op2_use) {
2470 					zend_ssa_unlink_use_chain(ssa, use, ssa_op->op1_use);
2471 				} else {
2472 					ssa_op->op2_use_chain = ssa_op->op1_use_chain;
2473 				}
2474 				ssa_op->op1_use = -1;
2475 				ssa_op->op1_use_chain = -1;
2476 			}
2477 			if (try_replace_op2(ctx, opline, ssa_op, i, value)) {
2478 				ZEND_ASSERT(ssa_op->op2_def == -1);
2479 				if (ssa_op->op2_use != ssa_op->op1_use) {
2480 					zend_ssa_unlink_use_chain(ssa, use, ssa_op->op2_use);
2481 				}
2482 				ssa_op->op2_use = -1;
2483 				ssa_op->op2_use_chain = -1;
2484 			}
2485 		} FOREACH_USE_END();
2486 
2487 		if (value_known(&ctx->values[i])) {
2488 			removed_ops += try_remove_definition(ctx, i, var, value);
2489 		}
2490 	}
2491 
2492 	return removed_ops;
2493 }
2494 
sccp_context_init(zend_optimizer_ctx * ctx,sccp_ctx * sccp,zend_ssa * ssa,zend_op_array * op_array,zend_call_info ** call_map)2495 static void sccp_context_init(zend_optimizer_ctx *ctx, sccp_ctx *sccp,
2496 		zend_ssa *ssa, zend_op_array *op_array, zend_call_info **call_map) {
2497 	int i;
2498 	sccp->call_map = call_map;
2499 	sccp->values = zend_arena_alloc(&ctx->arena, sizeof(zval) * ssa->vars_count);
2500 
2501 	MAKE_TOP(&sccp->top);
2502 	MAKE_BOT(&sccp->bot);
2503 
2504 	i = 0;
2505 	for (; i < op_array->last_var; ++i) {
2506 		/* These are all undefined variables, which we have to mark BOT.
2507 		 * Otherwise the undefined variable warning might not be preserved. */
2508 		MAKE_BOT(&sccp->values[i]);
2509 	}
2510 	for (; i < ssa->vars_count; ++i) {
2511 		if (ssa->vars[i].alias) {
2512 			MAKE_BOT(&sccp->values[i]);
2513 		} else {
2514 			MAKE_TOP(&sccp->values[i]);
2515 		}
2516 	}
2517 }
2518 
sccp_context_free(sccp_ctx * sccp)2519 static void sccp_context_free(sccp_ctx *sccp) {
2520 	int i;
2521 	for (i = sccp->scdf.op_array->last_var; i < sccp->scdf.ssa->vars_count; ++i) {
2522 		zval_ptr_dtor_nogc(&sccp->values[i]);
2523 	}
2524 }
2525 
sccp_optimize_op_array(zend_optimizer_ctx * ctx,zend_op_array * op_array,zend_ssa * ssa,zend_call_info ** call_map)2526 int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map)
2527 {
2528 	sccp_ctx sccp;
2529 	int removed_ops = 0;
2530 	void *checkpoint = zend_arena_checkpoint(ctx->arena);
2531 
2532 	sccp_context_init(ctx, &sccp, ssa, op_array, call_map);
2533 
2534 	sccp.scdf.handlers.visit_instr = sccp_visit_instr;
2535 	sccp.scdf.handlers.visit_phi = sccp_visit_phi;
2536 	sccp.scdf.handlers.mark_feasible_successors = sccp_mark_feasible_successors;
2537 
2538 	scdf_init(ctx, &sccp.scdf, op_array, ssa);
2539 	scdf_solve(&sccp.scdf, "SCCP");
2540 
2541 	if (ctx->debug_level & ZEND_DUMP_SCCP) {
2542 		int i, first = 1;
2543 
2544 		for (i = op_array->last_var; i < ssa->vars_count; i++) {
2545 			zval *zv = &sccp.values[i];
2546 
2547 			if (IS_TOP(zv) || IS_BOT(zv)) {
2548 				continue;
2549 			}
2550 			if (first) {
2551 				first = 0;
2552 				fprintf(stderr, "\nSCCP Values for \"");
2553 				zend_dump_op_array_name(op_array);
2554 				fprintf(stderr, "\":\n");
2555 			}
2556 			fprintf(stderr, "    #%d.", i);
2557 			zend_dump_var(op_array, IS_CV, ssa->vars[i].var);
2558 			fprintf(stderr, " =");
2559 			scp_dump_value(zv);
2560 			fprintf(stderr, "\n");
2561 		}
2562 	}
2563 
2564 	removed_ops += scdf_remove_unreachable_blocks(&sccp.scdf);
2565 	removed_ops += replace_constant_operands(&sccp);
2566 
2567 	sccp_context_free(&sccp);
2568 	zend_arena_release(&ctx->arena, checkpoint);
2569 
2570 	return removed_ops;
2571 }
2572