1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine, e-SSA based Type & Range Inference |
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 | https://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: Dmitry Stogov <dmitry@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include "zend_compile.h"
20 #include "zend_generators.h"
21 #include "zend_inference.h"
22 #include "zend_func_info.h"
23 #include "zend_call_graph.h"
24 #include "zend_closures.h"
25 #include "zend_worklist.h"
26 #include "zend_optimizer_internal.h"
27
28 /* The used range inference algorithm is described in:
29 * V. Campos, R. Rodrigues, I. de Assis Costa and F. Pereira.
30 * "Speed and Precision in Range Analysis", SBLP'12.
31 *
32 * There are a couple degrees of freedom, we use:
33 * * Propagation on SCCs.
34 * * e-SSA for live range splitting.
35 * * Only intra-procedural inference.
36 * * Widening with warmup passes, but without jump sets.
37 */
38
39 /* Whether to handle symbolic range constraints */
40 #define SYM_RANGE
41
42 /* Whether to handle negative range constraints */
43 /* Negative range inference is buggy, so disabled for now */
44 #undef NEG_RANGE
45
46 /* Number of warmup passes to use prior to widening */
47 #define RANGE_WARMUP_PASSES 16
48
49 /* Logging for range inference in general */
50 #if 0
51 #define LOG_SSA_RANGE(...) fprintf(stderr, __VA_ARGS__)
52 #else
53 #define LOG_SSA_RANGE(...)
54 #endif
55
56 /* Logging for negative range constraints */
57 #if 0
58 #define LOG_NEG_RANGE(...) fprintf(stderr, __VA_ARGS__)
59 #else
60 #define LOG_NEG_RANGE(...)
61 #endif
62
63 /* Pop elements in unspecified order from worklist until it is empty */
64 #define WHILE_WORKLIST(worklist, len, i) do { \
65 bool _done = 0; \
66 while (!_done) { \
67 _done = 1; \
68 ZEND_BITSET_FOREACH(worklist, len, i) { \
69 zend_bitset_excl(worklist, i); \
70 _done = 0;
71
72 #define WHILE_WORKLIST_END() \
73 } ZEND_BITSET_FOREACH_END(); \
74 } \
75 } while (0)
76
77 #define CHECK_SCC_VAR(var2) \
78 do { \
79 if (!ssa->vars[var2].no_val) { \
80 if (ssa->vars[var2].scc < 0) { \
81 zend_ssa_check_scc_var(op_array, ssa, var2, index, stack); \
82 } \
83 if (ssa->vars[var2].scc < ssa->vars[var].scc) { \
84 ssa->vars[var].scc = ssa->vars[var2].scc; \
85 is_root = 0; \
86 } \
87 } \
88 } while (0)
89
90 #define CHECK_SCC_ENTRY(var2) \
91 do { \
92 if (ssa->vars[var2].scc != ssa->vars[var].scc) { \
93 ssa->vars[var2].scc_entry = 1; \
94 } \
95 } while (0)
96
97 #define ADD_SCC_VAR(_var) \
98 do { \
99 if (ssa->vars[_var].scc == scc && \
100 !(ssa->var_info[_var].type & MAY_BE_REF)) { \
101 zend_bitset_incl(worklist, _var); \
102 } \
103 } while (0)
104
105 #define ADD_SCC_VAR_1(_var) \
106 do { \
107 if (ssa->vars[_var].scc == scc && \
108 !(ssa->var_info[_var].type & MAY_BE_REF) && \
109 !zend_bitset_in(visited, _var)) { \
110 zend_bitset_incl(worklist, _var); \
111 } \
112 } while (0)
113
114 #define FOR_EACH_DEFINED_VAR(line, MACRO) \
115 do { \
116 if (ssa->ops[line].op1_def >= 0) { \
117 MACRO(ssa->ops[line].op1_def); \
118 } \
119 if (ssa->ops[line].op2_def >= 0) { \
120 MACRO(ssa->ops[line].op2_def); \
121 } \
122 if (ssa->ops[line].result_def >= 0) { \
123 MACRO(ssa->ops[line].result_def); \
124 } \
125 if (op_array->opcodes[line].opcode == ZEND_OP_DATA) { \
126 if (ssa->ops[line-1].op1_def >= 0) { \
127 MACRO(ssa->ops[line-1].op1_def); \
128 } \
129 if (ssa->ops[line-1].op2_def >= 0) { \
130 MACRO(ssa->ops[line-1].op2_def); \
131 } \
132 if (ssa->ops[line-1].result_def >= 0) { \
133 MACRO(ssa->ops[line-1].result_def); \
134 } \
135 } else if ((uint32_t)line+1 < op_array->last && \
136 op_array->opcodes[line+1].opcode == ZEND_OP_DATA) { \
137 if (ssa->ops[line+1].op1_def >= 0) { \
138 MACRO(ssa->ops[line+1].op1_def); \
139 } \
140 if (ssa->ops[line+1].op2_def >= 0) { \
141 MACRO(ssa->ops[line+1].op2_def); \
142 } \
143 if (ssa->ops[line+1].result_def >= 0) { \
144 MACRO(ssa->ops[line+1].result_def); \
145 } \
146 } \
147 } while (0)
148
149
150 #define FOR_EACH_VAR_USAGE(_var, MACRO) \
151 do { \
152 zend_ssa_phi *p = ssa->vars[_var].phi_use_chain; \
153 int use = ssa->vars[_var].use_chain; \
154 while (use >= 0) { \
155 FOR_EACH_DEFINED_VAR(use, MACRO); \
156 use = zend_ssa_next_use(ssa->ops, _var, use); \
157 } \
158 p = ssa->vars[_var].phi_use_chain; \
159 while (p) { \
160 MACRO(p->ssa_var); \
161 p = zend_ssa_next_use_phi(ssa, _var, p); \
162 } \
163 } while (0)
164
add_will_overflow(zend_long a,zend_long b)165 static inline bool add_will_overflow(zend_long a, zend_long b) {
166 return (b > 0 && a > ZEND_LONG_MAX - b)
167 || (b < 0 && a < ZEND_LONG_MIN - b);
168 }
169 #if 0
170 static inline bool sub_will_overflow(zend_long a, zend_long b) {
171 return (b > 0 && a < ZEND_LONG_MIN + b)
172 || (b < 0 && a > ZEND_LONG_MAX + b);
173 }
174 #endif
175
176 #if 0
177 /* Recursive Pearce's SCC algorithm implementation */
178 static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack) /* {{{ */
179 {
180 int is_root = 1;
181 #ifdef SYM_RANGE
182 zend_ssa_phi *p;
183 #endif
184
185 ssa->vars[var].scc = *index;
186 (*index)++;
187
188 FOR_EACH_VAR_USAGE(var, CHECK_SCC_VAR);
189
190 #ifdef SYM_RANGE
191 /* Process symbolic control-flow constraints */
192 p = ssa->vars[var].sym_use_chain;
193 while (p) {
194 CHECK_SCC_VAR(p->ssa_var);
195 p = p->sym_use_chain;
196 }
197 #endif
198
199 if (is_root) {
200 ssa->sccs--;
201 while (stack->len > 0) {
202 int var2 = zend_worklist_stack_peek(stack);
203 if (ssa->vars[var2].scc < ssa->vars[var].scc) {
204 break;
205 }
206 zend_worklist_stack_pop(stack);
207 ssa->vars[var2].scc = ssa->sccs;
208 (*index)--;
209 }
210 ssa->vars[var].scc = ssa->sccs;
211 ssa->vars[var].scc_entry = 1;
212 (*index)--;
213 } else {
214 zend_worklist_stack_push(stack, var);
215 }
216 }
217 /* }}} */
218
219 ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
220 {
221 int index = 0;
222 zend_worklist_stack stack;
223 int j;
224 ALLOCA_FLAG(stack_use_heap)
225
226 ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
227
228 /* Find SCCs using Pearce's algorithm. */
229 ssa->sccs = ssa->vars_count;
230 for (j = 0; j < ssa->vars_count; j++) {
231 if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
232 zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack);
233 }
234 }
235
236 if (ssa->sccs) {
237 /* Shift SCC indexes. */
238 for (j = 0; j < ssa->vars_count; j++) {
239 if (ssa->vars[j].scc >= 0) {
240 ssa->vars[j].scc -= ssa->sccs;
241 }
242 }
243 }
244 ssa->sccs = ssa->vars_count - ssa->sccs;
245
246 for (j = 0; j < ssa->vars_count; j++) {
247 if (ssa->vars[j].scc >= 0) {
248 int var = j;
249 FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
250 }
251 }
252
253 ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
254 return SUCCESS;
255 }
256 /* }}} */
257
258 #else
259 /* Iterative Pearce's SCC algorithm implementation */
260
261 typedef struct _zend_scc_iterator {
262 int state;
263 int last;
264 union {
265 int use;
266 zend_ssa_phi *phi;
267 };
268 } zend_scc_iterator;
269
zend_scc_next(const zend_op_array * op_array,zend_ssa * ssa,int var,zend_scc_iterator * iterator)270 static int zend_scc_next(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_scc_iterator *iterator) /* {{{ */
271 {
272 zend_ssa_phi *phi;
273 int use, var2;
274
275 switch (iterator->state) {
276 case 0: goto state_0;
277 case 1: use = iterator->use; goto state_1;
278 case 2: use = iterator->use; goto state_2;
279 case 3: use = iterator->use; goto state_3;
280 case 4: use = iterator->use; goto state_4;
281 case 5: use = iterator->use; goto state_5;
282 case 6: use = iterator->use; goto state_6;
283 case 7: use = iterator->use; goto state_7;
284 case 8: use = iterator->use; goto state_8;
285 case 9: phi = iterator->phi; goto state_9;
286 #ifdef SYM_RANGE
287 case 10: phi = iterator->phi; goto state_10;
288 #endif
289 case 11: goto state_11;
290 }
291
292 state_0:
293 use = ssa->vars[var].use_chain;
294 while (use >= 0) {
295 iterator->use = use;
296 var2 = ssa->ops[use].op1_def;
297 if (var2 >= 0 && !ssa->vars[var2].no_val) {
298 iterator->state = 1;
299 return var2;
300 }
301 state_1:
302 var2 = ssa->ops[use].op2_def;
303 if (var2 >= 0 && !ssa->vars[var2].no_val) {
304 iterator->state = 2;
305 return var2;
306 }
307 state_2:
308 var2 = ssa->ops[use].result_def;
309 if (var2 >= 0 && !ssa->vars[var2].no_val) {
310 iterator->state = 3;
311 return var2;
312 }
313 state_3:
314 if (op_array->opcodes[use].opcode == ZEND_OP_DATA) {
315 var2 = ssa->ops[use-1].op1_def;
316 if (var2 >= 0 && !ssa->vars[var2].no_val) {
317 iterator->state = 4;
318 return var2;
319 }
320 state_4:
321 var2 = ssa->ops[use-1].op2_def;
322 if (var2 >= 0 && !ssa->vars[var2].no_val) {
323 iterator->state = 5;
324 return var2;
325 }
326 state_5:
327 var2 = ssa->ops[use-1].result_def;
328 if (var2 >= 0 && !ssa->vars[var2].no_val) {
329 iterator->state = 8;
330 return var2;
331 }
332 } else if ((uint32_t)use+1 < op_array->last &&
333 op_array->opcodes[use+1].opcode == ZEND_OP_DATA) {
334 var2 = ssa->ops[use+1].op1_def;
335 if (var2 >= 0 && !ssa->vars[var2].no_val) {
336 iterator->state = 6;
337 return var2;
338 }
339 state_6:
340 var2 = ssa->ops[use+1].op2_def;
341 if (var2 >= 0 && !ssa->vars[var2].no_val) {
342 iterator->state = 7;
343 return var2;
344 }
345 state_7:
346 var2 = ssa->ops[use+1].result_def;
347 if (var2 >= 0 && !ssa->vars[var2].no_val) {
348 iterator->state = 8;
349 return var2;
350 }
351 }
352 state_8:
353 use = zend_ssa_next_use(ssa->ops, var, use);
354 }
355
356 phi = ssa->vars[var].phi_use_chain;
357 while (phi) {
358 var2 = phi->ssa_var;
359 if (!ssa->vars[var2].no_val) {
360 iterator->state = 9;
361 iterator->phi = phi;
362 return var2;
363 }
364 state_9:
365 phi = zend_ssa_next_use_phi(ssa, var, phi);
366 }
367
368 #ifdef SYM_RANGE
369 /* Process symbolic control-flow constraints */
370 phi = ssa->vars[var].sym_use_chain;
371 while (phi) {
372 var2 = phi->ssa_var;
373 if (!ssa->vars[var2].no_val) {
374 iterator->state = 10;
375 iterator->phi = phi;
376 return var2;
377 }
378 state_10:
379 phi = phi->sym_use_chain;
380 }
381 #endif
382
383 iterator->state = 11;
384 state_11:
385 return -1;
386 }
387 /* }}} */
388
zend_ssa_check_scc_var(const zend_op_array * op_array,zend_ssa * ssa,int var,int * index,zend_worklist_stack * stack,zend_worklist_stack * vstack,zend_scc_iterator * iterators)389 static void zend_ssa_check_scc_var(const zend_op_array *op_array, zend_ssa *ssa, int var, int *index, zend_worklist_stack *stack, zend_worklist_stack *vstack, zend_scc_iterator *iterators) /* {{{ */
390 {
391 restart:
392 zend_worklist_stack_push(vstack, var);
393 iterators[var].state = 0;
394 iterators[var].last = -1;
395 ssa->vars[var].scc_entry = 1;
396 ssa->vars[var].scc = *index;
397 (*index)++;
398
399 while (vstack->len > 0) {
400 var = zend_worklist_stack_peek(vstack);
401 while (1) {
402 int var2;
403
404 if (iterators[var].last >= 0) {
405 /* finish edge */
406 var2 = iterators[var].last;
407 if (ssa->vars[var2].scc < ssa->vars[var].scc) {
408 ssa->vars[var].scc = ssa->vars[var2].scc;
409 ssa->vars[var].scc_entry = 0;
410 }
411 }
412 var2 = zend_scc_next(op_array, ssa, var, iterators + var);
413 iterators[var].last = var2;
414 if (var2 < 0) break;
415 /* begin edge */
416 if (ssa->vars[var2].scc < 0) {
417 var = var2;
418 goto restart;
419 }
420 }
421
422 /* finish visiting */
423 zend_worklist_stack_pop(vstack);
424 if (ssa->vars[var].scc_entry) {
425 ssa->sccs--;
426 while (stack->len > 0) {
427 int var2 = zend_worklist_stack_peek(stack);
428 if (ssa->vars[var2].scc < ssa->vars[var].scc) {
429 break;
430 }
431 zend_worklist_stack_pop(stack);
432 ssa->vars[var2].scc = ssa->sccs;
433 (*index)--;
434 }
435 ssa->vars[var].scc = ssa->sccs;
436 (*index)--;
437 } else {
438 zend_worklist_stack_push(stack, var);
439 }
440 }
441 }
442 /* }}} */
443
zend_ssa_find_sccs(const zend_op_array * op_array,zend_ssa * ssa)444 ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
445 {
446 int index = 0;
447 zend_worklist_stack stack, vstack;
448 zend_scc_iterator *iterators;
449 int j;
450 ALLOCA_FLAG(stack_use_heap)
451 ALLOCA_FLAG(vstack_use_heap)
452 ALLOCA_FLAG(iterators_use_heap)
453
454 iterators = do_alloca(sizeof(zend_scc_iterator) * ssa->vars_count, iterators_use_heap);
455 ZEND_WORKLIST_STACK_ALLOCA(&vstack, ssa->vars_count, vstack_use_heap);
456 ZEND_WORKLIST_STACK_ALLOCA(&stack, ssa->vars_count, stack_use_heap);
457
458 /* Find SCCs using Pearce's algorithm. */
459 ssa->sccs = ssa->vars_count;
460 for (j = 0; j < ssa->vars_count; j++) {
461 if (!ssa->vars[j].no_val && ssa->vars[j].scc < 0) {
462 zend_ssa_check_scc_var(op_array, ssa, j, &index, &stack, &vstack, iterators);
463 }
464 }
465
466 if (ssa->sccs) {
467 /* Shift SCC indexes. */
468 for (j = 0; j < ssa->vars_count; j++) {
469 if (ssa->vars[j].scc >= 0) {
470 ssa->vars[j].scc -= ssa->sccs;
471 }
472 }
473 }
474 ssa->sccs = ssa->vars_count - ssa->sccs;
475
476 for (j = 0; j < ssa->vars_count; j++) {
477 if (ssa->vars[j].scc >= 0) {
478 int var = j;
479 FOR_EACH_VAR_USAGE(var, CHECK_SCC_ENTRY);
480 }
481 }
482
483 ZEND_WORKLIST_STACK_FREE_ALLOCA(&stack, stack_use_heap);
484 ZEND_WORKLIST_STACK_FREE_ALLOCA(&vstack, vstack_use_heap);
485 free_alloca(iterators, iterators_use_heap);
486 return SUCCESS;
487 }
488 /* }}} */
489
490 #endif
491
zend_ssa_find_false_dependencies(const zend_op_array * op_array,zend_ssa * ssa)492 ZEND_API int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
493 {
494 zend_ssa_var *ssa_vars = ssa->vars;
495 zend_ssa_op *ssa_ops = ssa->ops;
496 int ssa_vars_count = ssa->vars_count;
497 zend_bitset worklist;
498 int i, j, use;
499 zend_ssa_phi *p;
500 ALLOCA_FLAG(use_heap);
501
502 if (!op_array->function_name || !ssa->vars || !ssa->ops) {
503 return SUCCESS;
504 }
505
506 worklist = do_alloca(sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count), use_heap);
507 memset(worklist, 0, sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count));
508
509 for (i = 0; i < ssa_vars_count; i++) {
510 ssa_vars[i].no_val = 1; /* mark as unused */
511 use = ssa->vars[i].use_chain;
512 while (use >= 0) {
513 if (!zend_ssa_is_no_val_use(&op_array->opcodes[use], &ssa->ops[use], i)) {
514 ssa_vars[i].no_val = 0; /* used directly */
515 zend_bitset_incl(worklist, i);
516 break;
517 }
518 use = zend_ssa_next_use(ssa_ops, i, use);
519 }
520 }
521
522 WHILE_WORKLIST(worklist, zend_bitset_len(ssa_vars_count), i) {
523 if (ssa_vars[i].definition_phi) {
524 /* mark all possible sources as used */
525 p = ssa_vars[i].definition_phi;
526 if (p->pi >= 0) {
527 if (ssa_vars[p->sources[0]].no_val) {
528 ssa_vars[p->sources[0]].no_val = 0; /* used indirectly */
529 zend_bitset_incl(worklist, p->sources[0]);
530 }
531 } else {
532 for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
533 ZEND_ASSERT(p->sources[j] >= 0);
534 if (ssa->vars[p->sources[j]].no_val) {
535 ssa_vars[p->sources[j]].no_val = 0; /* used indirectly */
536 zend_bitset_incl(worklist, p->sources[j]);
537 }
538 }
539 }
540 }
541 } WHILE_WORKLIST_END();
542
543 free_alloca(worklist, use_heap);
544
545 return SUCCESS;
546 }
547 /* }}} */
548
549 /* From "Hacker's Delight" */
minOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)550 zend_ulong minOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
551 {
552 zend_ulong m, temp;
553
554 m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
555 while (m != 0) {
556 if (~a & c & m) {
557 temp = (a | m) & -m;
558 if (temp <= b) {
559 a = temp;
560 break;
561 }
562 } else if (a & ~c & m) {
563 temp = (c | m) & -m;
564 if (temp <= d) {
565 c = temp;
566 break;
567 }
568 }
569 m = m >> 1;
570 }
571 return a | c;
572 }
573
maxOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)574 zend_ulong maxOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
575 {
576 zend_ulong m, temp;
577
578 m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
579 while (m != 0) {
580 if (b & d & m) {
581 temp = (b - m) | (m - 1);
582 if (temp >= a) {
583 b = temp;
584 break;
585 }
586 temp = (d - m) | (m - 1);
587 if (temp >= c) {
588 d = temp;
589 break;
590 }
591 }
592 m = m >> 1;
593 }
594 return b | d;
595 }
596
minAND(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)597 zend_ulong minAND(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
598 {
599 zend_ulong m, temp;
600
601 m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
602 while (m != 0) {
603 if (~a & ~c & m) {
604 temp = (a | m) & -m;
605 if (temp <= b) {
606 a = temp;
607 break;
608 }
609 temp = (c | m) & -m;
610 if (temp <= d) {
611 c = temp;
612 break;
613 }
614 }
615 m = m >> 1;
616 }
617 return a & c;
618 }
619
maxAND(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)620 zend_ulong maxAND(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
621 {
622 zend_ulong m, temp;
623
624 m = Z_UL(1) << (sizeof(zend_ulong) * 8 - 1);
625 while (m != 0) {
626 if (b & ~d & m) {
627 temp = (b | ~m) | (m - 1);
628 if (temp >= a) {
629 b = temp;
630 break;
631 }
632 } else if (~b & d & m) {
633 temp = (d | ~m) | (m - 1);
634 if (temp >= c) {
635 d = temp;
636 break;
637 }
638 }
639 m = m >> 1;
640 }
641 return b & d;
642 }
643
minXOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)644 zend_ulong minXOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
645 {
646 return minAND(a, b, ~d, ~c) | minAND(~b, ~a, c, d);
647 }
648
maxXOR(zend_ulong a,zend_ulong b,zend_ulong c,zend_ulong d)649 zend_ulong maxXOR(zend_ulong a, zend_ulong b, zend_ulong c, zend_ulong d)
650 {
651 return maxOR(0, maxAND(a, b, ~d, ~c), 0, maxAND(~b, ~a, c, d));
652 }
653
654 /* Based on "Hacker's Delight" */
655
656 /*
657 0: + + + + 0 0 0 0 => 0 0 + min/max
658 2: + + - + 0 0 1 0 => 1 0 ? min(a,b,c,-1)/max(a,b,0,d)
659 3: + + - - 0 0 1 1 => 1 1 - min/max
660 8: - + + + 1 0 0 0 => 1 0 ? min(a,-1,b,d)/max(0,b,c,d)
661 a: - + - + 1 0 1 0 => 1 0 ? MIN(a,c)/max(0,b,0,d)
662 b: - + - - 1 0 1 1 => 1 1 - c/-1
663 c: - - + + 1 1 0 0 => 1 1 - min/max
664 e: - - - + 1 1 1 0 => 1 1 - a/-1
665 f - - - - 1 1 1 1 => 1 1 - min/max
666 */
zend_ssa_range_or(zend_long a,zend_long b,zend_long c,zend_long d,zend_ssa_range * tmp)667 static void zend_ssa_range_or(zend_long a, zend_long b, zend_long c, zend_long d, zend_ssa_range *tmp)
668 {
669 int x = ((a < 0) ? 8 : 0) |
670 ((b < 0) ? 4 : 0) |
671 ((c < 0) ? 2 : 0) |
672 ((d < 0) ? 1 : 0);
673 switch (x) {
674 case 0x0:
675 case 0x3:
676 case 0xc:
677 case 0xf:
678 tmp->min = minOR(a, b, c, d);
679 tmp->max = maxOR(a, b, c, d);
680 break;
681 case 0x2:
682 tmp->min = minOR(a, b, c, -1);
683 tmp->max = maxOR(a, b, 0, d);
684 break;
685 case 0x8:
686 tmp->min = minOR(a, -1, c, d);
687 tmp->max = maxOR(0, b, c, d);
688 break;
689 case 0xa:
690 tmp->min = MIN(a, c);
691 tmp->max = maxOR(0, b, 0, d);
692 break;
693 case 0xb:
694 tmp->min = c;
695 tmp->max = -1;
696 break;
697 case 0xe:
698 tmp->min = a;
699 tmp->max = -1;
700 break;
701 }
702 }
703
704 /*
705 0: + + + + 0 0 0 0 => 0 0 + min/max
706 2: + + - + 0 0 1 0 => 0 0 + 0/b
707 3: + + - - 0 0 1 1 => 0 0 + min/max
708 8: - + + + 1 0 0 0 => 0 0 + 0/d
709 a: - + - + 1 0 1 0 => 1 0 ? min(a,-1,c,-1)/NAX(b,d)
710 b: - + - - 1 0 1 1 => 1 0 ? min(a,-1,c,d)/max(0,b,c,d)
711 c: - - + + 1 1 0 0 => 1 1 - min/max
712 e: - - - + 1 1 1 0 => 1 0 ? min(a,b,c,-1)/max(a,b,0,d)
713 f - - - - 1 1 1 1 => 1 1 - min/max
714 */
zend_ssa_range_and(zend_long a,zend_long b,zend_long c,zend_long d,zend_ssa_range * tmp)715 static void zend_ssa_range_and(zend_long a, zend_long b, zend_long c, zend_long d, zend_ssa_range *tmp)
716 {
717 int x = ((a < 0) ? 8 : 0) |
718 ((b < 0) ? 4 : 0) |
719 ((c < 0) ? 2 : 0) |
720 ((d < 0) ? 1 : 0);
721 switch (x) {
722 case 0x0:
723 case 0x3:
724 case 0xc:
725 case 0xf:
726 tmp->min = minAND(a, b, c, d);
727 tmp->max = maxAND(a, b, c, d);
728 break;
729 case 0x2:
730 tmp->min = 0;
731 tmp->max = b;
732 break;
733 case 0x8:
734 tmp->min = 0;
735 tmp->max = d;
736 break;
737 case 0xa:
738 tmp->min = minAND(a, -1, c, -1);
739 tmp->max = MAX(b, d);
740 break;
741 case 0xb:
742 tmp->min = minAND(a, -1, c, d);
743 tmp->max = maxAND(0, b, c, d);
744 break;
745 case 0xe:
746 tmp->min = minAND(a, b, c, -1);
747 tmp->max = maxAND(a, b, 0, d);
748 break;
749 }
750 }
751
zend_abs_range(zend_long min,zend_long max,zend_long * abs_min,zend_long * abs_max)752 static inline bool zend_abs_range(
753 zend_long min, zend_long max, zend_long *abs_min, zend_long *abs_max) {
754 if (min == ZEND_LONG_MIN) {
755 /* Cannot take absolute value of LONG_MIN */
756 return 0;
757 }
758
759 if (min >= 0) {
760 *abs_min = min;
761 *abs_max = max;
762 } else if (max <= 0) {
763 *abs_min = -max;
764 *abs_max = -min;
765 } else {
766 /* Range crossing zero */
767 *abs_min = 0;
768 *abs_max = MAX(max, -min);
769 }
770
771 return 1;
772 }
773
safe_shift_left(zend_long n,zend_long s)774 static inline zend_long safe_shift_left(zend_long n, zend_long s) {
775 return (zend_long) ((zend_ulong) n << (zend_ulong) s);
776 }
777
shift_left_overflows(zend_long n,zend_long s)778 static inline bool shift_left_overflows(zend_long n, zend_long s) {
779 /* This considers shifts that shift in the sign bit to be overflowing as well */
780 if (n >= 0) {
781 return s >= SIZEOF_ZEND_LONG * 8 - 1 || safe_shift_left(n, s) < n;
782 } else {
783 return s >= SIZEOF_ZEND_LONG * 8 || safe_shift_left(n, s) > n;
784 }
785 }
786
787 /* If b does not divide a exactly, return the two adjacent values between which the real result
788 * lies. */
float_div(zend_long a,zend_long b,zend_long * r1,zend_long * r2)789 static void float_div(zend_long a, zend_long b, zend_long *r1, zend_long *r2) {
790 *r1 = *r2 = a / b;
791 if (a % b != 0) {
792 if (*r2 < 0) {
793 (*r2)--;
794 } else {
795 (*r2)++;
796 }
797 }
798 }
799
zend_inference_calc_binary_op_range(const zend_op_array * op_array,zend_ssa * ssa,zend_op * opline,zend_ssa_op * ssa_op,zend_uchar opcode,zend_ssa_range * tmp)800 static int zend_inference_calc_binary_op_range(
801 const zend_op_array *op_array, zend_ssa *ssa,
802 zend_op *opline, zend_ssa_op *ssa_op, zend_uchar opcode, zend_ssa_range *tmp) {
803 zend_long op1_min, op2_min, op1_max, op2_max, t1, t2, t3, t4;
804
805 switch (opcode) {
806 case ZEND_ADD:
807 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
808 op1_min = OP1_MIN_RANGE();
809 op2_min = OP2_MIN_RANGE();
810 op1_max = OP1_MAX_RANGE();
811 op2_max = OP2_MAX_RANGE();
812 if (OP1_RANGE_UNDERFLOW() ||
813 OP2_RANGE_UNDERFLOW() ||
814 zend_add_will_overflow(op1_min, op2_min)) {
815 tmp->underflow = 1;
816 tmp->min = ZEND_LONG_MIN;
817 } else {
818 tmp->min = op1_min + op2_min;
819 }
820 if (OP1_RANGE_OVERFLOW() ||
821 OP2_RANGE_OVERFLOW() ||
822 zend_add_will_overflow(op1_max, op2_max)) {
823 tmp->overflow = 1;
824 tmp->max = ZEND_LONG_MAX;
825 } else {
826 tmp->max = op1_max + op2_max;
827 }
828 return 1;
829 }
830 break;
831 case ZEND_SUB:
832 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
833 op1_min = OP1_MIN_RANGE();
834 op2_min = OP2_MIN_RANGE();
835 op1_max = OP1_MAX_RANGE();
836 op2_max = OP2_MAX_RANGE();
837 if (OP1_RANGE_UNDERFLOW() ||
838 OP2_RANGE_OVERFLOW() ||
839 zend_sub_will_overflow(op1_min, op2_max)) {
840 tmp->underflow = 1;
841 tmp->min = ZEND_LONG_MIN;
842 } else {
843 tmp->min = op1_min - op2_max;
844 }
845 if (OP1_RANGE_OVERFLOW() ||
846 OP2_RANGE_UNDERFLOW() ||
847 zend_sub_will_overflow(op1_max, op2_min)) {
848 tmp->overflow = 1;
849 tmp->max = ZEND_LONG_MAX;
850 } else {
851 tmp->max = op1_max - op2_min;
852 }
853 return 1;
854 }
855 break;
856 case ZEND_MUL:
857 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
858 double dummy;
859 zend_long t1_overflow, t2_overflow, t3_overflow, t4_overflow;
860 op1_min = OP1_MIN_RANGE();
861 op2_min = OP2_MIN_RANGE();
862 op1_max = OP1_MAX_RANGE();
863 op2_max = OP2_MAX_RANGE();
864 /* Suppress uninit variable warnings, these will only be used if the overflow
865 * flags are all false. */
866 t1 = t2 = t3 = t4 = 0;
867 ZEND_SIGNED_MULTIPLY_LONG(op1_min, op2_min, t1, dummy, t1_overflow);
868 ZEND_SIGNED_MULTIPLY_LONG(op1_min, op2_max, t2, dummy, t2_overflow);
869 ZEND_SIGNED_MULTIPLY_LONG(op1_max, op2_min, t3, dummy, t3_overflow);
870 ZEND_SIGNED_MULTIPLY_LONG(op1_max, op2_max, t4, dummy, t4_overflow);
871 (void) dummy;
872
873 // FIXME: more careful overflow checks?
874 if (OP1_RANGE_UNDERFLOW() || OP2_RANGE_UNDERFLOW() ||
875 OP1_RANGE_OVERFLOW() || OP2_RANGE_OVERFLOW() ||
876 t1_overflow || t2_overflow || t3_overflow || t4_overflow
877 ) {
878 tmp->underflow = 1;
879 tmp->overflow = 1;
880 tmp->min = ZEND_LONG_MIN;
881 tmp->max = ZEND_LONG_MAX;
882 } else {
883 tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
884 tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
885 }
886 return 1;
887 }
888 break;
889 case ZEND_DIV:
890 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
891 op1_min = OP1_MIN_RANGE();
892 op2_min = OP2_MIN_RANGE();
893 op1_max = OP1_MAX_RANGE();
894 op2_max = OP2_MAX_RANGE();
895
896 /* If op2 crosses zero, then floating point values close to zero might be
897 * possible, which will result in arbitrarily large results (overflow). Also
898 * avoid dividing LONG_MIN by -1, which is UB. */
899 if (OP1_RANGE_UNDERFLOW() || OP2_RANGE_UNDERFLOW() ||
900 OP1_RANGE_OVERFLOW() || OP2_RANGE_OVERFLOW() ||
901 (op2_min <= 0 && op2_max >= 0) ||
902 (op1_min == ZEND_LONG_MIN && op2_max == -1)
903 ) {
904 tmp->underflow = 1;
905 tmp->overflow = 1;
906 tmp->min = ZEND_LONG_MIN;
907 tmp->max = ZEND_LONG_MAX;
908 } else {
909 zend_long t1_, t2_, t3_, t4_;
910 float_div(op1_min, op2_min, &t1, &t1_);
911 float_div(op1_min, op2_max, &t2, &t2_);
912 float_div(op1_max, op2_min, &t3, &t3_);
913 float_div(op1_max, op2_max, &t4, &t4_);
914
915 tmp->min = MIN(MIN(MIN(t1, t2), MIN(t3, t4)), MIN(MIN(t1_, t2_), MIN(t3_, t4_)));
916 tmp->max = MAX(MAX(MAX(t1, t2), MAX(t3, t4)), MAX(MAX(t1_, t2_), MAX(t3_, t4_)));
917 }
918 return 1;
919 }
920 break;
921 case ZEND_MOD:
922 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
923 if (OP1_RANGE_UNDERFLOW() ||
924 OP2_RANGE_UNDERFLOW() ||
925 OP1_RANGE_OVERFLOW() ||
926 OP2_RANGE_OVERFLOW()) {
927 tmp->min = ZEND_LONG_MIN;
928 tmp->max = ZEND_LONG_MAX;
929 } else {
930 zend_long op2_abs_min, op2_abs_max;
931
932 op1_min = OP1_MIN_RANGE();
933 op2_min = OP2_MIN_RANGE();
934 op1_max = OP1_MAX_RANGE();
935 op2_max = OP2_MAX_RANGE();
936 if (!zend_abs_range(op2_min, op2_max, &op2_abs_min, &op2_abs_max)) {
937 break;
938 }
939
940 if (op2_abs_max == 0) {
941 /* Always modulus by zero, nothing we can do */
942 break;
943 }
944 if (op2_abs_min == 0) {
945 /* Ignore the modulus by zero case, which will throw */
946 op2_abs_min++;
947 }
948
949 if (op1_min >= 0) {
950 tmp->min = op1_max < op2_abs_min ? op1_min : 0;
951 tmp->max = MIN(op1_max, op2_abs_max - 1);
952 } else if (op1_max <= 0) {
953 tmp->min = MAX(op1_min, -op2_abs_max + 1);
954 tmp->max = op1_min > -op2_abs_min ? op1_max : 0;
955 } else {
956 tmp->min = MAX(op1_min, -op2_abs_max + 1);
957 tmp->max = MIN(op1_max, op2_abs_max - 1);
958 }
959 }
960 return 1;
961 }
962 break;
963 case ZEND_SL:
964 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
965 if (OP1_RANGE_UNDERFLOW() ||
966 OP2_RANGE_UNDERFLOW() ||
967 OP1_RANGE_OVERFLOW() ||
968 OP2_RANGE_OVERFLOW()) {
969 tmp->min = ZEND_LONG_MIN;
970 tmp->max = ZEND_LONG_MAX;
971 } else {
972 op1_min = OP1_MIN_RANGE();
973 op2_min = OP2_MIN_RANGE();
974 op1_max = OP1_MAX_RANGE();
975 op2_max = OP2_MAX_RANGE();
976
977 /* Shifts by negative numbers will throw, ignore them */
978 if (op2_min < 0) {
979 op2_min = 0;
980 }
981 if (op2_max < 0) {
982 op2_max = 0;
983 }
984
985 if (shift_left_overflows(op1_min, op2_max)
986 || shift_left_overflows(op1_max, op2_max)) {
987 tmp->min = ZEND_LONG_MIN;
988 tmp->max = ZEND_LONG_MAX;
989 } else {
990 t1 = safe_shift_left(op1_min, op2_min);
991 t2 = safe_shift_left(op1_min, op2_max);
992 t3 = safe_shift_left(op1_max, op2_min);
993 t4 = safe_shift_left(op1_max, op2_max);
994 tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
995 tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
996 }
997 }
998 return 1;
999 }
1000 break;
1001 case ZEND_SR:
1002 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
1003 if (OP1_RANGE_UNDERFLOW() ||
1004 OP2_RANGE_UNDERFLOW() ||
1005 OP1_RANGE_OVERFLOW() ||
1006 OP2_RANGE_OVERFLOW()) {
1007 tmp->min = ZEND_LONG_MIN;
1008 tmp->max = ZEND_LONG_MAX;
1009 } else {
1010 op1_min = OP1_MIN_RANGE();
1011 op2_min = OP2_MIN_RANGE();
1012 op1_max = OP1_MAX_RANGE();
1013 op2_max = OP2_MAX_RANGE();
1014
1015 /* Shifts by negative numbers will throw, ignore them */
1016 if (op2_min < 0) {
1017 op2_min = 0;
1018 }
1019 if (op2_max < 0) {
1020 op2_max = 0;
1021 }
1022
1023 /* Shifts by more than the integer size will be 0 or -1 */
1024 if (op2_min >= SIZEOF_ZEND_LONG * 8) {
1025 op2_min = SIZEOF_ZEND_LONG * 8 - 1;
1026 }
1027 if (op2_max >= SIZEOF_ZEND_LONG * 8) {
1028 op2_max = SIZEOF_ZEND_LONG * 8 - 1;
1029 }
1030
1031 t1 = op1_min >> op2_min;
1032 t2 = op1_min >> op2_max;
1033 t3 = op1_max >> op2_min;
1034 t4 = op1_max >> op2_max;
1035 tmp->min = MIN(MIN(t1, t2), MIN(t3, t4));
1036 tmp->max = MAX(MAX(t1, t2), MAX(t3, t4));
1037 }
1038 return 1;
1039 }
1040 break;
1041 case ZEND_BW_OR:
1042 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
1043 if (OP1_RANGE_UNDERFLOW() ||
1044 OP2_RANGE_UNDERFLOW() ||
1045 OP1_RANGE_OVERFLOW() ||
1046 OP2_RANGE_OVERFLOW()) {
1047 tmp->min = ZEND_LONG_MIN;
1048 tmp->max = ZEND_LONG_MAX;
1049 } else {
1050 op1_min = OP1_MIN_RANGE();
1051 op2_min = OP2_MIN_RANGE();
1052 op1_max = OP1_MAX_RANGE();
1053 op2_max = OP2_MAX_RANGE();
1054 zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
1055 }
1056 return 1;
1057 }
1058 break;
1059 case ZEND_BW_AND:
1060 if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
1061 if (OP1_RANGE_UNDERFLOW() ||
1062 OP2_RANGE_UNDERFLOW() ||
1063 OP1_RANGE_OVERFLOW() ||
1064 OP2_RANGE_OVERFLOW()) {
1065 tmp->min = ZEND_LONG_MIN;
1066 tmp->max = ZEND_LONG_MAX;
1067 } else {
1068 op1_min = OP1_MIN_RANGE();
1069 op2_min = OP2_MIN_RANGE();
1070 op1_max = OP1_MAX_RANGE();
1071 op2_max = OP2_MAX_RANGE();
1072 zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
1073 }
1074 return 1;
1075 }
1076 break;
1077 case ZEND_BW_XOR:
1078 // TODO
1079 break;
1080 EMPTY_SWITCH_DEFAULT_CASE()
1081 }
1082 return 0;
1083 }
1084
zend_inference_calc_range(const zend_op_array * op_array,zend_ssa * ssa,int var,int widening,int narrowing,zend_ssa_range * tmp)1085 static int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp)
1086 {
1087 uint32_t line;
1088 zend_op *opline;
1089 zend_ssa_op *ssa_op;
1090
1091 if (ssa->vars[var].definition_phi) {
1092 zend_ssa_phi *p = ssa->vars[var].definition_phi;
1093 int i;
1094
1095 tmp->underflow = 0;
1096 tmp->min = ZEND_LONG_MAX;
1097 tmp->max = ZEND_LONG_MIN;
1098 tmp->overflow = 0;
1099 if (p->pi >= 0 && p->has_range_constraint) {
1100 zend_ssa_range_constraint *constraint = &p->constraint.range;
1101 if (constraint->negative) {
1102 int src1 = p->sources[0];
1103
1104 if (ssa->var_info[src1].has_range) {
1105 *tmp = ssa->var_info[src1].range;
1106 if (constraint->range.min == constraint->range.max
1107 && !constraint->range.underflow
1108 && !constraint->range.overflow
1109 && p->constraint.range.min_ssa_var < 0
1110 && p->constraint.range.max_ssa_var < 0
1111 && ssa->vars[src1].definition >= 0) {
1112 /* Check for constrained induction variable */
1113 line = ssa->vars[src1].definition;
1114 opline = op_array->opcodes + line;
1115 switch (opline->opcode) {
1116 case ZEND_PRE_DEC:
1117 case ZEND_POST_DEC:
1118 if (!tmp->underflow) {
1119 zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi;
1120
1121 if (p && p->pi < 0
1122 && ssa->cfg.blocks[p->block].predecessors_count == 2
1123 && p->sources[1] == var
1124 && ssa->var_info[p->sources[0]].has_range
1125 && ssa->var_info[p->sources[0]].range.min > constraint->range.max) {
1126 tmp->min = constraint->range.max + 1;
1127 }
1128 }
1129 break;
1130 case ZEND_PRE_INC:
1131 case ZEND_POST_INC:
1132 if (!tmp->overflow) {
1133 zend_ssa_phi *p = ssa->vars[ssa->ops[line].op1_use].definition_phi;
1134
1135 if (p && p->pi < 0
1136 && ssa->cfg.blocks[p->block].predecessors_count == 2
1137 && p->sources[1] == var
1138 && ssa->var_info[p->sources[0]].has_range
1139 && ssa->var_info[p->sources[0]].range.max < constraint->range.min) {
1140 tmp->max = constraint->range.min - 1;
1141 }
1142 }
1143 break;
1144 }
1145 }
1146 } else if (narrowing) {
1147 tmp->underflow = 1;
1148 tmp->min = ZEND_LONG_MIN;
1149 tmp->max = ZEND_LONG_MAX;
1150 tmp->overflow = 1;
1151 }
1152
1153 #ifdef NEG_RANGE
1154 if (constraint->min_ssa_var < 0 &&
1155 constraint->max_ssa_var < 0 &&
1156 ssa->var_info[p->ssa_var].has_range) {
1157 LOG_NEG_RANGE("%s() #%d [%ld..%ld] -> [%ld..%ld]?\n",
1158 ZSTR_VAL(op_array->function_name),
1159 p->ssa_var,
1160 ssa->var_info[p->ssa_var].range.min,
1161 ssa->var_info[p->ssa_var].range.max,
1162 tmp->min,
1163 tmp->max);
1164 if (constraint->negative == NEG_USE_LT &&
1165 tmp->max >= constraint->range.min) {
1166 tmp->overflow = 0;
1167 tmp->max = constraint->range.min - 1;
1168 LOG_NEG_RANGE(" => [%ld..%ld]\n", tmp->min, tmp->max);
1169 } else if (constraint->negative == NEG_USE_GT &&
1170 tmp->min <= constraint->range.max) {
1171 tmp->underflow = 0;
1172 tmp->min = constraint->range.max + 1;
1173 LOG_NEG_RANGE(" => [%ld..%ld]\n", tmp->min, tmp->max);
1174 }
1175 }
1176 #endif
1177 } else if (ssa->var_info[p->sources[0]].has_range) {
1178 /* intersection */
1179 *tmp = ssa->var_info[p->sources[0]].range;
1180 if (constraint->min_ssa_var < 0) {
1181 tmp->underflow = constraint->range.underflow && tmp->underflow;
1182 tmp->min = MAX(constraint->range.min, tmp->min);
1183 #ifdef SYM_RANGE
1184 } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) {
1185 tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow && tmp->underflow;
1186 if (!add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) {
1187 tmp->min = MAX(ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min, tmp->min);
1188 }
1189 #endif
1190 }
1191 if (constraint->max_ssa_var < 0) {
1192 tmp->max = MIN(constraint->range.max, tmp->max);
1193 tmp->overflow = constraint->range.overflow && tmp->overflow;
1194 #ifdef SYM_RANGE
1195 } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) {
1196 if (!add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) {
1197 tmp->max = MIN(ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max, tmp->max);
1198 }
1199 tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow && tmp->overflow;
1200 #endif
1201 }
1202 } else if (narrowing) {
1203 if (constraint->min_ssa_var < 0) {
1204 tmp->underflow = constraint->range.underflow;
1205 tmp->min = constraint->range.min;
1206 #ifdef SYM_RANGE
1207 } else if (narrowing && ssa->var_info[constraint->min_ssa_var].has_range) {
1208 if (add_will_overflow(ssa->var_info[constraint->min_ssa_var].range.min, constraint->range.min)) {
1209 tmp->underflow = 1;
1210 tmp->min = ZEND_LONG_MIN;
1211 } else {
1212 tmp->underflow = ssa->var_info[constraint->min_ssa_var].range.underflow;
1213 tmp->min = ssa->var_info[constraint->min_ssa_var].range.min + constraint->range.min;
1214 }
1215 #endif
1216 } else {
1217 tmp->underflow = 1;
1218 tmp->min = ZEND_LONG_MIN;
1219 }
1220 if (constraint->max_ssa_var < 0) {
1221 tmp->max = constraint->range.max;
1222 tmp->overflow = constraint->range.overflow;
1223 #ifdef SYM_RANGE
1224 } else if (narrowing && ssa->var_info[constraint->max_ssa_var].has_range) {
1225 if (add_will_overflow(ssa->var_info[constraint->max_ssa_var].range.max, constraint->range.max)) {
1226 tmp->overflow = 1;
1227 tmp->max = ZEND_LONG_MAX;
1228 } else {
1229 tmp->max = ssa->var_info[constraint->max_ssa_var].range.max + constraint->range.max;
1230 tmp->overflow = ssa->var_info[constraint->max_ssa_var].range.overflow;
1231 }
1232 #endif
1233 } else {
1234 tmp->max = ZEND_LONG_MAX;
1235 tmp->overflow = 1;
1236 }
1237 }
1238 } else {
1239 for (i = 0; i < ssa->cfg.blocks[p->block].predecessors_count; i++) {
1240 ZEND_ASSERT(p->sources[i] >= 0);
1241 if (ssa->var_info[p->sources[i]].has_range) {
1242 /* union */
1243 tmp->underflow |= ssa->var_info[p->sources[i]].range.underflow;
1244 tmp->min = MIN(tmp->min, ssa->var_info[p->sources[i]].range.min);
1245 tmp->max = MAX(tmp->max, ssa->var_info[p->sources[i]].range.max);
1246 tmp->overflow |= ssa->var_info[p->sources[i]].range.overflow;
1247 } else if (narrowing) {
1248 tmp->underflow = 1;
1249 tmp->min = ZEND_LONG_MIN;
1250 tmp->max = ZEND_LONG_MAX;
1251 tmp->overflow = 1;
1252 }
1253 }
1254 }
1255 return (tmp->min <= tmp->max);
1256 } else if (ssa->vars[var].definition < 0) {
1257 if (var < op_array->last_var &&
1258 op_array->function_name) {
1259
1260 tmp->min = 0;
1261 tmp->max = 0;
1262 tmp->underflow = 0;
1263 tmp->overflow = 0;
1264 return 1;
1265 }
1266 return 0;
1267 }
1268 line = ssa->vars[var].definition;
1269 opline = op_array->opcodes + line;
1270 ssa_op = &ssa->ops[line];
1271
1272 return zend_inference_propagate_range(op_array, ssa, opline, ssa_op, var, tmp);
1273 }
1274
zend_inference_propagate_range(const zend_op_array * op_array,zend_ssa * ssa,zend_op * opline,zend_ssa_op * ssa_op,int var,zend_ssa_range * tmp)1275 ZEND_API int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp)
1276 {
1277 tmp->underflow = 0;
1278 tmp->overflow = 0;
1279 switch (opline->opcode) {
1280 case ZEND_ADD:
1281 case ZEND_SUB:
1282 case ZEND_MUL:
1283 case ZEND_DIV:
1284 case ZEND_MOD:
1285 case ZEND_SL:
1286 case ZEND_SR:
1287 case ZEND_BW_OR:
1288 case ZEND_BW_AND:
1289 case ZEND_BW_XOR:
1290 if (ssa_op->result_def == var) {
1291 return zend_inference_calc_binary_op_range(
1292 op_array, ssa, opline, ssa_op, opline->opcode, tmp);
1293 }
1294 break;
1295
1296 case ZEND_BW_NOT:
1297 if (ssa_op->result_def == var) {
1298 if (OP1_HAS_RANGE()) {
1299 if (OP1_RANGE_UNDERFLOW() ||
1300 OP1_RANGE_OVERFLOW()) {
1301 tmp->min = ZEND_LONG_MIN;
1302 tmp->max = ZEND_LONG_MAX;
1303 } else {
1304 zend_long op1_min = OP1_MIN_RANGE();
1305 zend_long op1_max = OP1_MAX_RANGE();
1306 tmp->min = ~op1_max;
1307 tmp->max = ~op1_min;
1308 }
1309 return 1;
1310 }
1311 }
1312 break;
1313 case ZEND_CAST:
1314 if (ssa_op->op1_def == var) {
1315 if (ssa_op->op1_def >= 0) {
1316 if (OP1_HAS_RANGE()) {
1317 tmp->underflow = OP1_RANGE_UNDERFLOW();
1318 tmp->min = OP1_MIN_RANGE();
1319 tmp->max = OP1_MAX_RANGE();
1320 tmp->overflow = OP1_RANGE_OVERFLOW();
1321 return 1;
1322 }
1323 }
1324 } else if (ssa_op->result_def == var) {
1325 if (opline->extended_value == IS_LONG) {
1326 if (OP1_HAS_RANGE()) {
1327 tmp->min = OP1_MIN_RANGE();
1328 tmp->max = OP1_MAX_RANGE();
1329 return 1;
1330 } else {
1331 tmp->min = ZEND_LONG_MIN;
1332 tmp->max = ZEND_LONG_MAX;
1333 return 1;
1334 }
1335 }
1336 }
1337 break;
1338 case ZEND_QM_ASSIGN:
1339 case ZEND_JMP_SET:
1340 case ZEND_COALESCE:
1341 case ZEND_COPY_TMP:
1342 if (ssa_op->op1_def == var) {
1343 if (ssa_op->op1_def >= 0) {
1344 if (OP1_HAS_RANGE()) {
1345 tmp->underflow = OP1_RANGE_UNDERFLOW();
1346 tmp->min = OP1_MIN_RANGE();
1347 tmp->max = OP1_MAX_RANGE();
1348 tmp->overflow = OP1_RANGE_OVERFLOW();
1349 return 1;
1350 }
1351 }
1352 }
1353 if (ssa_op->result_def == var) {
1354 if (OP1_HAS_RANGE()) {
1355 tmp->min = OP1_MIN_RANGE();
1356 tmp->max = OP1_MAX_RANGE();
1357 tmp->underflow = OP1_RANGE_UNDERFLOW();
1358 tmp->overflow = OP1_RANGE_OVERFLOW();
1359 return 1;
1360 }
1361 }
1362 break;
1363 case ZEND_SEND_VAR:
1364 if (ssa_op->op1_def == var) {
1365 if (ssa_op->op1_def >= 0) {
1366 if (OP1_HAS_RANGE()) {
1367 tmp->underflow = OP1_RANGE_UNDERFLOW();
1368 tmp->min = OP1_MIN_RANGE();
1369 tmp->max = OP1_MAX_RANGE();
1370 tmp->overflow = OP1_RANGE_OVERFLOW();
1371 return 1;
1372 }
1373 }
1374 }
1375 break;
1376 case ZEND_PRE_INC:
1377 if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1378 if (OP1_HAS_RANGE()) {
1379 tmp->min = OP1_MIN_RANGE();
1380 tmp->max = OP1_MAX_RANGE();
1381 tmp->underflow = OP1_RANGE_UNDERFLOW();
1382 tmp->overflow = OP1_RANGE_OVERFLOW();
1383 if (tmp->max < ZEND_LONG_MAX) {
1384 tmp->max++;
1385 } else {
1386 tmp->overflow = 1;
1387 }
1388 if (tmp->min < ZEND_LONG_MAX && !tmp->underflow) {
1389 tmp->min++;
1390 }
1391 return 1;
1392 }
1393 }
1394 break;
1395 case ZEND_PRE_DEC:
1396 if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1397 if (OP1_HAS_RANGE()) {
1398 tmp->min = OP1_MIN_RANGE();
1399 tmp->max = OP1_MAX_RANGE();
1400 tmp->underflow = OP1_RANGE_UNDERFLOW();
1401 tmp->overflow = OP1_RANGE_OVERFLOW();
1402 if (tmp->min > ZEND_LONG_MIN) {
1403 tmp->min--;
1404 } else {
1405 tmp->underflow = 1;
1406 }
1407 if (tmp->max > ZEND_LONG_MIN && !tmp->overflow) {
1408 tmp->max--;
1409 }
1410 return 1;
1411 }
1412 }
1413 break;
1414 case ZEND_POST_INC:
1415 if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1416 if (OP1_HAS_RANGE()) {
1417 tmp->min = OP1_MIN_RANGE();
1418 tmp->max = OP1_MAX_RANGE();
1419 tmp->underflow = OP1_RANGE_UNDERFLOW();
1420 tmp->overflow = OP1_RANGE_OVERFLOW();
1421 if (ssa_op->result_def == var) {
1422 return 1;
1423 }
1424 if (tmp->max < ZEND_LONG_MAX) {
1425 tmp->max++;
1426 } else {
1427 tmp->overflow = 1;
1428 }
1429 if (tmp->min < ZEND_LONG_MAX && !tmp->underflow) {
1430 tmp->min++;
1431 }
1432 return 1;
1433 }
1434 }
1435 break;
1436 case ZEND_POST_DEC:
1437 if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1438 if (OP1_HAS_RANGE()) {
1439 tmp->min = OP1_MIN_RANGE();
1440 tmp->max = OP1_MAX_RANGE();
1441 tmp->underflow = OP1_RANGE_UNDERFLOW();
1442 tmp->overflow = OP1_RANGE_OVERFLOW();
1443 if (ssa_op->result_def == var) {
1444 return 1;
1445 }
1446 if (tmp->min > ZEND_LONG_MIN) {
1447 tmp->min--;
1448 } else {
1449 tmp->underflow = 1;
1450 }
1451 if (tmp->max > ZEND_LONG_MIN && !tmp->overflow) {
1452 tmp->max--;
1453 }
1454 return 1;
1455 }
1456 }
1457 break;
1458 case ZEND_UNSET_DIM:
1459 case ZEND_UNSET_OBJ:
1460 if (ssa_op->op1_def == var) {
1461 /* If op1 is scalar, UNSET_DIM and UNSET_OBJ have no effect, so we can keep
1462 * the previous ranges. */
1463 if (OP1_HAS_RANGE()) {
1464 tmp->min = OP1_MIN_RANGE();
1465 tmp->max = OP1_MAX_RANGE();
1466 tmp->underflow = OP1_RANGE_UNDERFLOW();
1467 tmp->overflow = OP1_RANGE_OVERFLOW();
1468 return 1;
1469 }
1470 }
1471 break;
1472 case ZEND_ASSIGN:
1473 if (ssa_op->op1_def == var || ssa_op->op2_def == var || ssa_op->result_def == var) {
1474 if (OP2_HAS_RANGE()) {
1475 tmp->min = OP2_MIN_RANGE();
1476 tmp->max = OP2_MAX_RANGE();
1477 tmp->underflow = OP2_RANGE_UNDERFLOW();
1478 tmp->overflow = OP2_RANGE_OVERFLOW();
1479 return 1;
1480 }
1481 }
1482 break;
1483 case ZEND_ASSIGN_DIM:
1484 case ZEND_ASSIGN_OBJ:
1485 case ZEND_ASSIGN_STATIC_PROP:
1486 case ZEND_ASSIGN_DIM_OP:
1487 case ZEND_ASSIGN_OBJ_OP:
1488 case ZEND_ASSIGN_STATIC_PROP_OP:
1489 if ((ssa_op+1)->op1_def == var) {
1490 opline++;
1491 ssa_op++;
1492 if (OP1_HAS_RANGE()) {
1493 tmp->min = OP1_MIN_RANGE();
1494 tmp->max = OP1_MAX_RANGE();
1495 tmp->underflow = OP1_RANGE_UNDERFLOW();
1496 tmp->overflow = OP1_RANGE_OVERFLOW();
1497 }
1498 return 1;
1499 }
1500 break;
1501 case ZEND_ASSIGN_OP:
1502 if (opline->extended_value != ZEND_CONCAT
1503 && opline->extended_value != ZEND_POW) {
1504 if (ssa_op->op1_def == var || ssa_op->result_def == var) {
1505 return zend_inference_calc_binary_op_range(
1506 op_array, ssa, opline, ssa_op,
1507 opline->extended_value, tmp);
1508 }
1509 }
1510 break;
1511 case ZEND_OP_DATA:
1512 if (ssa_op->op1_def == var) {
1513 if ((opline-1)->opcode == ZEND_ASSIGN_DIM ||
1514 (opline-1)->opcode == ZEND_ASSIGN_OBJ ||
1515 (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP ||
1516 (opline-1)->opcode == ZEND_ASSIGN_DIM_OP ||
1517 (opline-1)->opcode == ZEND_ASSIGN_OBJ_OP ||
1518 (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
1519 if (OP1_HAS_RANGE()) {
1520 tmp->min = OP1_MIN_RANGE();
1521 tmp->max = OP1_MAX_RANGE();
1522 tmp->underflow = OP1_RANGE_UNDERFLOW();
1523 tmp->overflow = OP1_RANGE_OVERFLOW();
1524 return 1;
1525 }
1526 }
1527 break;
1528 }
1529 break;
1530 case ZEND_RECV:
1531 case ZEND_RECV_INIT:
1532 if (ssa_op->result_def == var) {
1533 if (op_array->arg_info &&
1534 opline->op1.num <= op_array->num_args) {
1535 zend_type type = op_array->arg_info[opline->op1.num-1].type;
1536 uint32_t mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type);
1537 if (mask == MAY_BE_LONG) {
1538 tmp->underflow = 0;
1539 tmp->min = ZEND_LONG_MIN;
1540 tmp->max = ZEND_LONG_MAX;
1541 tmp->overflow = 0;
1542 return 1;
1543 }
1544 }
1545 }
1546 break;
1547 case ZEND_STRLEN:
1548 if (ssa_op->result_def == var) {
1549 #if SIZEOF_ZEND_LONG == 4
1550 /* The length of a string is a non-negative integer. However, on 32-bit
1551 * platforms overflows into negative lengths may occur, so it's better
1552 * to not assume any particular range. */
1553 tmp->min = ZEND_LONG_MIN;
1554 #else
1555 tmp->min = 0;
1556 #endif
1557 tmp->max = ZEND_LONG_MAX;
1558 return 1;
1559 }
1560 break;
1561 case ZEND_FUNC_NUM_ARGS:
1562 tmp->min = 0;
1563 tmp->max = ZEND_LONG_MAX;
1564 return 1;
1565 case ZEND_COUNT:
1566 /* count() on Countable objects may return negative numbers */
1567 tmp->min = ZEND_LONG_MIN;
1568 tmp->max = ZEND_LONG_MAX;
1569 return 1;
1570 case ZEND_DO_FCALL:
1571 case ZEND_DO_ICALL:
1572 case ZEND_DO_UCALL:
1573 case ZEND_DO_FCALL_BY_NAME:
1574 if (ssa_op->result_def == var) {
1575 zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
1576 zend_call_info *call_info;
1577 if (!func_info || !func_info->call_map) {
1578 break;
1579 }
1580
1581 call_info = func_info->call_map[opline - op_array->opcodes];
1582 if (!call_info || call_info->is_prototype) {
1583 break;
1584 }
1585 if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
1586 func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
1587 if (func_info && func_info->return_info.has_range) {
1588 *tmp = func_info->return_info.range;
1589 return 1;
1590 }
1591 }
1592 //TODO: we can't use type inference for internal functions at this point ???
1593 #if 0
1594 uint32_t type;
1595
1596 type = zend_get_func_info(call_info, ssa);
1597 if (!(type & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)))) {
1598 tmp->underflow = 0;
1599 tmp->min = 0;
1600 tmp->max = 0;
1601 tmp->overflow = 0;
1602 if (type & MAY_BE_LONG) {
1603 tmp->min = ZEND_LONG_MIN;
1604 tmp->max = ZEND_LONG_MAX;
1605 } else if (type & MAY_BE_TRUE) {
1606 if (!(type & (MAY_BE_NULL|MAY_BE_FALSE))) {
1607 tmp->min = 1;
1608 }
1609 tmp->max = 1;
1610 }
1611 return 1;
1612 }
1613 #endif
1614 }
1615 break;
1616 // FIXME: support for more opcodes
1617 default:
1618 break;
1619 }
1620 return 0;
1621 }
1622
zend_inference_init_range(const zend_op_array * op_array,zend_ssa * ssa,int var,bool underflow,zend_long min,zend_long max,bool overflow)1623 static void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, bool underflow, zend_long min, zend_long max, bool overflow)
1624 {
1625 if (underflow) {
1626 min = ZEND_LONG_MIN;
1627 }
1628 if (overflow) {
1629 max = ZEND_LONG_MAX;
1630 }
1631 ssa->var_info[var].has_range = 1;
1632 ssa->var_info[var].range.underflow = underflow;
1633 ssa->var_info[var].range.min = min;
1634 ssa->var_info[var].range.max = max;
1635 ssa->var_info[var].range.overflow = overflow;
1636 LOG_SSA_RANGE(" change range (init SCC %2d) %2d [%s%ld..%ld%s]\n", ssa->vars[var].scc, var, (underflow?"-- ":""), min, max, (overflow?" ++":""));
1637 }
1638
zend_inference_widening_meet(zend_ssa_var_info * var_info,zend_ssa_range * r)1639 static int zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r)
1640 {
1641 if (!var_info->has_range) {
1642 var_info->has_range = 1;
1643 } else {
1644 if (r->underflow ||
1645 var_info->range.underflow ||
1646 r->min < var_info->range.min) {
1647 r->underflow = 1;
1648 r->min = ZEND_LONG_MIN;
1649 }
1650 if (r->overflow ||
1651 var_info->range.overflow ||
1652 r->max > var_info->range.max) {
1653 r->overflow = 1;
1654 r->max = ZEND_LONG_MAX;
1655 }
1656 if (var_info->range.min == r->min &&
1657 var_info->range.max == r->max &&
1658 var_info->range.underflow == r->underflow &&
1659 var_info->range.overflow == r->overflow) {
1660 return 0;
1661 }
1662 }
1663 var_info->range = *r;
1664 return 1;
1665 }
1666
zend_ssa_range_widening(const zend_op_array * op_array,zend_ssa * ssa,int var,int scc)1667 static int zend_ssa_range_widening(const zend_op_array *op_array, zend_ssa *ssa, int var, int scc)
1668 {
1669 zend_ssa_range tmp;
1670
1671 if (zend_inference_calc_range(op_array, ssa, var, 1, 0, &tmp)) {
1672 if (zend_inference_widening_meet(&ssa->var_info[var], &tmp)) {
1673 LOG_SSA_RANGE(" change range (widening SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1674 return 1;
1675 }
1676 }
1677 return 0;
1678 }
1679
zend_inference_narrowing_meet(zend_ssa_var_info * var_info,zend_ssa_range * r)1680 static int zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *r)
1681 {
1682 if (!var_info->has_range) {
1683 var_info->has_range = 1;
1684 } else {
1685 if (!r->underflow &&
1686 !var_info->range.underflow &&
1687 var_info->range.min < r->min) {
1688 r->min = var_info->range.min;
1689 }
1690 if (!r->overflow &&
1691 !var_info->range.overflow &&
1692 var_info->range.max > r->max) {
1693 r->max = var_info->range.max;
1694 }
1695 if (r->underflow) {
1696 r->min = ZEND_LONG_MIN;
1697 }
1698 if (r->overflow) {
1699 r->max = ZEND_LONG_MAX;
1700 }
1701 if (var_info->range.min == r->min &&
1702 var_info->range.max == r->max &&
1703 var_info->range.underflow == r->underflow &&
1704 var_info->range.overflow == r->overflow) {
1705 return 0;
1706 }
1707 }
1708 var_info->range = *r;
1709 return 1;
1710 }
1711
zend_ssa_range_narrowing(const zend_op_array * op_array,zend_ssa * ssa,int var,int scc)1712 static int zend_ssa_range_narrowing(const zend_op_array *op_array, zend_ssa *ssa, int var, int scc)
1713 {
1714 zend_ssa_range tmp;
1715
1716 if (zend_inference_calc_range(op_array, ssa, var, 0, 1, &tmp)) {
1717 if (zend_inference_narrowing_meet(&ssa->var_info[var], &tmp)) {
1718 LOG_SSA_RANGE(" change range (narrowing SCC %2d) %2d [%s%ld..%ld%s]\n", scc, var, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1719 return 1;
1720 }
1721 }
1722 return 0;
1723 }
1724
1725 #ifdef NEG_RANGE
1726 # define CHECK_INNER_CYCLE(var2) \
1727 do { \
1728 if (ssa->vars[var2].scc == ssa->vars[var].scc && \
1729 !ssa->vars[var2].scc_entry && \
1730 !zend_bitset_in(visited, var2) && \
1731 zend_check_inner_cycles(op_array, ssa, worklist, visited, var2)) { \
1732 return 1; \
1733 } \
1734 } while (0)
1735
zend_check_inner_cycles(const zend_op_array * op_array,zend_ssa * ssa,zend_bitset worklist,zend_bitset visited,int var)1736 static int zend_check_inner_cycles(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset worklist, zend_bitset visited, int var)
1737 {
1738 if (zend_bitset_in(worklist, var)) {
1739 return 1;
1740 }
1741 zend_bitset_incl(worklist, var);
1742 FOR_EACH_VAR_USAGE(var, CHECK_INNER_CYCLE);
1743 zend_bitset_incl(visited, var);
1744 return 0;
1745 }
1746 #endif
1747
zend_infer_ranges_warmup(const zend_op_array * op_array,zend_ssa * ssa,int * scc_var,int * next_scc_var,int scc)1748 static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ssa, int *scc_var, int *next_scc_var, int scc)
1749 {
1750 int worklist_len = zend_bitset_len(ssa->vars_count);
1751 int j, n;
1752 zend_ssa_range tmp;
1753 ALLOCA_FLAG(use_heap)
1754 zend_bitset worklist = do_alloca(sizeof(zend_ulong) * worklist_len * 2, use_heap);
1755 zend_bitset visited = worklist + worklist_len;
1756 #ifdef NEG_RANGE
1757 int has_inner_cycles = 0;
1758
1759 memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1760 memset(visited, 0, sizeof(zend_ulong) * worklist_len);
1761 j = scc_var[scc];
1762 while (j >= 0) {
1763 if (!zend_bitset_in(visited, j) &&
1764 zend_check_inner_cycles(op_array, ssa, worklist, visited, j)) {
1765 has_inner_cycles = 1;
1766 break;
1767 }
1768 j = next_scc_var[j];
1769 }
1770 #endif
1771
1772 memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1773
1774 for (n = 0; n < RANGE_WARMUP_PASSES; n++) {
1775 j= scc_var[scc];
1776 while (j >= 0) {
1777 if (ssa->vars[j].scc_entry
1778 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1779 zend_bitset_incl(worklist, j);
1780 }
1781 j = next_scc_var[j];
1782 }
1783
1784 memset(visited, 0, sizeof(zend_ulong) * worklist_len);
1785
1786 WHILE_WORKLIST(worklist, worklist_len, j) {
1787 if (zend_inference_calc_range(op_array, ssa, j, 0, 0, &tmp)) {
1788 #ifdef NEG_RANGE
1789 if (!has_inner_cycles &&
1790 ssa->var_info[j].has_range &&
1791 ssa->vars[j].definition_phi &&
1792 ssa->vars[j].definition_phi->pi >= 0 &&
1793 ssa->vars[j].definition_phi->has_range_constraint &&
1794 ssa->vars[j].definition_phi->constraint.range.negative &&
1795 ssa->vars[j].definition_phi->constraint.range.min_ssa_var < 0 &&
1796 ssa->vars[j].definition_phi->constraint.range.max_ssa_var < 0) {
1797 zend_ssa_range_constraint *constraint =
1798 &ssa->vars[j].definition_phi->constraint.range;
1799 if (tmp.min == ssa->var_info[j].range.min &&
1800 tmp.max == ssa->var_info[j].range.max) {
1801 if (constraint->negative == NEG_INIT) {
1802 LOG_NEG_RANGE("#%d INVARIANT\n", j);
1803 constraint->negative = NEG_INVARIANT;
1804 }
1805 } else if (tmp.min == ssa->var_info[j].range.min &&
1806 tmp.max == ssa->var_info[j].range.max + 1 &&
1807 tmp.max < constraint->range.min) {
1808 if (constraint->negative == NEG_INIT ||
1809 constraint->negative == NEG_INVARIANT) {
1810 LOG_NEG_RANGE("#%d LT\n", j);
1811 constraint->negative = NEG_USE_LT;
1812 //???NEG
1813 } else if (constraint->negative == NEG_USE_GT) {
1814 LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1815 constraint->negative = NEG_UNKNOWN;
1816 }
1817 } else if (tmp.max == ssa->var_info[j].range.max &&
1818 tmp.min == ssa->var_info[j].range.min - 1 &&
1819 tmp.min > constraint->range.max) {
1820 if (constraint->negative == NEG_INIT ||
1821 constraint->negative == NEG_INVARIANT) {
1822 LOG_NEG_RANGE("#%d GT\n", j);
1823 constraint->negative = NEG_USE_GT;
1824 //???NEG
1825 } else if (constraint->negative == NEG_USE_LT) {
1826 LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1827 constraint->negative = NEG_UNKNOWN;
1828 }
1829 } else {
1830 LOG_NEG_RANGE("#%d UNKNOWN\n", j);
1831 constraint->negative = NEG_UNKNOWN;
1832 }
1833 }
1834 #endif
1835 if (zend_inference_narrowing_meet(&ssa->var_info[j], &tmp)) {
1836 LOG_SSA_RANGE(" change range (warmup %2d SCC %2d) %2d [%s%ld..%ld%s]\n", n, scc, j, (tmp.underflow?"-- ":""), tmp.min, tmp.max, (tmp.overflow?" ++":""));
1837 zend_bitset_incl(visited, j);
1838 FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR_1);
1839 }
1840 }
1841 } WHILE_WORKLIST_END();
1842 }
1843 free_alloca(worklist, use_heap);
1844 }
1845
zend_infer_ranges(const zend_op_array * op_array,zend_ssa * ssa)1846 static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{{ */
1847 {
1848 int worklist_len = zend_bitset_len(ssa->vars_count);
1849 zend_bitset worklist;
1850 int *next_scc_var;
1851 int *scc_var;
1852 zend_ssa_phi *p;
1853 zend_ssa_range tmp;
1854 int scc, j;
1855 ALLOCA_FLAG(use_heap);
1856
1857 worklist = do_alloca(
1858 ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len) +
1859 ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count) +
1860 sizeof(int) * ssa->sccs, use_heap);
1861 next_scc_var = (int*)((char*)worklist + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ulong) * worklist_len));
1862 scc_var = (int*)((char*)next_scc_var + ZEND_MM_ALIGNED_SIZE(sizeof(int) * ssa->vars_count));
1863
1864 LOG_SSA_RANGE("Range Inference\n");
1865
1866 /* Create linked lists of SSA variables for each SCC */
1867 memset(scc_var, -1, sizeof(int) * ssa->sccs);
1868 for (j = 0; j < ssa->vars_count; j++) {
1869 if (ssa->vars[j].scc >= 0) {
1870 next_scc_var[j] = scc_var[ssa->vars[j].scc];
1871 scc_var[ssa->vars[j].scc] = j;
1872 }
1873 }
1874
1875 for (scc = 0; scc < ssa->sccs; scc++) {
1876 j = scc_var[scc];
1877 if (next_scc_var[j] < 0) {
1878 /* SCC with a single element */
1879 if (ssa->var_info[j].type & MAY_BE_REF) {
1880 /* pass */
1881 } else if (zend_inference_calc_range(op_array, ssa, j, 0, 1, &tmp)) {
1882 zend_inference_init_range(op_array, ssa, j, tmp.underflow, tmp.min, tmp.max, tmp.overflow);
1883 } else {
1884 zend_inference_init_range(op_array, ssa, j, 1, ZEND_LONG_MIN, ZEND_LONG_MAX, 1);
1885 }
1886 } else {
1887 /* Find SCC entry points */
1888 memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
1889 do {
1890 if (ssa->vars[j].scc_entry
1891 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1892 zend_bitset_incl(worklist, j);
1893 }
1894 j = next_scc_var[j];
1895 } while (j >= 0);
1896
1897 #if RANGE_WARMUP_PASSES > 0
1898 zend_infer_ranges_warmup(op_array, ssa, scc_var, next_scc_var, scc);
1899 j = scc_var[scc];
1900 do {
1901 if (!(ssa->var_info[j].type & MAY_BE_REF)) {
1902 zend_bitset_incl(worklist, j);
1903 }
1904 j = next_scc_var[j];
1905 } while (j >= 0);
1906 #endif
1907
1908 /* widening */
1909 WHILE_WORKLIST(worklist, worklist_len, j) {
1910 if (zend_ssa_range_widening(op_array, ssa, j, scc)) {
1911 FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1912 }
1913 } WHILE_WORKLIST_END();
1914
1915 /* initialize missing ranges */
1916 for (j = scc_var[scc]; j >= 0; j = next_scc_var[j]) {
1917 if (!ssa->var_info[j].has_range
1918 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1919 zend_inference_init_range(op_array, ssa, j, 1, ZEND_LONG_MIN, ZEND_LONG_MAX, 1);
1920 FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1921 }
1922 }
1923
1924 /* widening (second round) */
1925 WHILE_WORKLIST(worklist, worklist_len, j) {
1926 if (zend_ssa_range_widening(op_array, ssa, j, scc)) {
1927 FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1928 }
1929 } WHILE_WORKLIST_END();
1930
1931 /* Add all SCC entry variables into worklist for narrowing */
1932 for (j = scc_var[scc]; j >= 0; j = next_scc_var[j]) {
1933 if (ssa->vars[j].definition_phi
1934 && ssa->vars[j].definition_phi->pi < 0
1935 && !(ssa->var_info[j].type & MAY_BE_REF)) {
1936 /* narrowing Phi functions first */
1937 zend_ssa_range_narrowing(op_array, ssa, j, scc);
1938 }
1939 zend_bitset_incl(worklist, j);
1940 }
1941
1942 /* narrowing */
1943 WHILE_WORKLIST(worklist, worklist_len, j) {
1944 if (zend_ssa_range_narrowing(op_array, ssa, j, scc)) {
1945 FOR_EACH_VAR_USAGE(j, ADD_SCC_VAR);
1946 #ifdef SYM_RANGE
1947 /* Process symbolic control-flow constraints */
1948 p = ssa->vars[j].sym_use_chain;
1949 while (p) {
1950 ADD_SCC_VAR(p->ssa_var);
1951 p = p->sym_use_chain;
1952 }
1953 #endif
1954 }
1955 } WHILE_WORKLIST_END();
1956 }
1957 }
1958
1959 free_alloca(worklist, use_heap);
1960
1961 return SUCCESS;
1962 }
1963 /* }}} */
1964
get_ssa_alias_types(zend_ssa_alias_kind alias)1965 static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
1966 if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
1967 return MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_RC1 | MAY_BE_RCN;
1968 } else {
1969 return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1970 }
1971 }
1972
1973 #define UPDATE_SSA_TYPE(_type, _var) \
1974 do { \
1975 uint32_t __type = (_type) & ~MAY_BE_GUARD; \
1976 int __var = (_var); \
1977 if (__type & MAY_BE_REF) { \
1978 __type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; \
1979 } \
1980 if (__var >= 0) { \
1981 zend_ssa_var *__ssa_var = &ssa_vars[__var]; \
1982 if (__ssa_var->var < op_array->num_args) { \
1983 if (__type & MAY_BE_RC1) { \
1984 /* TODO: may be captured by exception backtreace */ \
1985 __type |= MAY_BE_RCN; \
1986 } \
1987 } \
1988 if (__ssa_var->var < op_array->last_var) { \
1989 if (__type & (MAY_BE_REF|MAY_BE_RCN)) { \
1990 __type |= MAY_BE_RC1 | MAY_BE_RCN; \
1991 } \
1992 if ((__type & MAY_BE_RC1) && (__type & MAY_BE_STRING)) {\
1993 /* TODO: support for array keys and ($str . "")*/ \
1994 __type |= MAY_BE_RCN; \
1995 } \
1996 if (__ssa_var->alias) { \
1997 __type |= get_ssa_alias_types(__ssa_var->alias); \
1998 } \
1999 } \
2000 if (ssa_var_info[__var].type != __type) { \
2001 ZEND_ASSERT(ssa_opcodes != NULL || \
2002 __ssa_var->var >= op_array->last_var || \
2003 (ssa_var_info[__var].type & MAY_BE_REF) \
2004 == (__type & MAY_BE_REF)); \
2005 if (ssa_var_info[__var].type & ~__type) { \
2006 emit_type_narrowing_warning(op_array, ssa, __var); \
2007 return FAILURE; \
2008 } \
2009 ssa_var_info[__var].type = __type; \
2010 if (update_worklist) { \
2011 add_usages(op_array, ssa, worklist, __var); \
2012 } \
2013 } \
2014 /*zend_bitset_excl(worklist, var);*/ \
2015 } \
2016 } while (0)
2017
2018 #define UPDATE_SSA_OBJ_TYPE(_ce, _is_instanceof, var) \
2019 do { \
2020 if (var >= 0) { \
2021 if (ssa_var_info[var].ce != (_ce) || \
2022 ssa_var_info[var].is_instanceof != (_is_instanceof)) { \
2023 ssa_var_info[var].ce = (_ce); \
2024 ssa_var_info[var].is_instanceof = (_is_instanceof); \
2025 if (update_worklist) { \
2026 add_usages(op_array, ssa, worklist, var); \
2027 } \
2028 } \
2029 /*zend_bitset_excl(worklist, var);*/ \
2030 } \
2031 } while (0)
2032
2033 #define COPY_SSA_OBJ_TYPE(from_var, to_var) do { \
2034 if ((from_var) >= 0 && (ssa_var_info[(from_var)].type & MAY_BE_OBJECT) \
2035 && ssa_var_info[(from_var)].ce && !(ssa_var_info[(to_var)].type & MAY_BE_REF)) { \
2036 UPDATE_SSA_OBJ_TYPE(ssa_var_info[(from_var)].ce, \
2037 ssa_var_info[(from_var)].is_instanceof, (to_var)); \
2038 } else { \
2039 UPDATE_SSA_OBJ_TYPE(NULL, 0, (to_var)); \
2040 } \
2041 } while (0)
2042
add_usages(const zend_op_array * op_array,zend_ssa * ssa,zend_bitset worklist,int var)2043 static void add_usages(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset worklist, int var)
2044 {
2045 if (ssa->vars[var].phi_use_chain) {
2046 zend_ssa_phi *p = ssa->vars[var].phi_use_chain;
2047 do {
2048 zend_bitset_incl(worklist, p->ssa_var);
2049 p = zend_ssa_next_use_phi(ssa, var, p);
2050 } while (p);
2051 }
2052 if (ssa->vars[var].use_chain >= 0) {
2053 int use = ssa->vars[var].use_chain;
2054 zend_ssa_op *op;
2055
2056 do {
2057 op = ssa->ops + use;
2058 if (op->result_def >= 0) {
2059 zend_bitset_incl(worklist, op->result_def);
2060 }
2061 if (op->op1_def >= 0) {
2062 zend_bitset_incl(worklist, op->op1_def);
2063 }
2064 if (op->op2_def >= 0) {
2065 zend_bitset_incl(worklist, op->op2_def);
2066 }
2067 if (op_array->opcodes[use].opcode == ZEND_OP_DATA) {
2068 op--;
2069 if (op->result_def >= 0) {
2070 zend_bitset_incl(worklist, op->result_def);
2071 }
2072 if (op->op1_def >= 0) {
2073 zend_bitset_incl(worklist, op->op1_def);
2074 }
2075 if (op->op2_def >= 0) {
2076 zend_bitset_incl(worklist, op->op2_def);
2077 }
2078 } else if (use + 1 < op_array->last
2079 && op_array->opcodes[use + 1].opcode == ZEND_OP_DATA) {
2080 op++;
2081 if (op->result_def >= 0) {
2082 zend_bitset_incl(worklist, op->result_def);
2083 }
2084 if (op->op1_def >= 0) {
2085 zend_bitset_incl(worklist, op->op1_def);
2086 }
2087 if (op->op2_def >= 0) {
2088 zend_bitset_incl(worklist, op->op2_def);
2089 }
2090 }
2091 use = zend_ssa_next_use(ssa->ops, var, use);
2092 } while (use >= 0);
2093 }
2094 }
2095
emit_type_narrowing_warning(const zend_op_array * op_array,zend_ssa * ssa,int var)2096 static void emit_type_narrowing_warning(const zend_op_array *op_array, zend_ssa *ssa, int var)
2097 {
2098 int def_op_num = ssa->vars[var].definition;
2099 const zend_op *def_opline = def_op_num >= 0 ? &op_array->opcodes[def_op_num] : NULL;
2100 const char *def_op_name = def_opline ? zend_get_opcode_name(def_opline->opcode) : "PHI";
2101 uint32_t lineno = def_opline ? def_opline->lineno : 0;
2102 zend_error_at(
2103 E_WARNING, op_array->filename, lineno,
2104 "Narrowing occurred during type inference of %s. Please file a bug report on https://github.com/php/php-src/issues", def_op_name);
2105 }
2106
zend_array_element_type(uint32_t t1,zend_uchar op_type,int write,int insert)2107 ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert)
2108 {
2109 uint32_t tmp = 0;
2110
2111 if (t1 & MAY_BE_OBJECT) {
2112 if (!write) {
2113 /* can't be REF because of ZVAL_COPY_DEREF() usage */
2114 tmp |= MAY_BE_ANY | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2115 } else {
2116 tmp |= MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2117 }
2118 if (write) {
2119 tmp |= MAY_BE_INDIRECT;
2120 }
2121 }
2122 if (t1 & MAY_BE_ARRAY) {
2123 if (insert) {
2124 tmp |= MAY_BE_NULL;
2125 } else {
2126 tmp |= MAY_BE_NULL | ((t1 & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
2127 if (tmp & MAY_BE_ARRAY) {
2128 tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2129 }
2130 if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2131 if (!write) {
2132 /* can't be REF because of ZVAL_COPY_DEREF() usage */
2133 tmp |= MAY_BE_RCN;
2134 if ((op_type & (IS_VAR|IS_TMP_VAR)) && (t1 & MAY_BE_RC1)) {
2135 tmp |= MAY_BE_RC1;
2136 }
2137 } else if (t1 & MAY_BE_ARRAY_OF_REF) {
2138 tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
2139 } else {
2140 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2141 }
2142 }
2143 }
2144 if (write) {
2145 tmp |= MAY_BE_INDIRECT;
2146 }
2147 }
2148 if (t1 & MAY_BE_STRING) {
2149 tmp |= MAY_BE_STRING | MAY_BE_RC1;
2150 if (write) {
2151 tmp |= MAY_BE_NULL;
2152 }
2153 }
2154 if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2155 tmp |= MAY_BE_NULL;
2156 if (write) {
2157 tmp |= MAY_BE_INDIRECT;
2158 }
2159 }
2160 if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
2161 if (!write) {
2162 tmp |= MAY_BE_NULL;
2163 }
2164 }
2165 return tmp;
2166 }
2167
assign_dim_array_result_type(uint32_t arr_type,uint32_t dim_type,uint32_t value_type,zend_uchar dim_op_type)2168 static uint32_t assign_dim_array_result_type(
2169 uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) {
2170 uint32_t tmp = 0;
2171 /* Only add key type if we have a value type. We want to maintain the invariant that a
2172 * key type exists iff a value type exists even in dead code that may use empty types. */
2173 if (value_type & (MAY_BE_ANY|MAY_BE_UNDEF)) {
2174 if (value_type & MAY_BE_UNDEF) {
2175 value_type |= MAY_BE_NULL;
2176 }
2177 if (dim_op_type == IS_UNUSED) {
2178 if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2179 tmp |= MAY_BE_ARRAY_PACKED;
2180 }
2181 tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2182 } else {
2183 if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
2184 if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2185 tmp |= MAY_BE_ARRAY_PACKED;
2186 }
2187 tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2188 }
2189 if (dim_type & MAY_BE_STRING) {
2190 tmp |= MAY_BE_ARRAY_KEY_STRING;
2191 if (dim_op_type != IS_CONST) {
2192 // FIXME: numeric string
2193 if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2194 tmp |= MAY_BE_ARRAY_PACKED;
2195 }
2196 tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
2197 }
2198 }
2199 if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
2200 tmp |= MAY_BE_ARRAY_KEY_STRING;
2201 }
2202 }
2203 }
2204 /* Only add value type if we have a key type. It might be that the key type is illegal
2205 * for arrays. */
2206 if (tmp & MAY_BE_ARRAY_KEY_ANY) {
2207 tmp |= (value_type & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
2208 }
2209 return tmp;
2210 }
2211
assign_dim_result_type(uint32_t arr_type,uint32_t dim_type,uint32_t value_type,zend_uchar dim_op_type)2212 static uint32_t assign_dim_result_type(
2213 uint32_t arr_type, uint32_t dim_type, uint32_t value_type, zend_uchar dim_op_type) {
2214 uint32_t tmp = arr_type & ~(MAY_BE_RC1|MAY_BE_RCN);
2215
2216 if (arr_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
2217 tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
2218 tmp |= MAY_BE_ARRAY|MAY_BE_RC1;
2219 }
2220 if (tmp & (MAY_BE_ARRAY|MAY_BE_STRING)) {
2221 tmp |= MAY_BE_RC1;
2222 }
2223 if (tmp & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2224 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2225 }
2226 if (tmp & MAY_BE_ARRAY) {
2227 tmp |= assign_dim_array_result_type(arr_type, dim_type, value_type, dim_op_type);
2228 }
2229 return tmp;
2230 }
2231
2232 /* For binary ops that have compound assignment operators */
binary_op_result_type(zend_ssa * ssa,zend_uchar opcode,uint32_t t1,uint32_t t2,int result_var,zend_long optimization_level)2233 static uint32_t binary_op_result_type(
2234 zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, int result_var,
2235 zend_long optimization_level) {
2236 uint32_t tmp = 0;
2237 uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
2238 uint32_t t2_type = (t2 & MAY_BE_ANY) | (t2 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
2239
2240 if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
2241 /* Handle potentially overloaded operators.
2242 * This could be made more precise by checking the class type, if known. */
2243 if ((t1_type & MAY_BE_OBJECT) || (t2_type & MAY_BE_OBJECT)) {
2244 /* This is somewhat GMP specific. */
2245 tmp |= MAY_BE_OBJECT | MAY_BE_FALSE | MAY_BE_RC1;
2246 }
2247 }
2248
2249 switch (opcode) {
2250 case ZEND_ADD:
2251 if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
2252 if (result_var < 0 ||
2253 !ssa->var_info[result_var].has_range ||
2254 ssa->var_info[result_var].range.underflow ||
2255 ssa->var_info[result_var].range.overflow) {
2256 /* may overflow */
2257 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2258 } else {
2259 tmp |= MAY_BE_LONG;
2260 }
2261 } else if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2262 tmp |= MAY_BE_DOUBLE;
2263 } else if (t1_type == MAY_BE_ARRAY && t2_type == MAY_BE_ARRAY) {
2264 tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
2265 tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2266 tmp |= t2 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2267 } else {
2268 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2269 if ((t1_type & MAY_BE_ARRAY) && (t2_type & MAY_BE_ARRAY)) {
2270 tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
2271 tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2272 tmp |= t2 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
2273 }
2274 }
2275 break;
2276 case ZEND_SUB:
2277 case ZEND_MUL:
2278 if (t1_type == MAY_BE_LONG && t2_type == MAY_BE_LONG) {
2279 if (result_var < 0 ||
2280 !ssa->var_info[result_var].has_range ||
2281 ssa->var_info[result_var].range.underflow ||
2282 ssa->var_info[result_var].range.overflow) {
2283 /* may overflow */
2284 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2285 } else {
2286 tmp |= MAY_BE_LONG;
2287 }
2288 } else if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2289 tmp |= MAY_BE_DOUBLE;
2290 } else {
2291 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2292 }
2293 break;
2294 case ZEND_DIV:
2295 case ZEND_POW:
2296 if (t1_type == MAY_BE_DOUBLE || t2_type == MAY_BE_DOUBLE) {
2297 tmp |= MAY_BE_DOUBLE;
2298 } else {
2299 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2300 }
2301 /* Division by zero results in Inf/-Inf/Nan (double), so it doesn't need any special
2302 * handling */
2303 break;
2304 case ZEND_MOD:
2305 tmp |= MAY_BE_LONG;
2306 /* Division by zero results in an exception, so it doesn't need any special handling */
2307 break;
2308 case ZEND_BW_OR:
2309 case ZEND_BW_AND:
2310 case ZEND_BW_XOR:
2311 if ((t1_type & MAY_BE_STRING) && (t2_type & MAY_BE_STRING)) {
2312 tmp |= MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2313 }
2314 if ((t1_type & ~MAY_BE_STRING) || (t2_type & ~MAY_BE_STRING)) {
2315 tmp |= MAY_BE_LONG;
2316 }
2317 break;
2318 case ZEND_SL:
2319 case ZEND_SR:
2320 tmp |= MAY_BE_LONG;
2321 break;
2322 case ZEND_CONCAT:
2323 case ZEND_FAST_CONCAT:
2324 /* TODO: +MAY_BE_OBJECT ??? */
2325 tmp = MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2326 break;
2327 EMPTY_SWITCH_DEFAULT_CASE()
2328 }
2329 return tmp;
2330 }
2331
zend_convert_type_declaration_mask(uint32_t type_mask)2332 static uint32_t zend_convert_type_declaration_mask(uint32_t type_mask) {
2333 uint32_t result_mask = type_mask & MAY_BE_ANY;
2334 if (type_mask & MAY_BE_VOID) {
2335 result_mask |= MAY_BE_NULL;
2336 }
2337 if (type_mask & MAY_BE_CALLABLE) {
2338 result_mask |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
2339 }
2340 if (type_mask & MAY_BE_ITERABLE) {
2341 result_mask |= MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
2342 }
2343 if (type_mask & MAY_BE_STATIC) {
2344 result_mask |= MAY_BE_OBJECT;
2345 }
2346 if (type_mask & MAY_BE_ARRAY) {
2347 result_mask |= MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
2348 }
2349 return result_mask;
2350 }
2351
zend_convert_type(const zend_script * script,zend_type type,zend_class_entry ** pce)2352 static uint32_t zend_convert_type(const zend_script *script, zend_type type, zend_class_entry **pce)
2353 {
2354 if (pce) {
2355 *pce = NULL;
2356 }
2357
2358 if (!ZEND_TYPE_IS_SET(type)) {
2359 return MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_RC1|MAY_BE_RCN;
2360 }
2361
2362 uint32_t tmp = zend_convert_type_declaration_mask(ZEND_TYPE_PURE_MASK(type));
2363 if (ZEND_TYPE_IS_COMPLEX(type)) {
2364 tmp |= MAY_BE_OBJECT;
2365 if (pce) {
2366 /* As we only have space to store one CE,
2367 * we use a plain object type for class unions. */
2368 if (ZEND_TYPE_HAS_NAME(type)) {
2369 zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(type));
2370 *pce = zend_optimizer_get_class_entry(script, lcname);
2371 zend_string_release_ex(lcname, 0);
2372 }
2373 }
2374 }
2375 if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2376 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2377 }
2378 return tmp;
2379 }
2380
zend_fetch_arg_info_type(const zend_script * script,zend_arg_info * arg_info,zend_class_entry ** pce)2381 ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
2382 {
2383 return zend_convert_type(script, arg_info->type, pce);
2384 }
2385
lookup_prop_info(zend_class_entry * ce,zend_string * name,zend_class_entry * scope)2386 static zend_property_info *lookup_prop_info(zend_class_entry *ce, zend_string *name, zend_class_entry *scope) {
2387 zend_property_info *prop_info;
2388
2389 /* If the class is linked, reuse the precise runtime logic. */
2390 if ((ce->ce_flags & ZEND_ACC_LINKED)
2391 && (!scope || (scope->ce_flags & ZEND_ACC_LINKED))) {
2392 zend_class_entry *prev_scope = EG(fake_scope);
2393 EG(fake_scope) = scope;
2394 prop_info = zend_get_property_info(ce, name, 1);
2395 EG(fake_scope) = prev_scope;
2396 if (prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO) {
2397 return prop_info;
2398 }
2399 return NULL;
2400 }
2401
2402 /* Otherwise, handle only some safe cases */
2403 prop_info = zend_hash_find_ptr(&ce->properties_info, name);
2404 if (prop_info &&
2405 ((prop_info->ce == scope) ||
2406 (!scope && (prop_info->flags & ZEND_ACC_PUBLIC)))
2407 ) {
2408 return prop_info;
2409 }
2410 return NULL;
2411 }
2412
zend_fetch_prop_info(const zend_op_array * op_array,zend_ssa * ssa,zend_op * opline,zend_ssa_op * ssa_op)2413 static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op)
2414 {
2415 zend_property_info *prop_info = NULL;
2416 if (opline->op2_type == IS_CONST) {
2417 zend_class_entry *ce = NULL;
2418
2419 if (opline->op1_type == IS_UNUSED && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
2420 ce = op_array->scope;
2421 } else if (ssa_op->op1_use >= 0) {
2422 ce = ssa->var_info[ssa_op->op1_use].ce;
2423 }
2424 if (ce) {
2425 prop_info = lookup_prop_info(ce,
2426 Z_STR_P(CRT_CONSTANT(opline->op2)),
2427 op_array->scope);
2428 if (prop_info && (prop_info->flags & ZEND_ACC_STATIC)) {
2429 prop_info = NULL;
2430 }
2431 }
2432 }
2433 return prop_info;
2434 }
2435
zend_fetch_static_prop_info(const zend_script * script,const zend_op_array * op_array,zend_ssa * ssa,zend_op * opline)2436 static zend_property_info *zend_fetch_static_prop_info(const zend_script *script, const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline)
2437 {
2438 zend_property_info *prop_info = NULL;
2439 if (opline->op1_type == IS_CONST) {
2440 zend_class_entry *ce = NULL;
2441 if (opline->op2_type == IS_UNUSED) {
2442 int fetch_type = opline->op2.num & ZEND_FETCH_CLASS_MASK;
2443 switch (fetch_type) {
2444 case ZEND_FETCH_CLASS_SELF:
2445 case ZEND_FETCH_CLASS_STATIC:
2446 /* We enforce that static property types cannot change during inheritance, so
2447 * handling static the same way as self here is legal. */
2448 ce = op_array->scope;
2449 break;
2450 case ZEND_FETCH_CLASS_PARENT:
2451 if (op_array->scope && (op_array->scope->ce_flags & ZEND_ACC_LINKED)) {
2452 ce = op_array->scope->parent;
2453 }
2454 break;
2455 }
2456 } else if (opline->op2_type == IS_CONST) {
2457 zval *zv = CRT_CONSTANT(opline->op2);
2458 ce = zend_optimizer_get_class_entry(script, Z_STR_P(zv + 1));
2459 }
2460
2461 if (ce) {
2462 zval *zv = CRT_CONSTANT(opline->op1);
2463 prop_info = lookup_prop_info(ce, Z_STR_P(zv), op_array->scope);
2464 if (prop_info && !(prop_info->flags & ZEND_ACC_STATIC)) {
2465 prop_info = NULL;
2466 }
2467 }
2468 }
2469 return prop_info;
2470 }
2471
zend_fetch_prop_type(const zend_script * script,zend_property_info * prop_info,zend_class_entry ** pce)2472 static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_info *prop_info, zend_class_entry **pce)
2473 {
2474 if (!prop_info) {
2475 if (pce) {
2476 *pce = NULL;
2477 }
2478 return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN;
2479 }
2480
2481 return zend_convert_type(script, prop_info->type, pce);
2482 }
2483
result_may_be_separated(zend_ssa * ssa,zend_ssa_op * ssa_op)2484 static bool result_may_be_separated(zend_ssa *ssa, zend_ssa_op *ssa_op)
2485 {
2486 int tmp_var = ssa_op->result_def;
2487
2488 if (ssa->vars[tmp_var].use_chain >= 0
2489 && !ssa->vars[tmp_var].phi_use_chain) {
2490 zend_ssa_op *use_op = &ssa->ops[ssa->vars[tmp_var].use_chain];
2491
2492 /* TODO: analize instructions between ssa_op and use_op */
2493 if (use_op == ssa_op + 1) {
2494 if ((use_op->op1_use == tmp_var && use_op->op1_use_chain < 0)
2495 || (use_op->op2_use == tmp_var && use_op->op2_use_chain < 0)) {
2496 return 0;
2497 }
2498 }
2499 }
2500 return 1;
2501 }
2502
_zend_update_type_info(const zend_op_array * op_array,zend_ssa * ssa,const zend_script * script,zend_bitset worklist,zend_op * opline,zend_ssa_op * ssa_op,const zend_op ** ssa_opcodes,zend_long optimization_level,bool update_worklist)2503 static zend_always_inline int _zend_update_type_info(
2504 const zend_op_array *op_array,
2505 zend_ssa *ssa,
2506 const zend_script *script,
2507 zend_bitset worklist,
2508 zend_op *opline,
2509 zend_ssa_op *ssa_op,
2510 const zend_op **ssa_opcodes,
2511 zend_long optimization_level,
2512 bool update_worklist)
2513 {
2514 uint32_t t1, t2;
2515 uint32_t tmp, orig;
2516 zend_ssa_var *ssa_vars = ssa->vars;
2517 zend_ssa_var_info *ssa_var_info = ssa->var_info;
2518 zend_class_entry *ce;
2519 int j;
2520
2521 if (opline->opcode == ZEND_OP_DATA) {
2522 opline--;
2523 ssa_op--;
2524 }
2525
2526 t1 = OP1_INFO();
2527 t2 = OP2_INFO();
2528
2529 /* If one of the operands cannot have any type, this means the operand derives from
2530 * unreachable code. Propagate the empty result early, so that that the following
2531 * code may assume that operands have at least one type. */
2532 if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
2533 || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
2534 || (ssa_op->result_use >= 0 && !(RES_USE_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS)))) {
2535 tmp = 0;
2536 if (ssa_op->result_def >= 0 && !(ssa_var_info[ssa_op->result_def].type & MAY_BE_REF)) {
2537 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2538 }
2539 if (ssa_op->op1_def >= 0 && !(ssa_var_info[ssa_op->op1_def].type & MAY_BE_REF)) {
2540 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2541 }
2542 if (ssa_op->op2_def >= 0 && !(ssa_var_info[ssa_op->op2_def].type & MAY_BE_REF)) {
2543 UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
2544 }
2545 return 1;
2546 }
2547
2548 switch (opline->opcode) {
2549 case ZEND_ADD:
2550 case ZEND_SUB:
2551 case ZEND_MUL:
2552 case ZEND_DIV:
2553 case ZEND_POW:
2554 case ZEND_MOD:
2555 case ZEND_BW_OR:
2556 case ZEND_BW_AND:
2557 case ZEND_BW_XOR:
2558 case ZEND_SL:
2559 case ZEND_SR:
2560 case ZEND_CONCAT:
2561 tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_op->result_def, optimization_level);
2562 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2563 break;
2564 case ZEND_BW_NOT:
2565 tmp = 0;
2566 if (t1 & MAY_BE_STRING) {
2567 tmp |= MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
2568 }
2569 if (t1 & (MAY_BE_ANY-MAY_BE_STRING)) {
2570 tmp |= MAY_BE_LONG;
2571 }
2572 if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
2573 if (t1 & MAY_BE_OBJECT) {
2574 /* Potentially overloaded operator. */
2575 tmp |= MAY_BE_OBJECT | MAY_BE_RC1;
2576 }
2577 }
2578 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2579 break;
2580 case ZEND_BEGIN_SILENCE:
2581 UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def);
2582 break;
2583 case ZEND_BOOL_NOT:
2584 case ZEND_BOOL_XOR:
2585 case ZEND_IS_IDENTICAL:
2586 case ZEND_IS_NOT_IDENTICAL:
2587 case ZEND_IS_EQUAL:
2588 case ZEND_IS_NOT_EQUAL:
2589 case ZEND_IS_SMALLER:
2590 case ZEND_IS_SMALLER_OR_EQUAL:
2591 case ZEND_INSTANCEOF:
2592 case ZEND_JMPZ_EX:
2593 case ZEND_JMPNZ_EX:
2594 case ZEND_CASE:
2595 case ZEND_CASE_STRICT:
2596 case ZEND_BOOL:
2597 case ZEND_ISSET_ISEMPTY_CV:
2598 case ZEND_ISSET_ISEMPTY_VAR:
2599 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
2600 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
2601 case ZEND_ISSET_ISEMPTY_STATIC_PROP:
2602 case ZEND_ASSERT_CHECK:
2603 case ZEND_IN_ARRAY:
2604 case ZEND_ARRAY_KEY_EXISTS:
2605 UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def);
2606 break;
2607 case ZEND_CAST:
2608 if (ssa_op->op1_def >= 0) {
2609 tmp = t1;
2610 if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) &&
2611 (opline->extended_value == IS_ARRAY ||
2612 opline->extended_value == IS_OBJECT)) {
2613 tmp |= MAY_BE_RCN;
2614 } else if ((t1 & MAY_BE_STRING) &&
2615 opline->extended_value == IS_STRING) {
2616 tmp |= MAY_BE_RCN;
2617 }
2618 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2619 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2620 }
2621 tmp = 1 << opline->extended_value;
2622 if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2623 if ((tmp & MAY_BE_ANY) == (t1 & MAY_BE_ANY)) {
2624 tmp |= (t1 & MAY_BE_RC1) | MAY_BE_RCN;
2625 } else if ((opline->extended_value == IS_ARRAY ||
2626 opline->extended_value == IS_OBJECT) &&
2627 (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
2628 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2629 } else if (opline->extended_value == IS_STRING &&
2630 (t1 & (MAY_BE_STRING|MAY_BE_OBJECT))) {
2631 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2632 } else {
2633 tmp |= MAY_BE_RC1;
2634 if (opline->extended_value == IS_ARRAY
2635 && (t1 & (MAY_BE_UNDEF|MAY_BE_NULL))) {
2636 tmp |= MAY_BE_RCN;
2637 }
2638 }
2639 }
2640 if (opline->extended_value == IS_ARRAY) {
2641 if (t1 & MAY_BE_ARRAY) {
2642 tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF);
2643 }
2644 if (t1 & MAY_BE_OBJECT) {
2645 tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2646 } else if (t1 & (MAY_BE_ANY - MAY_BE_NULL)) {
2647 tmp |= ((t1 & (MAY_BE_ANY - MAY_BE_NULL)) << MAY_BE_ARRAY_SHIFT) | ((t1 & MAY_BE_NULL) ? MAY_BE_ARRAY_KEY_LONG : MAY_BE_ARRAY_PACKED);
2648 }
2649 }
2650 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2651 break;
2652 case ZEND_QM_ASSIGN:
2653 case ZEND_JMP_SET:
2654 case ZEND_COALESCE:
2655 case ZEND_COPY_TMP:
2656 if (ssa_op->op1_def >= 0) {
2657 tmp = t1;
2658 if (t1 & (MAY_BE_RC1|MAY_BE_REF)) {
2659 tmp |= MAY_BE_RCN;
2660 }
2661 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2662 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2663 }
2664 tmp = t1 & ~(MAY_BE_UNDEF|MAY_BE_REF);
2665 if (t1 & MAY_BE_UNDEF) {
2666 tmp |= MAY_BE_NULL;
2667 }
2668 if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2669 tmp |= (t1 & (MAY_BE_RC1|MAY_BE_RCN));
2670 if (opline->opcode == ZEND_COPY_TMP || opline->op1_type == IS_CV) {
2671 tmp |= MAY_BE_RCN;
2672 }
2673 }
2674 if (opline->opcode == ZEND_COALESCE || opline->opcode == ZEND_JMP_SET) {
2675 /* COALESCE and JMP_SET result can't be null */
2676 tmp &= ~MAY_BE_NULL;
2677 if (opline->opcode == ZEND_JMP_SET) {
2678 /* JMP_SET result can't be false either */
2679 tmp &= ~MAY_BE_FALSE;
2680 }
2681 }
2682 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2683 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
2684 break;
2685 case ZEND_JMP_NULL:
2686 if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EXPR) {
2687 tmp = MAY_BE_NULL;
2688 } else if (opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_ISSET) {
2689 tmp = MAY_BE_FALSE;
2690 } else {
2691 ZEND_ASSERT(opline->extended_value == ZEND_SHORT_CIRCUITING_CHAIN_EMPTY);
2692 tmp = MAY_BE_TRUE;
2693 }
2694 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2695 break;
2696 case ZEND_ASSIGN_OP:
2697 case ZEND_ASSIGN_DIM_OP:
2698 case ZEND_ASSIGN_OBJ_OP:
2699 case ZEND_ASSIGN_STATIC_PROP_OP:
2700 {
2701 zend_property_info *prop_info = NULL;
2702 orig = 0;
2703 tmp = 0;
2704 if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2705 prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
2706 orig = t1;
2707 t1 = zend_fetch_prop_type(script, prop_info, NULL);
2708 t2 = OP1_DATA_INFO();
2709 } else if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2710 if (t1 & MAY_BE_ARRAY_OF_REF) {
2711 tmp |= MAY_BE_REF;
2712 }
2713 orig = t1;
2714 t1 = zend_array_element_type(t1, opline->op1_type, 1, 0);
2715 t2 = OP1_DATA_INFO();
2716 } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2717 prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline);
2718 t1 = zend_fetch_prop_type(script, prop_info, NULL);
2719 t2 = OP1_DATA_INFO();
2720 } else {
2721 if (t1 & MAY_BE_REF) {
2722 tmp |= MAY_BE_REF;
2723 }
2724 }
2725
2726 tmp |= binary_op_result_type(
2727 ssa, opline->extended_value, t1, t2,
2728 opline->opcode == ZEND_ASSIGN_OP ? ssa_op->op1_def : -1, optimization_level);
2729 if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) {
2730 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2731 }
2732 if (tmp & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2733 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2734 }
2735
2736 if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2737 if (opline->op1_type == IS_CV) {
2738 orig = assign_dim_result_type(orig, OP2_INFO(), tmp, opline->op2_type);
2739 UPDATE_SSA_TYPE(orig, ssa_op->op1_def);
2740 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2741 }
2742 } else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2743 if (opline->op1_type == IS_CV) {
2744 orig = (orig & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
2745 UPDATE_SSA_TYPE(orig, ssa_op->op1_def);
2746 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2747 }
2748 } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2749 /* Nothing to do */
2750 } else {
2751 if (opline->opcode == ZEND_ASSIGN_OP && ssa_op->result_def >= 0 && (tmp & MAY_BE_RC1)) {
2752 tmp |= MAY_BE_RCN;
2753 }
2754 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2755 }
2756 if (ssa_op->result_def >= 0) {
2757 ce = NULL;
2758 if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
2759 if (opline->op2_type == IS_UNUSED) {
2760 /* When appending to an array and the LONG_MAX key is already used
2761 * null will be returned. */
2762 tmp |= MAY_BE_NULL;
2763 }
2764 if (t2 & (MAY_BE_ARRAY | MAY_BE_OBJECT)) {
2765 /* Arrays and objects cannot be used as keys. */
2766 tmp |= MAY_BE_NULL;
2767 }
2768 if (t1 & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) {
2769 /* null and false are implicitly converted to array, anything else
2770 * results in a null return value. */
2771 tmp |= MAY_BE_NULL;
2772 }
2773 if (tmp & MAY_BE_REF) {
2774 /* Typed reference may cause auto conversion */
2775 tmp |= MAY_BE_ANY;
2776 }
2777 } else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
2778 /* The return value must also satisfy the property type */
2779 if (prop_info) {
2780 t1 = zend_fetch_prop_type(script, prop_info, &ce);
2781 if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG
2782 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) {
2783 /* DOUBLE may be auto-converted to LONG */
2784 tmp |= MAY_BE_LONG;
2785 tmp &= ~MAY_BE_DOUBLE;
2786 }
2787 tmp &= t1;
2788 }
2789 } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) {
2790 /* The return value must also satisfy the property type */
2791 if (prop_info) {
2792 t1 = zend_fetch_prop_type(script, prop_info, &ce);
2793 if ((t1 & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_LONG
2794 && (tmp & (MAY_BE_LONG|MAY_BE_DOUBLE)) == MAY_BE_DOUBLE) {
2795 /* DOUBLE may be auto-converted to LONG */
2796 tmp |= MAY_BE_LONG;
2797 tmp &= ~MAY_BE_DOUBLE;
2798 }
2799 tmp &= t1;
2800 }
2801 } else {
2802 if (tmp & MAY_BE_REF) {
2803 /* Typed reference may cause auto conversion */
2804 tmp |= MAY_BE_ANY;
2805 }
2806 }
2807 tmp &= ~MAY_BE_REF;
2808 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2809 if (ce) {
2810 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
2811 }
2812 }
2813 break;
2814 }
2815 case ZEND_PRE_INC:
2816 case ZEND_PRE_DEC:
2817 tmp = 0;
2818 if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2819 tmp |= MAY_BE_RC1;
2820 if (ssa_op->result_def >= 0) {
2821 tmp |= MAY_BE_RCN;
2822 }
2823 }
2824 if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
2825 if (!ssa_var_info[ssa_op->op1_use].has_range ||
2826 (opline->opcode == ZEND_PRE_DEC &&
2827 (ssa_var_info[ssa_op->op1_use].range.underflow ||
2828 ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) ||
2829 (opline->opcode == ZEND_PRE_INC &&
2830 (ssa_var_info[ssa_op->op1_use].range.overflow ||
2831 ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) {
2832 /* may overflow */
2833 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2834 } else {
2835 tmp |= MAY_BE_LONG;
2836 }
2837 } else {
2838 if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
2839 if (opline->opcode == ZEND_PRE_INC) {
2840 tmp |= MAY_BE_LONG;
2841 } else {
2842 tmp |= MAY_BE_NULL;
2843 }
2844 }
2845 if (t1 & MAY_BE_LONG) {
2846 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2847 }
2848 if (t1 & MAY_BE_DOUBLE) {
2849 tmp |= MAY_BE_DOUBLE;
2850 }
2851 if (t1 & MAY_BE_STRING) {
2852 tmp |= MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE;
2853 }
2854 tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT);
2855 }
2856 if (ssa_op->result_def >= 0) {
2857 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2858 }
2859 if (ssa_op->op1_def >= 0) {
2860 if (t1 & MAY_BE_REF) {
2861 tmp |= MAY_BE_REF;
2862 }
2863 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2864 }
2865 break;
2866 case ZEND_POST_INC:
2867 case ZEND_POST_DEC:
2868 if (ssa_op->result_def >= 0) {
2869 tmp = 0;
2870 if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2871 tmp |= MAY_BE_RC1|MAY_BE_RCN;
2872 }
2873 tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN);
2874 if (t1 & MAY_BE_UNDEF) {
2875 tmp |= MAY_BE_NULL;
2876 }
2877 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2878 }
2879 tmp = 0;
2880 if (t1 & MAY_BE_REF) {
2881 tmp |= MAY_BE_REF;
2882 }
2883 if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
2884 tmp |= MAY_BE_RC1;
2885 }
2886 if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
2887 if (!ssa_var_info[ssa_op->op1_use].has_range ||
2888 (opline->opcode == ZEND_POST_DEC &&
2889 (ssa_var_info[ssa_op->op1_use].range.underflow ||
2890 ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) ||
2891 (opline->opcode == ZEND_POST_INC &&
2892 (ssa_var_info[ssa_op->op1_use].range.overflow ||
2893 ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) {
2894 /* may overflow */
2895 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2896 } else {
2897 tmp |= MAY_BE_LONG;
2898 }
2899 } else {
2900 if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
2901 if (opline->opcode == ZEND_POST_INC) {
2902 tmp |= MAY_BE_LONG;
2903 } else {
2904 tmp |= MAY_BE_NULL;
2905 }
2906 }
2907 if (t1 & MAY_BE_LONG) {
2908 tmp |= MAY_BE_LONG | MAY_BE_DOUBLE;
2909 }
2910 if (t1 & MAY_BE_DOUBLE) {
2911 tmp |= MAY_BE_DOUBLE;
2912 }
2913 if (t1 & MAY_BE_STRING) {
2914 tmp |= MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE;
2915 }
2916 tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY);
2917 }
2918 if (ssa_op->op1_def >= 0) {
2919 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2920 }
2921 break;
2922 case ZEND_ASSIGN_DIM:
2923 if (opline->op1_type == IS_CV) {
2924 tmp = assign_dim_result_type(t1, t2, OP1_DATA_INFO(), opline->op2_type);
2925 tmp |= ssa->var_info[ssa_op->op1_def].type & (MAY_BE_ARRAY_PACKED|MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2926 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2927 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2928 }
2929 if (ssa_op->result_def >= 0) {
2930 tmp = 0;
2931 if (t1 & MAY_BE_STRING) {
2932 tmp |= MAY_BE_STRING | MAY_BE_NULL;
2933 }
2934 if (t1 & MAY_BE_OBJECT) {
2935 tmp |= (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF);
2936 }
2937 if (t1 & (MAY_BE_ARRAY|MAY_BE_FALSE|MAY_BE_NULL|MAY_BE_UNDEF)) {
2938 tmp |= (OP1_DATA_INFO() & (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF));
2939
2940 if (OP1_DATA_INFO() & MAY_BE_UNDEF) {
2941 tmp |= MAY_BE_NULL;
2942 }
2943 if (t1 & MAY_BE_ARRAY_OF_REF) {
2944 /* A scalar type conversion may occur when assigning to a typed reference. */
2945 tmp |= MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING;
2946 }
2947 }
2948 if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
2949 tmp |= MAY_BE_NULL;
2950 }
2951 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
2952 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2953 }
2954 if ((ssa_op+1)->op1_def >= 0) {
2955 opline++;
2956 ssa_op++;
2957 tmp = OP1_INFO();
2958 if (tmp & (MAY_BE_ANY | MAY_BE_REF)) {
2959 if (tmp & MAY_BE_RC1) {
2960 tmp |= MAY_BE_RCN;
2961 }
2962 }
2963 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2964 }
2965 break;
2966 case ZEND_ASSIGN_OBJ:
2967 if (opline->op1_type == IS_CV) {
2968 tmp = (t1 & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
2969 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2970 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
2971 }
2972 if (ssa_op->result_def >= 0) {
2973 // TODO: If there is no __set we might do better
2974 tmp = zend_fetch_prop_type(script,
2975 zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce);
2976 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2977 if (ce) {
2978 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
2979 }
2980 }
2981 if ((ssa_op+1)->op1_def >= 0) {
2982 opline++;
2983 ssa_op++;
2984 tmp = OP1_INFO();
2985 if (tmp & MAY_BE_RC1) {
2986 tmp |= MAY_BE_RCN;
2987 }
2988 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
2989 }
2990 break;
2991 case ZEND_ASSIGN_STATIC_PROP:
2992 if (ssa_op->result_def >= 0) {
2993 tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN;
2994 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
2995 }
2996 if ((ssa_op+1)->op1_def >= 0) {
2997 opline++;
2998 ssa_op++;
2999 tmp = OP1_INFO();
3000 if (tmp & MAY_BE_RC1) {
3001 tmp |= MAY_BE_RCN;
3002 }
3003 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3004 }
3005 break;
3006 case ZEND_PRE_INC_OBJ:
3007 case ZEND_PRE_DEC_OBJ:
3008 case ZEND_POST_INC_OBJ:
3009 case ZEND_POST_DEC_OBJ:
3010 if (opline->op1_type == IS_CV) {
3011 tmp = (t1 & (MAY_BE_REF|MAY_BE_OBJECT))|MAY_BE_RC1|MAY_BE_RCN;
3012 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3013 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3014 }
3015 if (ssa_op->result_def >= 0) {
3016 // TODO: ???
3017 tmp = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3018 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3019 }
3020 break;
3021 case ZEND_ASSIGN:
3022 if (ssa_op->op2_def >= 0) {
3023 tmp = t2;
3024 if (tmp & MAY_BE_RC1) {
3025 tmp |= MAY_BE_RCN;
3026 }
3027 UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3028 }
3029 tmp = t2 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
3030 if (t2 & MAY_BE_UNDEF) {
3031 tmp |= MAY_BE_NULL;
3032 }
3033 if (t1 & MAY_BE_REF) {
3034 tmp |= MAY_BE_REF;
3035 }
3036 if (t2 & MAY_BE_REF) {
3037 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3038 } else if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
3039 tmp |= t2 & (MAY_BE_RC1|MAY_BE_RCN);
3040 } else if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) {
3041 tmp |= MAY_BE_RCN;
3042 }
3043 if (RETURN_VALUE_USED(opline) && (tmp & MAY_BE_RC1)) {
3044 tmp |= MAY_BE_RCN;
3045 }
3046 if (ssa_op->op1_def >= 0) {
3047 if (ssa_var_info[ssa_op->op1_def].use_as_double) {
3048 tmp &= ~MAY_BE_LONG;
3049 tmp |= MAY_BE_DOUBLE;
3050 }
3051 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3052 COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op1_def);
3053 }
3054 if (ssa_op->result_def >= 0) {
3055 if (tmp & MAY_BE_REF) {
3056 /* A scalar type conversion may occur when assigning to a typed reference. */
3057 tmp &= ~MAY_BE_REF;
3058 tmp |= MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN;
3059 }
3060 if ((tmp & (MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_RCN) {
3061 /* refcount may be indirectly decremented. Make an exception if the result is used in the next instruction */
3062 if (!ssa_opcodes) {
3063 if (ssa->vars[ssa_op->result_def].use_chain < 0
3064 || opline + 1 != op_array->opcodes + ssa->vars[ssa_op->result_def].use_chain) {
3065 tmp |= MAY_BE_RC1;
3066 }
3067 } else {
3068 if (ssa->vars[ssa_op->result_def].use_chain < 0
3069 || opline + 1 != ssa_opcodes[ssa->vars[ssa_op->result_def].use_chain]) {
3070 tmp |= MAY_BE_RC1;
3071 }
3072 }
3073 }
3074 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3075 COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def);
3076 }
3077 break;
3078 case ZEND_ASSIGN_REF:
3079 // TODO: ???
3080 if (opline->op2_type == IS_CV) {
3081 tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3082 if (t2 & MAY_BE_UNDEF) {
3083 tmp |= MAY_BE_NULL;
3084 }
3085 UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3086 }
3087 if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) {
3088 tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
3089 } else {
3090 tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3091 }
3092 if (t2 & MAY_BE_UNDEF) {
3093 tmp |= MAY_BE_NULL;
3094 }
3095 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3096 if (ssa_op->result_def >= 0) {
3097 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3098 }
3099 break;
3100 case ZEND_ASSIGN_OBJ_REF:
3101 if (opline->op1_type == IS_CV) {
3102 tmp = t1;
3103 if (tmp & MAY_BE_OBJECT) {
3104 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3105 }
3106 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3107 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3108 }
3109
3110 t2 = OP1_DATA_INFO();
3111 if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) {
3112 tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
3113 } else {
3114 tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3115 }
3116 if (t2 & MAY_BE_UNDEF) {
3117 tmp |= MAY_BE_NULL;
3118 }
3119 if (ssa_op->result_def >= 0) {
3120 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3121 }
3122 if ((opline+1)->op1_type == IS_CV) {
3123 opline++;
3124 ssa_op++;
3125 tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3126 if (t2 & MAY_BE_UNDEF) {
3127 tmp |= MAY_BE_NULL;
3128 }
3129 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3130 }
3131 break;
3132 case ZEND_ASSIGN_STATIC_PROP_REF:
3133 if (ssa_op->result_def >= 0) {
3134 UPDATE_SSA_TYPE(MAY_BE_REF, ssa_op->result_def);
3135 }
3136 if ((opline+1)->op1_type == IS_CV) {
3137 opline++;
3138 ssa_op++;
3139 UPDATE_SSA_TYPE(MAY_BE_REF, ssa_op->op1_def);
3140 }
3141 break;
3142 case ZEND_BIND_GLOBAL:
3143 tmp = MAY_BE_REF | MAY_BE_ANY
3144 | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3145 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3146 break;
3147 case ZEND_BIND_STATIC:
3148 tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
3149 | ((opline->extended_value & ZEND_BIND_REF) ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN));
3150 if (opline->extended_value & ZEND_BIND_IMPLICIT) {
3151 tmp |= MAY_BE_UNDEF;
3152 }
3153 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3154 break;
3155 case ZEND_SEND_VAR:
3156 if (ssa_op->op1_def >= 0) {
3157 tmp = t1;
3158 if (t1 & (MAY_BE_RC1|MAY_BE_REF)) {
3159 tmp |= MAY_BE_RCN;
3160 }
3161 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3162 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3163 }
3164 break;
3165 case ZEND_BIND_LEXICAL:
3166 if (ssa_op->op2_def >= 0) {
3167 if (opline->extended_value & ZEND_BIND_REF) {
3168 tmp = t2 | MAY_BE_REF;
3169 } else {
3170 tmp = t2 & ~(MAY_BE_RC1|MAY_BE_RCN);
3171 if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) {
3172 tmp |= MAY_BE_RCN;
3173 }
3174 }
3175 UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3176 COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op2_def);
3177 }
3178 break;
3179 case ZEND_YIELD:
3180 if (ssa_op->op1_def >= 0) {
3181 if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
3182 tmp = t1 | MAY_BE_REF;
3183 } else {
3184 tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
3185 if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
3186 tmp |= MAY_BE_RCN;
3187 }
3188 }
3189 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3190 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3191 }
3192 if (ssa_op->result_def >= 0) {
3193 tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
3194 | MAY_BE_RC1 | MAY_BE_RCN;
3195 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3196 }
3197 break;
3198 case ZEND_SEND_VAR_EX:
3199 case ZEND_SEND_FUNC_ARG:
3200 if (ssa_op->op1_def >= 0) {
3201 tmp = (t1 & MAY_BE_UNDEF)|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3202 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3203 }
3204 break;
3205 case ZEND_SEND_REF:
3206 if (ssa_op->op1_def >= 0) {
3207 tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3208 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3209 }
3210 break;
3211 case ZEND_SEND_UNPACK:
3212 if (ssa_op->op1_def >= 0) {
3213 tmp = t1;
3214 if (t1 & MAY_BE_ARRAY) {
3215 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3216 if (t1 & MAY_BE_ARRAY_OF_ANY) {
3217 /* SEND_UNPACK may acquire references into the array */
3218 tmp |= MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3219 }
3220 }
3221 if (t1 & MAY_BE_OBJECT) {
3222 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3223 }
3224 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3225 }
3226 break;
3227 case ZEND_FAST_CONCAT:
3228 case ZEND_ROPE_INIT:
3229 case ZEND_ROPE_ADD:
3230 case ZEND_ROPE_END:
3231 UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def);
3232 break;
3233 case ZEND_RECV:
3234 case ZEND_RECV_INIT:
3235 case ZEND_RECV_VARIADIC:
3236 {
3237 /* Typehinting */
3238 zend_arg_info *arg_info = &op_array->arg_info[opline->op1.num-1];
3239
3240 ce = NULL;
3241 tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
3242 if (ZEND_ARG_SEND_MODE(arg_info)) {
3243 tmp |= MAY_BE_REF;
3244 ce = NULL;
3245 }
3246
3247 if (opline->opcode == ZEND_RECV_VARIADIC) {
3248 uint32_t elem_type = tmp & MAY_BE_REF
3249 ? MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF
3250 : (tmp & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT;
3251 tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|elem_type;
3252 ce = NULL;
3253 }
3254
3255 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3256 if (ce) {
3257 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3258 } else {
3259 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3260 }
3261 break;
3262 }
3263 case ZEND_DECLARE_ANON_CLASS:
3264 UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def);
3265 if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT(opline->op1)))) != NULL) {
3266 UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3267 }
3268 break;
3269 case ZEND_FETCH_CLASS:
3270 UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def);
3271 if (opline->op2_type == IS_UNUSED) {
3272 switch (opline->op1.num & ZEND_FETCH_CLASS_MASK) {
3273 case ZEND_FETCH_CLASS_SELF:
3274 if (op_array->scope) {
3275 UPDATE_SSA_OBJ_TYPE(op_array->scope, 0, ssa_op->result_def);
3276 } else {
3277 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3278 }
3279 break;
3280 case ZEND_FETCH_CLASS_PARENT:
3281 if (op_array->scope && op_array->scope->parent && (op_array->scope->ce_flags & ZEND_ACC_LINKED)) {
3282 UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_op->result_def);
3283 } else {
3284 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3285 }
3286 break;
3287 case ZEND_FETCH_CLASS_STATIC:
3288 default:
3289 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3290 break;
3291 }
3292 } else if (opline->op2_type == IS_CONST) {
3293 zval *zv = CRT_CONSTANT(opline->op2);
3294 if (Z_TYPE_P(zv) == IS_STRING) {
3295 ce = zend_optimizer_get_class_entry(script, Z_STR_P(zv+1));
3296 UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3297 } else {
3298 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3299 }
3300 } else {
3301 COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def);
3302 }
3303 break;
3304 case ZEND_NEW:
3305 tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT;
3306 if (opline->op1_type == IS_CONST &&
3307 (ce = zend_optimizer_get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) {
3308 UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def);
3309 } else if ((t1 & MAY_BE_CLASS) && ssa_op->op1_use >= 0 && ssa_var_info[ssa_op->op1_use].ce) {
3310 UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_op->op1_use].ce, ssa_var_info[ssa_op->op1_use].is_instanceof, ssa_op->result_def);
3311 } else {
3312 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3313 }
3314 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3315 break;
3316 case ZEND_CLONE:
3317 UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def);
3318 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
3319 break;
3320 case ZEND_INIT_ARRAY:
3321 case ZEND_ADD_ARRAY_ELEMENT:
3322 if (ssa_op->op1_def >= 0) {
3323 if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
3324 tmp = (MAY_BE_REF | t1) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3325 if (t1 & MAY_BE_UNDEF) {
3326 tmp |= MAY_BE_NULL;
3327 }
3328 } else if ((t1 & (MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_REF) {
3329 tmp = (MAY_BE_REF | t1) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
3330 if (t1 & MAY_BE_UNDEF) {
3331 tmp |= MAY_BE_NULL;
3332 }
3333 } else if (t1 & MAY_BE_REF) {
3334 tmp = (MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | t1);
3335 } else {
3336 tmp = t1;
3337 if (t1 & MAY_BE_RC1) {
3338 tmp |= MAY_BE_RCN;
3339 }
3340 }
3341 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3342 }
3343 if (ssa_op->result_def >= 0) {
3344 uint32_t arr_type;
3345 if (opline->opcode == ZEND_INIT_ARRAY) {
3346 arr_type = 0;
3347 } else {
3348 arr_type = RES_USE_INFO();
3349 }
3350 tmp = MAY_BE_RC1|MAY_BE_ARRAY|arr_type;
3351 if (opline->op1_type != IS_UNUSED
3352 && (opline->op2_type == IS_UNUSED
3353 || (t2 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_STRING)))) {
3354 tmp |= assign_dim_array_result_type(arr_type, t2, t1, opline->op2_type);
3355 if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
3356 tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3357 }
3358 }
3359 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3360 }
3361 break;
3362 case ZEND_ADD_ARRAY_UNPACK:
3363 tmp = ssa_var_info[ssa_op->result_use].type;
3364 ZEND_ASSERT(tmp & MAY_BE_ARRAY);
3365 tmp |= t1 & (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
3366 if (t1 & MAY_BE_OBJECT) {
3367 tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
3368 }
3369 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3370 break;
3371 case ZEND_UNSET_CV:
3372 tmp = MAY_BE_UNDEF;
3373 if (!op_array->function_name) {
3374 /* In global scope, we know nothing */
3375 tmp |= MAY_BE_REF;
3376 }
3377 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3378 break;
3379 case ZEND_UNSET_DIM:
3380 case ZEND_UNSET_OBJ:
3381 if (ssa_op->op1_def >= 0) {
3382 UPDATE_SSA_TYPE(t1, ssa_op->op1_def);
3383 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3384 }
3385 break;
3386 case ZEND_FE_RESET_R:
3387 case ZEND_FE_RESET_RW:
3388 if (ssa_op->op1_def >= 0) {
3389 tmp = t1;
3390 if (opline->opcode == ZEND_FE_RESET_RW) {
3391 tmp |= MAY_BE_REF;
3392 } else if (t1 & MAY_BE_RC1) {
3393 tmp |= MAY_BE_RCN;
3394 }
3395 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3396 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3397 }
3398 if (opline->opcode == ZEND_FE_RESET_RW) {
3399 //???
3400 tmp = MAY_BE_REF | (t1 & (MAY_BE_ARRAY | MAY_BE_OBJECT));
3401 } else {
3402 tmp = MAY_BE_RC1 | MAY_BE_RCN | (t1 & (MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF));
3403 }
3404 /* The result is set to UNDEF for invalid foreach inputs. */
3405 if ((t1 & (MAY_BE_ANY | MAY_BE_UNDEF)) & ~(MAY_BE_ARRAY | MAY_BE_OBJECT)) {
3406 tmp |= MAY_BE_UNDEF;
3407 }
3408 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3409 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def);
3410 break;
3411 case ZEND_FE_FETCH_R:
3412 case ZEND_FE_FETCH_RW:
3413 tmp = 0;
3414 if (opline->op2_type == IS_CV) {
3415 tmp = t2 & MAY_BE_REF;
3416 }
3417 if (t1 & MAY_BE_OBJECT) {
3418 if (opline->opcode == ZEND_FE_FETCH_RW) {
3419 tmp |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3420 } else {
3421 tmp |= MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3422 if (opline->op2_type != IS_CV) {
3423 tmp |= MAY_BE_REF;
3424 }
3425 }
3426 }
3427 if (t1 & MAY_BE_ARRAY) {
3428 if (opline->opcode == ZEND_FE_FETCH_RW) {
3429 tmp |= MAY_BE_REF | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3430 } else {
3431 tmp |= ((t1 & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
3432 if (tmp & MAY_BE_ARRAY) {
3433 tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3434 }
3435 if (t1 & MAY_BE_ARRAY_OF_REF) {
3436 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3437 if (opline->op2_type != IS_CV) {
3438 tmp |= MAY_BE_REF;
3439 }
3440 } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3441 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3442 }
3443 }
3444 }
3445 UPDATE_SSA_TYPE(tmp, ssa_op->op2_def);
3446 if (ssa_op->result_def >= 0) {
3447 tmp = (ssa_op->result_use >= 0) ? RES_USE_INFO() : 0;
3448 if (t1 & MAY_BE_OBJECT) {
3449 tmp |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3450 }
3451 if (t1 & MAY_BE_ARRAY) {
3452 if (t1 & MAY_BE_ARRAY_KEY_LONG) {
3453 tmp |= MAY_BE_LONG;
3454 }
3455 if (t1 & MAY_BE_ARRAY_KEY_STRING) {
3456 tmp |= MAY_BE_STRING | MAY_BE_RCN;
3457 }
3458 }
3459 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3460 }
3461 break;
3462 case ZEND_FETCH_DIM_R:
3463 case ZEND_FETCH_DIM_IS:
3464 case ZEND_FETCH_DIM_RW:
3465 case ZEND_FETCH_DIM_W:
3466 case ZEND_FETCH_DIM_UNSET:
3467 case ZEND_FETCH_DIM_FUNC_ARG:
3468 case ZEND_FETCH_LIST_R:
3469 case ZEND_FETCH_LIST_W:
3470 if (ssa_op->op1_def >= 0) {
3471 uint32_t key_type = 0;
3472 tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
3473 if (opline->opcode == ZEND_FETCH_DIM_W ||
3474 opline->opcode == ZEND_FETCH_DIM_RW ||
3475 opline->opcode == ZEND_FETCH_DIM_FUNC_ARG ||
3476 opline->opcode == ZEND_FETCH_LIST_W) {
3477 if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3478 if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) {
3479 tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
3480 }
3481 tmp |= MAY_BE_ARRAY | MAY_BE_RC1;
3482 }
3483 if (t1 & (MAY_BE_STRING|MAY_BE_ARRAY)) {
3484 tmp |= MAY_BE_RC1;
3485 if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG) {
3486 tmp |= t1 & MAY_BE_RCN;
3487 }
3488 }
3489 if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3490 tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
3491 }
3492 if (opline->op2_type == IS_UNUSED) {
3493 if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3494 key_type |= MAY_BE_ARRAY_PACKED;
3495 }
3496 if (t1 & MAY_BE_ARRAY) {
3497 key_type |= MAY_BE_HASH_ONLY(t1) ?
3498 MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3499 }
3500 } else {
3501 if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
3502 if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3503 key_type |= MAY_BE_ARRAY_PACKED;
3504 }
3505 if (t1 & MAY_BE_ARRAY) {
3506 key_type |= MAY_BE_HASH_ONLY(t1) ?
3507 MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3508 }
3509 }
3510 if (t2 & MAY_BE_STRING) {
3511 key_type |= MAY_BE_ARRAY_KEY_STRING;
3512 if (opline->op2_type != IS_CONST) {
3513 // FIXME: numeric string
3514 if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
3515 key_type |= MAY_BE_ARRAY_PACKED;
3516 }
3517 if (t1 & MAY_BE_ARRAY) {
3518 key_type |= MAY_BE_HASH_ONLY(t1) ?
3519 MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
3520 }
3521 }
3522 }
3523 if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
3524 key_type |= MAY_BE_ARRAY_KEY_STRING;
3525 }
3526 }
3527 } else if (opline->opcode == ZEND_FETCH_DIM_UNSET) {
3528 if (t1 & MAY_BE_ARRAY) {
3529 tmp |= MAY_BE_RC1;
3530 }
3531 if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
3532 tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
3533 }
3534 }
3535 if ((key_type & (MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING))
3536 && (opline->opcode == ZEND_FETCH_DIM_RW
3537 || opline->opcode == ZEND_FETCH_DIM_W
3538 || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3539 || opline->opcode == ZEND_FETCH_LIST_W)) {
3540 j = ssa_vars[ssa_op->result_def].use_chain;
3541 if (j < 0) {
3542 /* no uses */
3543 tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_NULL;
3544 }
3545 while (j >= 0) {
3546 zend_uchar opcode;
3547
3548 if (!ssa_opcodes) {
3549 if (j != (opline - op_array->opcodes) + 1) {
3550 /* Use must be in next opline */
3551 tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3552 break;
3553 }
3554 opcode = op_array->opcodes[j].opcode;
3555 } else {
3556 if (ssa_opcodes[j] != opline + 1) {
3557 /* Use must be in next opline */
3558 tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3559 break;
3560 }
3561 opcode = ssa_opcodes[j]->opcode;
3562 }
3563 switch (opcode) {
3564 case ZEND_FETCH_DIM_W:
3565 case ZEND_FETCH_DIM_RW:
3566 case ZEND_FETCH_DIM_FUNC_ARG:
3567 case ZEND_FETCH_LIST_W:
3568 case ZEND_ASSIGN_DIM:
3569 case ZEND_ASSIGN_DIM_OP:
3570 tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
3571 break;
3572 case ZEND_SEND_VAR_EX:
3573 case ZEND_SEND_FUNC_ARG:
3574 case ZEND_SEND_VAR_NO_REF:
3575 case ZEND_SEND_VAR_NO_REF_EX:
3576 case ZEND_SEND_REF:
3577 case ZEND_ASSIGN_REF:
3578 case ZEND_YIELD:
3579 case ZEND_INIT_ARRAY:
3580 case ZEND_ADD_ARRAY_ELEMENT:
3581 case ZEND_RETURN_BY_REF:
3582 case ZEND_VERIFY_RETURN_TYPE:
3583 case ZEND_MAKE_REF:
3584 case ZEND_FE_RESET_RW:
3585 tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3586 break;
3587 case ZEND_PRE_INC:
3588 case ZEND_PRE_DEC:
3589 case ZEND_POST_INC:
3590 case ZEND_POST_DEC:
3591 if (tmp & MAY_BE_ARRAY_OF_LONG) {
3592 /* may overflow */
3593 tmp |= key_type | MAY_BE_ARRAY_OF_DOUBLE;
3594 } else if (!(tmp & (MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE))) {
3595 tmp |= key_type | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
3596 }
3597 break;
3598 case ZEND_FETCH_OBJ_W:
3599 case ZEND_FETCH_OBJ_RW:
3600 case ZEND_FETCH_OBJ_FUNC_ARG:
3601 case ZEND_ASSIGN_OBJ:
3602 case ZEND_ASSIGN_OBJ_OP:
3603 case ZEND_ASSIGN_OBJ_REF:
3604 case ZEND_PRE_INC_OBJ:
3605 case ZEND_PRE_DEC_OBJ:
3606 case ZEND_POST_INC_OBJ:
3607 case ZEND_POST_DEC_OBJ:
3608 /* These will result in an error exception, unless the element
3609 * is already an object. */
3610 break;
3611 case ZEND_SEND_VAR:
3612 case ZEND_FETCH_DIM_R:
3613 /* This can occur if a DIM_FETCH_FUNC_ARG with UNUSED op2 is left
3614 * behind, because it can't be converted to DIM_FETCH_R. */
3615 break;
3616 EMPTY_SWITCH_DEFAULT_CASE()
3617 }
3618 j = zend_ssa_next_use(ssa->ops, ssa_op->result_def, j);
3619 if (j >= 0) {
3620 tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3621 break;
3622 }
3623 }
3624 }
3625 if (((tmp & MAY_BE_ARRAY) && (tmp & MAY_BE_ARRAY_KEY_ANY))
3626 || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
3627 || opline->opcode == ZEND_FETCH_DIM_R
3628 || opline->opcode == ZEND_FETCH_DIM_IS
3629 || opline->opcode == ZEND_FETCH_DIM_UNSET
3630 || opline->opcode == ZEND_FETCH_LIST_R) {
3631 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3632 } else {
3633 /* invalid key type */
3634 tmp = (tmp & (MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ARRAY)) |
3635 (t1 & ~(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE));
3636 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3637 }
3638 COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def);
3639 }
3640 /* FETCH_LIST on a string behaves like FETCH_R on null */
3641 tmp = zend_array_element_type(
3642 opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL),
3643 opline->op1_type,
3644 opline->result_type == IS_VAR,
3645 opline->op2_type == IS_UNUSED);
3646 if (opline->opcode == ZEND_FETCH_DIM_FUNC_ARG && (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE))) {
3647 tmp |= MAY_BE_NULL;
3648 }
3649 if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
3650 tmp |= MAY_BE_NULL;
3651 }
3652 if ((tmp & (MAY_BE_RC1|MAY_BE_RCN)) == MAY_BE_RCN && opline->result_type == IS_TMP_VAR) {
3653 /* refcount may be indirectly decremented. Make an exception if the result is used in the next instruction */
3654 if (!ssa_opcodes) {
3655 if (ssa->vars[ssa_op->result_def].use_chain < 0
3656 || opline + 1 != op_array->opcodes + ssa->vars[ssa_op->result_def].use_chain) {
3657 tmp |= MAY_BE_RC1;
3658 }
3659 } else {
3660 if (ssa->vars[ssa_op->result_def].use_chain < 0
3661 || opline + 1 != ssa_opcodes[ssa->vars[ssa_op->result_def].use_chain]) {
3662 tmp |= MAY_BE_RC1;
3663 }
3664 }
3665 }
3666 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3667 break;
3668 case ZEND_FETCH_THIS:
3669 if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
3670 UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_op->result_def);
3671 }
3672 UPDATE_SSA_TYPE(MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def);
3673 break;
3674 case ZEND_FETCH_OBJ_R:
3675 case ZEND_FETCH_OBJ_IS:
3676 case ZEND_FETCH_OBJ_RW:
3677 case ZEND_FETCH_OBJ_W:
3678 case ZEND_FETCH_OBJ_UNSET:
3679 case ZEND_FETCH_OBJ_FUNC_ARG:
3680 if (ssa_op->result_def >= 0) {
3681 uint32_t tmp = 0;
3682 ce = NULL;
3683 if (opline->op1_type != IS_UNUSED
3684 && (t1 & (MAY_BE_ANY | MAY_BE_UNDEF) & ~MAY_BE_OBJECT)) {
3685 tmp |= MAY_BE_NULL;
3686 }
3687 if (opline->op1_type == IS_UNUSED || (t1 & MAY_BE_OBJECT)) {
3688 zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
3689 tmp |= zend_fetch_prop_type(script, prop_info, &ce);
3690 if (opline->result_type == IS_VAR) {
3691 tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
3692 if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
3693 tmp |= MAY_BE_UNDEF;
3694 }
3695 } else if (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || !(t1 & MAY_BE_RC1)) {
3696 zend_class_entry *ce = NULL;
3697
3698 if (opline->op1_type == IS_UNUSED) {
3699 ce = op_array->scope;
3700 } else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
3701 ce = ssa->var_info[ssa_op->op1_use].ce;
3702 }
3703 /* Unset properties will resort back to __get/__set */
3704 if (ce
3705 && !ce->create_object
3706 && !ce->__get
3707 && !result_may_be_separated(ssa, ssa_op)) {
3708 tmp &= ~MAY_BE_RC1;
3709 }
3710 if (opline->opcode == ZEND_FETCH_OBJ_IS) {
3711 /* IS check may return null for uninitialized typed property. */
3712 tmp |= MAY_BE_NULL;
3713 }
3714 }
3715 }
3716 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3717 if (ce) {
3718 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3719 }
3720 }
3721 break;
3722 case ZEND_FETCH_STATIC_PROP_R:
3723 case ZEND_FETCH_STATIC_PROP_IS:
3724 case ZEND_FETCH_STATIC_PROP_RW:
3725 case ZEND_FETCH_STATIC_PROP_W:
3726 case ZEND_FETCH_STATIC_PROP_UNSET:
3727 case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
3728 tmp = zend_fetch_prop_type(script,
3729 zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
3730 if (opline->result_type == IS_VAR) {
3731 tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
3732 if ((opline->extended_value & ZEND_FETCH_OBJ_FLAGS) == ZEND_FETCH_DIM_WRITE) {
3733 tmp |= MAY_BE_UNDEF;
3734 }
3735 } else {
3736 if (!result_may_be_separated(ssa, ssa_op)) {
3737 tmp &= ~MAY_BE_RC1;
3738 }
3739 if (opline->opcode == ZEND_FETCH_STATIC_PROP_IS) {
3740 tmp |= MAY_BE_UNDEF;
3741 }
3742 }
3743 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3744 if (ce) {
3745 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3746 }
3747 break;
3748 case ZEND_DO_FCALL:
3749 case ZEND_DO_ICALL:
3750 case ZEND_DO_UCALL:
3751 case ZEND_DO_FCALL_BY_NAME:
3752 if (ssa_op->result_def >= 0) {
3753 zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
3754 zend_call_info *call_info;
3755
3756 if (!func_info || !func_info->call_map) {
3757 goto unknown_opcode;
3758 }
3759 call_info = func_info->call_map[opline - op_array->opcodes];
3760 if (!call_info) {
3761 goto unknown_opcode;
3762 }
3763
3764 zend_class_entry *ce;
3765 bool ce_is_instanceof;
3766 tmp = zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof);
3767 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3768 if (ce) {
3769 UPDATE_SSA_OBJ_TYPE(ce, ce_is_instanceof, ssa_op->result_def);
3770 }
3771 }
3772 break;
3773 case ZEND_CALLABLE_CONVERT:
3774 UPDATE_SSA_TYPE(MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN, ssa_op->result_def);
3775 UPDATE_SSA_OBJ_TYPE(zend_ce_closure, /* is_instanceof */ false, ssa_op->result_def);
3776 break;
3777 case ZEND_FETCH_CONSTANT:
3778 case ZEND_FETCH_CLASS_CONSTANT:
3779 UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
3780 break;
3781 case ZEND_STRLEN:
3782 tmp = MAY_BE_LONG;
3783 if (t1 & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING))) {
3784 tmp |= MAY_BE_NULL;
3785 }
3786 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3787 break;
3788 case ZEND_COUNT:
3789 case ZEND_FUNC_NUM_ARGS:
3790 UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def);
3791 break;
3792 case ZEND_FUNC_GET_ARGS:
3793 UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN| MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
3794 break;
3795 case ZEND_GET_CLASS:
3796 case ZEND_GET_CALLED_CLASS:
3797 UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_RCN, ssa_op->result_def);
3798 break;
3799 case ZEND_GET_TYPE:
3800 UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def);
3801 break;
3802 case ZEND_TYPE_CHECK:
3803 case ZEND_DEFINED:
3804 UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def);
3805 break;
3806 case ZEND_VERIFY_RETURN_TYPE:
3807 if (t1 & MAY_BE_REF) {
3808 tmp = t1;
3809 ce = NULL;
3810 } else {
3811 zend_arg_info *ret_info = op_array->arg_info - 1;
3812 tmp = zend_fetch_arg_info_type(script, ret_info, &ce);
3813 tmp |= (t1 & MAY_BE_INDIRECT);
3814
3815 // TODO: We could model more precisely how illegal types are converted.
3816 uint32_t extra_types = t1 & ~tmp;
3817 if (!extra_types) {
3818 tmp &= t1;
3819 }
3820 }
3821 if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
3822 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3823 if (ce) {
3824 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->op1_def);
3825 } else {
3826 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->op1_def);
3827 }
3828 } else {
3829 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3830 if (ce) {
3831 UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def);
3832 } else {
3833 UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def);
3834 }
3835 }
3836 break;
3837 case ZEND_MAKE_REF:
3838 tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
3839 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3840 if (ssa_op->op1_def >= 0) {
3841 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3842 }
3843 break;
3844 case ZEND_CATCH:
3845 /* Forbidden opcodes */
3846 ZEND_UNREACHABLE();
3847 break;
3848 default:
3849 unknown_opcode:
3850 if (ssa_op->op1_def >= 0) {
3851 tmp = MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3852 UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
3853 }
3854 if (ssa_op->result_def >= 0) {
3855 tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
3856 if (opline->result_type == IS_TMP_VAR) {
3857 if (opline->opcode == ZEND_FETCH_R || opline->opcode == ZEND_FETCH_IS) {
3858 /* Variable reference counter may be decremented before use */
3859 /* See: ext/opcache/tests/jit/fetch_r_001.phpt */
3860 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3861 } else {
3862 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3863 }
3864 } else if (opline->result_type == IS_CV) {
3865 tmp |= MAY_BE_RC1 | MAY_BE_RCN;
3866 } else {
3867 tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
3868 switch (opline->opcode) {
3869 case ZEND_FETCH_W:
3870 case ZEND_FETCH_RW:
3871 case ZEND_FETCH_FUNC_ARG:
3872 case ZEND_FETCH_UNSET:
3873 case ZEND_FETCH_DIM_W:
3874 case ZEND_FETCH_DIM_RW:
3875 case ZEND_FETCH_DIM_FUNC_ARG:
3876 case ZEND_FETCH_DIM_UNSET:
3877 case ZEND_FETCH_OBJ_W:
3878 case ZEND_FETCH_OBJ_RW:
3879 case ZEND_FETCH_OBJ_FUNC_ARG:
3880 case ZEND_FETCH_OBJ_UNSET:
3881 case ZEND_FETCH_STATIC_PROP_W:
3882 case ZEND_FETCH_STATIC_PROP_RW:
3883 case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
3884 case ZEND_FETCH_STATIC_PROP_UNSET:
3885 tmp |= MAY_BE_INDIRECT;
3886 break;
3887 }
3888 }
3889 UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
3890 }
3891 break;
3892 }
3893
3894 return SUCCESS;
3895 }
3896
zend_update_type_info(const zend_op_array * op_array,zend_ssa * ssa,const zend_script * script,zend_op * opline,zend_ssa_op * ssa_op,const zend_op ** ssa_opcodes,zend_long optimization_level)3897 ZEND_API int zend_update_type_info(
3898 const zend_op_array *op_array,
3899 zend_ssa *ssa,
3900 const zend_script *script,
3901 zend_op *opline,
3902 zend_ssa_op *ssa_op,
3903 const zend_op **ssa_opcodes,
3904 zend_long optimization_level)
3905 {
3906 return _zend_update_type_info(op_array, ssa, script, NULL, opline, ssa_op, ssa_opcodes, optimization_level, 0);
3907 }
3908
get_class_entry_rank(zend_class_entry * ce)3909 static uint32_t get_class_entry_rank(zend_class_entry *ce) {
3910 uint32_t rank = 0;
3911 if (ce->ce_flags & ZEND_ACC_LINKED) {
3912 while (ce->parent) {
3913 rank++;
3914 ce = ce->parent;
3915 }
3916 }
3917 return rank;
3918 }
3919
3920 /* Compute least common ancestor on class inheritance tree only */
join_class_entries(zend_class_entry * ce1,zend_class_entry * ce2,int * is_instanceof)3921 static zend_class_entry *join_class_entries(
3922 zend_class_entry *ce1, zend_class_entry *ce2, int *is_instanceof) {
3923 uint32_t rank1, rank2;
3924 if (ce1 == ce2) {
3925 return ce1;
3926 }
3927 if (!ce1 || !ce2) {
3928 return NULL;
3929 }
3930
3931 rank1 = get_class_entry_rank(ce1);
3932 rank2 = get_class_entry_rank(ce2);
3933
3934 while (rank1 != rank2) {
3935 if (rank1 > rank2) {
3936 ce1 = !(ce1->ce_flags & ZEND_ACC_LINKED) ? NULL : ce1->parent;
3937 rank1--;
3938 } else {
3939 ce2 = !(ce2->ce_flags & ZEND_ACC_LINKED) ? NULL : ce2->parent;
3940 rank2--;
3941 }
3942 }
3943
3944 while (ce1 != ce2) {
3945 ce1 = !(ce1->ce_flags & ZEND_ACC_LINKED) ? NULL : ce1->parent;
3946 ce2 = !(ce2->ce_flags & ZEND_ACC_LINKED) ? NULL : ce2->parent;
3947 }
3948
3949 if (ce1) {
3950 *is_instanceof = 1;
3951 }
3952 return ce1;
3953 }
3954
zend_infer_types_ex(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_bitset worklist,zend_long optimization_level)3955 static int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level)
3956 {
3957 zend_basic_block *blocks = ssa->cfg.blocks;
3958 zend_ssa_var *ssa_vars = ssa->vars;
3959 zend_ssa_var_info *ssa_var_info = ssa->var_info;
3960 int ssa_vars_count = ssa->vars_count;
3961 int i, j;
3962 uint32_t tmp, worklist_len = zend_bitset_len(ssa_vars_count);
3963 bool update_worklist = 1;
3964 const zend_op **ssa_opcodes = NULL;
3965
3966 while (!zend_bitset_empty(worklist, worklist_len)) {
3967 j = zend_bitset_first(worklist, worklist_len);
3968 zend_bitset_excl(worklist, j);
3969 if (ssa_vars[j].definition_phi) {
3970 zend_ssa_phi *p = ssa_vars[j].definition_phi;
3971 if (p->pi >= 0) {
3972 zend_class_entry *ce = ssa_var_info[p->sources[0]].ce;
3973 int is_instanceof = ssa_var_info[p->sources[0]].is_instanceof;
3974 tmp = get_ssa_var_info(ssa, p->sources[0]);
3975
3976 if (!p->has_range_constraint) {
3977 zend_ssa_type_constraint *constraint = &p->constraint.type;
3978 tmp &= constraint->type_mask;
3979 if (!(tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
3980 tmp &= ~(MAY_BE_RC1|MAY_BE_RCN);
3981 }
3982 if ((tmp & MAY_BE_OBJECT) && constraint->ce && ce != constraint->ce) {
3983 if (!ce) {
3984 ce = constraint->ce;
3985 is_instanceof = 1;
3986 } else if (is_instanceof && instanceof_function(constraint->ce, ce)) {
3987 ce = constraint->ce;
3988 } else {
3989 /* Ignore the constraint (either ce instanceof constraint->ce or
3990 * they are unrelated, as far as we can statically determine) */
3991 }
3992 }
3993 }
3994
3995 UPDATE_SSA_TYPE(tmp, j);
3996 if (tmp & MAY_BE_REF) {
3997 UPDATE_SSA_OBJ_TYPE(NULL, 0, j);
3998 } else {
3999 UPDATE_SSA_OBJ_TYPE(ce, is_instanceof, j);
4000 }
4001 } else {
4002 int first = 1;
4003 int is_instanceof = 0;
4004 zend_class_entry *ce = NULL;
4005
4006 tmp = 0;
4007 for (i = 0; i < blocks[p->block].predecessors_count; i++) {
4008 tmp |= get_ssa_var_info(ssa, p->sources[i]);
4009 }
4010 UPDATE_SSA_TYPE(tmp, j);
4011 for (i = 0; i < blocks[p->block].predecessors_count; i++) {
4012 zend_ssa_var_info *info;
4013
4014 ZEND_ASSERT(p->sources[i] >= 0);
4015 info = &ssa_var_info[p->sources[i]];
4016 if (info->type & MAY_BE_OBJECT) {
4017 if (first) {
4018 ce = info->ce;
4019 is_instanceof = info->is_instanceof;
4020 first = 0;
4021 } else {
4022 is_instanceof |= info->is_instanceof;
4023 ce = join_class_entries(ce, info->ce, &is_instanceof);
4024 }
4025 }
4026 }
4027 UPDATE_SSA_OBJ_TYPE(ce, ce ? is_instanceof : 0, j);
4028 }
4029 } else if (ssa_vars[j].definition >= 0) {
4030 i = ssa_vars[j].definition;
4031 if (_zend_update_type_info(op_array, ssa, script, worklist, op_array->opcodes + i, ssa->ops + i, NULL, optimization_level, 1) == FAILURE) {
4032 return FAILURE;
4033 }
4034 }
4035 }
4036 return SUCCESS;
4037 }
4038
is_narrowable_instr(zend_op * opline)4039 static bool is_narrowable_instr(zend_op *opline) {
4040 return opline->opcode == ZEND_ADD || opline->opcode == ZEND_SUB
4041 || opline->opcode == ZEND_MUL || opline->opcode == ZEND_DIV;
4042 }
4043
is_effective_op1_double_cast(zend_op * opline,zval * op2)4044 static bool is_effective_op1_double_cast(zend_op *opline, zval *op2) {
4045 return (opline->opcode == ZEND_ADD && Z_LVAL_P(op2) == 0)
4046 || (opline->opcode == ZEND_SUB && Z_LVAL_P(op2) == 0)
4047 || (opline->opcode == ZEND_MUL && Z_LVAL_P(op2) == 1)
4048 || (opline->opcode == ZEND_DIV && Z_LVAL_P(op2) == 1);
4049 }
is_effective_op2_double_cast(zend_op * opline,zval * op1)4050 static bool is_effective_op2_double_cast(zend_op *opline, zval *op1) {
4051 /* In PHP it holds that (double)(0-$int) is bitwise identical to 0.0-(double)$int,
4052 * so allowing SUB here is fine. */
4053 return (opline->opcode == ZEND_ADD && Z_LVAL_P(op1) == 0)
4054 || (opline->opcode == ZEND_SUB && Z_LVAL_P(op1) == 0)
4055 || (opline->opcode == ZEND_MUL && Z_LVAL_P(op1) == 1);
4056 }
4057
4058 /* This function recursively checks whether it's possible to convert an integer variable
4059 * initialization to a double initialization. The basic idea is that if the value is used
4060 * only in add/sub/mul/div ("narrowable" instructions) with a double result value, then it
4061 * will be cast to double at that point anyway, so we may as well do it earlier already.
4062 *
4063 * The tricky case are chains of operations, where it's not necessarily a given that converting
4064 * an integer to double before the chain of operations is the same as converting it after the
4065 * chain. What this function does is detect two cases where it is safe:
4066 * * If the operations only involve constants, then we can simply verify that performing the
4067 * calculation on integers and doubles yields the same value.
4068 * * Even if one operand is not known, we may be able to determine that the operations with the
4069 * integer replaced by a double only acts as an effective double cast on the unknown operand.
4070 * E.g. 0+$i and 0.0+$i only differ by that cast. If then the consuming instruction of this
4071 * result will perform a double cast anyway, the conversion is safe.
4072 *
4073 * The checks happens recursively, while keeping track of which variables are already visited to
4074 * avoid infinite loops. An iterative, worklist driven approach would be possible, but the state
4075 * management more cumbersome to implement, so we don't bother for now.
4076 */
can_convert_to_double(const zend_op_array * op_array,zend_ssa * ssa,int var_num,zval * value,zend_bitset visited)4077 static bool can_convert_to_double(
4078 const zend_op_array *op_array, zend_ssa *ssa, int var_num,
4079 zval *value, zend_bitset visited) {
4080 zend_ssa_var *var = &ssa->vars[var_num];
4081 zend_ssa_phi *phi;
4082 int use;
4083 uint32_t type;
4084
4085 if (zend_bitset_in(visited, var_num)) {
4086 return 1;
4087 }
4088 zend_bitset_incl(visited, var_num);
4089
4090 for (use = var->use_chain; use >= 0; use = zend_ssa_next_use(ssa->ops, var_num, use)) {
4091 zend_op *opline = &op_array->opcodes[use];
4092 zend_ssa_op *ssa_op = &ssa->ops[use];
4093
4094 if (zend_ssa_is_no_val_use(opline, ssa_op, var_num)) {
4095 continue;
4096 }
4097
4098 if (!is_narrowable_instr(opline)) {
4099 return 0;
4100 }
4101
4102 /* Instruction always returns double, the conversion is certainly fine */
4103 type = ssa->var_info[ssa_op->result_def].type;
4104 if ((type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4105 continue;
4106 }
4107
4108 /* UNDEF signals that the previous result is an effective double cast, this is only allowed
4109 * if this instruction would have done the cast anyway (previous check). */
4110 if (Z_ISUNDEF_P(value)) {
4111 return 0;
4112 }
4113
4114 /* Check that narrowing can actually be useful */
4115 if ((type & MAY_BE_ANY) & ~(MAY_BE_LONG|MAY_BE_DOUBLE)) {
4116 return 0;
4117 }
4118
4119 {
4120 /* For calculation on original values */
4121 zval orig_op1, orig_op2, orig_result;
4122 /* For calculation with var_num cast to double */
4123 zval dval_op1, dval_op2, dval_result;
4124
4125 ZVAL_UNDEF(&orig_op1);
4126 ZVAL_UNDEF(&dval_op1);
4127 if (ssa_op->op1_use == var_num) {
4128 ZVAL_COPY_VALUE(&orig_op1, value);
4129 ZVAL_DOUBLE(&dval_op1, (double) Z_LVAL_P(value));
4130 } else if (opline->op1_type == IS_CONST) {
4131 zval *zv = CRT_CONSTANT(opline->op1);
4132 if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
4133 ZVAL_COPY_VALUE(&orig_op1, zv);
4134 ZVAL_COPY_VALUE(&dval_op1, zv);
4135 }
4136 }
4137
4138 ZVAL_UNDEF(&orig_op2);
4139 ZVAL_UNDEF(&dval_op2);
4140 if (ssa_op->op2_use == var_num) {
4141 ZVAL_COPY_VALUE(&orig_op2, value);
4142 ZVAL_DOUBLE(&dval_op2, (double) Z_LVAL_P(value));
4143 } else if (opline->op2_type == IS_CONST) {
4144 zval *zv = CRT_CONSTANT(opline->op2);
4145 if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
4146 ZVAL_COPY_VALUE(&orig_op2, zv);
4147 ZVAL_COPY_VALUE(&dval_op2, zv);
4148 }
4149 }
4150
4151 ZEND_ASSERT(!Z_ISUNDEF(orig_op1) || !Z_ISUNDEF(orig_op2));
4152 if (Z_ISUNDEF(orig_op1)) {
4153 if (opline->opcode == ZEND_MUL && Z_LVAL(orig_op2) == 0) {
4154 ZVAL_LONG(&orig_result, 0);
4155 } else if (is_effective_op1_double_cast(opline, &orig_op2)) {
4156 ZVAL_UNDEF(&orig_result);
4157 } else {
4158 return 0;
4159 }
4160 } else if (Z_ISUNDEF(orig_op2)) {
4161 if (opline->opcode == ZEND_MUL && Z_LVAL(orig_op1) == 0) {
4162 ZVAL_LONG(&orig_result, 0);
4163 } else if (is_effective_op2_double_cast(opline, &orig_op1)) {
4164 ZVAL_UNDEF(&orig_result);
4165 } else {
4166 return 0;
4167 }
4168 } else {
4169 zend_uchar opcode = opline->opcode;
4170
4171 if (opcode == ZEND_ASSIGN_OP) {
4172 opcode = opline->extended_value;
4173 }
4174
4175 /* Avoid division by zero */
4176 if (opcode == ZEND_DIV && zval_get_double(&orig_op2) == 0.0) {
4177 return 0;
4178 }
4179
4180 get_binary_op(opcode)(&orig_result, &orig_op1, &orig_op2);
4181 get_binary_op(opcode)(&dval_result, &dval_op1, &dval_op2);
4182 ZEND_ASSERT(Z_TYPE(dval_result) == IS_DOUBLE);
4183 if (zval_get_double(&orig_result) != Z_DVAL(dval_result)) {
4184 return 0;
4185 }
4186 }
4187
4188 if (!can_convert_to_double(op_array, ssa, ssa_op->result_def, &orig_result, visited)) {
4189 return 0;
4190 }
4191 }
4192 }
4193
4194 for (phi = var->phi_use_chain; phi; phi = zend_ssa_next_use_phi(ssa, var_num, phi)) {
4195 /* Check that narrowing can actually be useful */
4196 type = ssa->var_info[phi->ssa_var].type;
4197 if ((type & MAY_BE_ANY) & ~(MAY_BE_LONG|MAY_BE_DOUBLE)) {
4198 return 0;
4199 }
4200
4201 if (!can_convert_to_double(op_array, ssa, phi->ssa_var, value, visited)) {
4202 return 0;
4203 }
4204 }
4205
4206 return 1;
4207 }
4208
zend_type_narrowing(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4209 static int zend_type_narrowing(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
4210 {
4211 uint32_t bitset_len = zend_bitset_len(ssa->vars_count);
4212 zend_bitset visited, worklist;
4213 int i, v;
4214 zend_op *opline;
4215 bool narrowed = 0;
4216 ALLOCA_FLAG(use_heap)
4217
4218 visited = ZEND_BITSET_ALLOCA(2 * bitset_len, use_heap);
4219 worklist = visited + bitset_len;
4220
4221 zend_bitset_clear(worklist, bitset_len);
4222
4223 for (v = op_array->last_var; v < ssa->vars_count; v++) {
4224 if ((ssa->var_info[v].type & (MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF)) != MAY_BE_LONG) continue;
4225 if (ssa->vars[v].definition < 0) continue;
4226 if (ssa->vars[v].no_val) continue;
4227 opline = op_array->opcodes + ssa->vars[v].definition;
4228 /* Go through assignments of literal integers and check if they can be converted to
4229 * doubles instead, in the hope that we'll narrow long|double to double. */
4230 if (opline->opcode == ZEND_ASSIGN && opline->result_type == IS_UNUSED &&
4231 opline->op1_type == IS_CV && opline->op2_type == IS_CONST) {
4232 zval *value = CRT_CONSTANT(opline->op2);
4233
4234 zend_bitset_clear(visited, bitset_len);
4235 if (can_convert_to_double(op_array, ssa, v, value, visited)) {
4236 narrowed = 1;
4237 ssa->var_info[v].use_as_double = 1;
4238 /* The "visited" vars are exactly those which may change their type due to
4239 * narrowing. Reset their types and add them to the type inference worklist */
4240 ZEND_BITSET_FOREACH(visited, bitset_len, i) {
4241 ssa->var_info[i].type &= ~MAY_BE_ANY;
4242 } ZEND_BITSET_FOREACH_END();
4243 zend_bitset_union(worklist, visited, bitset_len);
4244 }
4245 }
4246 }
4247
4248 if (!narrowed) {
4249 free_alloca(visited, use_heap);
4250 return SUCCESS;
4251 }
4252
4253 if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) != SUCCESS) {
4254 free_alloca(visited, use_heap);
4255 return FAILURE;
4256 }
4257
4258 free_alloca(visited, use_heap);
4259 return SUCCESS;
4260 }
4261
is_recursive_tail_call(const zend_op_array * op_array,zend_op * opline)4262 static int is_recursive_tail_call(const zend_op_array *op_array,
4263 zend_op *opline)
4264 {
4265 zend_func_info *info = ZEND_FUNC_INFO(op_array);
4266
4267 if (info->ssa.ops && info->ssa.vars && info->call_map &&
4268 info->ssa.ops[opline - op_array->opcodes].op1_use >= 0 &&
4269 info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition >= 0) {
4270
4271 zend_op *op = op_array->opcodes + info->ssa.vars[info->ssa.ops[opline - op_array->opcodes].op1_use].definition;
4272
4273 if (op->opcode == ZEND_DO_UCALL) {
4274 zend_call_info *call_info = info->call_map[op - op_array->opcodes];
4275 if (call_info && op_array == &call_info->callee_func->op_array) {
4276 return 1;
4277 }
4278 }
4279 }
4280 return 0;
4281 }
4282
zend_get_return_info_from_signature_only(const zend_function * func,const zend_script * script,zend_class_entry ** ce,bool * ce_is_instanceof,bool use_tentative_return_info)4283 uint32_t zend_get_return_info_from_signature_only(
4284 const zend_function *func, const zend_script *script,
4285 zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info) {
4286 uint32_t type;
4287 if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE &&
4288 (use_tentative_return_info || !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1))
4289 ) {
4290 zend_arg_info *ret_info = func->common.arg_info - 1;
4291 type = zend_fetch_arg_info_type(script, ret_info, ce);
4292 *ce_is_instanceof = ce != NULL;
4293 } else {
4294 type = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
4295 | MAY_BE_RC1 | MAY_BE_RCN;
4296 *ce = NULL;
4297 *ce_is_instanceof = false;
4298 }
4299
4300 /* For generators RETURN_REFERENCE refers to the yielded values. */
4301 if ((func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
4302 && !(func->common.fn_flags & ZEND_ACC_GENERATOR)) {
4303 type |= MAY_BE_REF;
4304 }
4305 return type;
4306 }
4307
zend_init_func_return_info(const zend_op_array * op_array,const zend_script * script,zend_ssa_var_info * ret)4308 ZEND_API void zend_init_func_return_info(
4309 const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
4310 {
4311 ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE));
4312
4313 zend_ssa_range tmp_range = {0, 0, 0, 0};
4314 bool is_instanceof = false;
4315 ret->type = zend_get_return_info_from_signature_only(
4316 (zend_function *) op_array, script, &ret->ce, &is_instanceof, /* use_tentative_return_info */ 1);
4317 ret->is_instanceof = is_instanceof;
4318 ret->range = tmp_range;
4319 ret->has_range = 0;
4320 }
4321
zend_func_return_info(const zend_op_array * op_array,const zend_script * script,int recursive,int widening,zend_ssa_var_info * ret)4322 static void zend_func_return_info(const zend_op_array *op_array,
4323 const zend_script *script,
4324 int recursive,
4325 int widening,
4326 zend_ssa_var_info *ret)
4327 {
4328 zend_func_info *info = ZEND_FUNC_INFO(op_array);
4329 zend_ssa *ssa = &info->ssa;
4330 int blocks_count = info->ssa.cfg.blocks_count;
4331 zend_basic_block *blocks = info->ssa.cfg.blocks;
4332 int j;
4333 uint32_t t1;
4334 uint32_t tmp = 0;
4335 zend_class_entry *tmp_ce = NULL;
4336 int tmp_is_instanceof = -1;
4337 zend_class_entry *arg_ce;
4338 int arg_is_instanceof;
4339 zend_ssa_range tmp_range = {0, 0, 0, 0};
4340 int tmp_has_range = -1;
4341
4342 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
4343 ret->type = MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN;
4344 ret->ce = zend_ce_generator;
4345 ret->is_instanceof = 0;
4346 ret->range = tmp_range;
4347 ret->has_range = 0;
4348 return;
4349 }
4350
4351 if (!ret->type) {
4352 /* We will intersect the type later. */
4353 ret->type = MAY_BE_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY
4354 | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF;
4355 }
4356
4357 for (j = 0; j < blocks_count; j++) {
4358 if ((blocks[j].flags & ZEND_BB_REACHABLE) && blocks[j].len != 0) {
4359 zend_op *opline = op_array->opcodes + blocks[j].start + blocks[j].len - 1;
4360
4361 if (opline->opcode == ZEND_RETURN || opline->opcode == ZEND_RETURN_BY_REF) {
4362 zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
4363 if (!recursive && ssa_op && info->ssa.var_info &&
4364 ssa_op->op1_use >= 0 &&
4365 info->ssa.var_info[ssa_op->op1_use].recursive) {
4366 continue;
4367 }
4368 if (is_recursive_tail_call(op_array, opline)) {
4369 continue;
4370 }
4371 t1 = OP1_INFO();
4372 if (t1 & MAY_BE_UNDEF) {
4373 t1 |= MAY_BE_NULL;
4374 }
4375 if (opline->opcode == ZEND_RETURN) {
4376 if (t1 & MAY_BE_RC1) {
4377 t1 |= MAY_BE_RCN;
4378 }
4379 t1 &= ~(MAY_BE_UNDEF | MAY_BE_REF);
4380 } else {
4381 t1 |= MAY_BE_REF;
4382 t1 &= ~(MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN);
4383 }
4384 tmp |= t1;
4385
4386 if (ssa_op && info->ssa.var_info &&
4387 ssa_op->op1_use >= 0 &&
4388 info->ssa.var_info[ssa_op->op1_use].ce) {
4389 arg_ce = info->ssa.var_info[ssa_op->op1_use].ce;
4390 arg_is_instanceof = info->ssa.var_info[ssa_op->op1_use].is_instanceof;
4391 } else {
4392 arg_ce = NULL;
4393 arg_is_instanceof = 0;
4394 }
4395
4396 if (tmp_is_instanceof < 0) {
4397 tmp_ce = arg_ce;
4398 tmp_is_instanceof = arg_is_instanceof;
4399 } else if (arg_ce && arg_ce == tmp_ce) {
4400 if (tmp_is_instanceof != arg_is_instanceof) {
4401 tmp_is_instanceof = 1;
4402 }
4403 } else {
4404 tmp_ce = NULL;
4405 tmp_is_instanceof = 0;
4406 }
4407
4408 if (opline->op1_type == IS_CONST) {
4409 zval *zv = CRT_CONSTANT(opline->op1);
4410
4411 if (Z_TYPE_P(zv) == IS_NULL) {
4412 if (tmp_has_range < 0) {
4413 tmp_has_range = 1;
4414 tmp_range.underflow = 0;
4415 tmp_range.min = 0;
4416 tmp_range.max = 0;
4417 tmp_range.overflow = 0;
4418 } else if (tmp_has_range) {
4419 if (!tmp_range.underflow) {
4420 tmp_range.min = MIN(tmp_range.min, 0);
4421 }
4422 if (!tmp_range.overflow) {
4423 tmp_range.max = MAX(tmp_range.max, 0);
4424 }
4425 }
4426 } else if (Z_TYPE_P(zv) == IS_FALSE) {
4427 if (tmp_has_range < 0) {
4428 tmp_has_range = 1;
4429 tmp_range.underflow = 0;
4430 tmp_range.min = 0;
4431 tmp_range.max = 0;
4432 tmp_range.overflow = 0;
4433 } else if (tmp_has_range) {
4434 if (!tmp_range.underflow) {
4435 tmp_range.min = MIN(tmp_range.min, 0);
4436 }
4437 if (!tmp_range.overflow) {
4438 tmp_range.max = MAX(tmp_range.max, 0);
4439 }
4440 }
4441 } else if (Z_TYPE_P(zv) == IS_TRUE) {
4442 if (tmp_has_range < 0) {
4443 tmp_has_range = 1;
4444 tmp_range.underflow = 0;
4445 tmp_range.min = 1;
4446 tmp_range.max = 1;
4447 tmp_range.overflow = 0;
4448 } else if (tmp_has_range) {
4449 if (!tmp_range.underflow) {
4450 tmp_range.min = MIN(tmp_range.min, 1);
4451 }
4452 if (!tmp_range.overflow) {
4453 tmp_range.max = MAX(tmp_range.max, 1);
4454 }
4455 }
4456 } else if (Z_TYPE_P(zv) == IS_LONG) {
4457 if (tmp_has_range < 0) {
4458 tmp_has_range = 1;
4459 tmp_range.underflow = 0;
4460 tmp_range.min = Z_LVAL_P(zv);
4461 tmp_range.max = Z_LVAL_P(zv);
4462 tmp_range.overflow = 0;
4463 } else if (tmp_has_range) {
4464 if (!tmp_range.underflow) {
4465 tmp_range.min = MIN(tmp_range.min, Z_LVAL_P(zv));
4466 }
4467 if (!tmp_range.overflow) {
4468 tmp_range.max = MAX(tmp_range.max, Z_LVAL_P(zv));
4469 }
4470 }
4471 } else {
4472 tmp_has_range = 0;
4473 }
4474 } else if (ssa_op && info->ssa.var_info && ssa_op->op1_use >= 0) {
4475 if (info->ssa.var_info[ssa_op->op1_use].has_range) {
4476 if (tmp_has_range < 0) {
4477 tmp_has_range = 1;
4478 tmp_range = info->ssa.var_info[ssa_op->op1_use].range;
4479 } else if (tmp_has_range) {
4480 /* union */
4481 if (info->ssa.var_info[ssa_op->op1_use].range.underflow) {
4482 tmp_range.underflow = 1;
4483 tmp_range.min = ZEND_LONG_MIN;
4484 } else {
4485 tmp_range.min = MIN(tmp_range.min, info->ssa.var_info[ssa_op->op1_use].range.min);
4486 }
4487 if (info->ssa.var_info[ssa_op->op1_use].range.overflow) {
4488 tmp_range.overflow = 1;
4489 tmp_range.max = ZEND_LONG_MAX;
4490 } else {
4491 tmp_range.max = MAX(tmp_range.max, info->ssa.var_info[ssa_op->op1_use].range.max);
4492 }
4493 }
4494 } else if (!widening) {
4495 tmp_has_range = 1;
4496 tmp_range.underflow = 1;
4497 tmp_range.min = ZEND_LONG_MIN;
4498 tmp_range.max = ZEND_LONG_MAX;
4499 tmp_range.overflow = 1;
4500 }
4501 } else {
4502 tmp_has_range = 0;
4503 }
4504 }
4505 }
4506 }
4507
4508 if (!(op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
4509 if (tmp_is_instanceof < 0) {
4510 tmp_is_instanceof = 0;
4511 tmp_ce = NULL;
4512 }
4513 if (tmp_has_range < 0) {
4514 tmp_has_range = 0;
4515 }
4516 ret->ce = tmp_ce;
4517 ret->is_instanceof = tmp_is_instanceof;
4518 }
4519 ret->type &= tmp;
4520 ret->range = tmp_range;
4521 ret->has_range = tmp_has_range;
4522 }
4523
zend_infer_types(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4524 static int zend_infer_types(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
4525 {
4526 int ssa_vars_count = ssa->vars_count;
4527 int j;
4528 zend_bitset worklist;
4529 ALLOCA_FLAG(use_heap);
4530
4531 worklist = do_alloca(sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count), use_heap);
4532 memset(worklist, 0, sizeof(zend_ulong) * zend_bitset_len(ssa_vars_count));
4533
4534 /* Type Inference */
4535 for (j = op_array->last_var; j < ssa_vars_count; j++) {
4536 zend_bitset_incl(worklist, j);
4537 }
4538
4539 if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) != SUCCESS) {
4540 free_alloca(worklist, use_heap);
4541 return FAILURE;
4542 }
4543
4544 if (optimization_level & ZEND_OPTIMIZER_NARROW_TO_DOUBLE) {
4545 /* Narrowing integer initialization to doubles */
4546 zend_type_narrowing(op_array, script, ssa, optimization_level);
4547 }
4548
4549 if (ZEND_FUNC_INFO(op_array)) {
4550 zend_func_return_info(op_array, script, 1, 0, &ZEND_FUNC_INFO(op_array)->return_info);
4551 }
4552
4553 free_alloca(worklist, use_heap);
4554 return SUCCESS;
4555 }
4556
zend_mark_cv_references(const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa)4557 static int zend_mark_cv_references(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa)
4558 {
4559 int var, def;
4560 const zend_op *opline;
4561 zend_arg_info *arg_info;
4562 uint32_t worklist_len = zend_bitset_len(ssa->vars_count);
4563 zend_bitset worklist;
4564 ALLOCA_FLAG(use_heap);
4565
4566 worklist = do_alloca(sizeof(zend_ulong) * worklist_len, use_heap);
4567 memset(worklist, 0, sizeof(zend_ulong) * worklist_len);
4568
4569 /* Collect SSA variables which definitions creates PHP reference */
4570 for (var = 0; var < ssa->vars_count; var++) {
4571 def = ssa->vars[var].definition;
4572 if (def >= 0 && ssa->vars[var].var < op_array->last_var) {
4573 opline = op_array->opcodes + def;
4574 if (ssa->ops[def].result_def == var) {
4575 switch (opline->opcode) {
4576 case ZEND_RECV:
4577 case ZEND_RECV_INIT:
4578 arg_info = &op_array->arg_info[opline->op1.num-1];
4579 if (!ZEND_ARG_SEND_MODE(arg_info)) {
4580 continue;
4581 }
4582 break;
4583 default:
4584 continue;
4585 }
4586 } else if (ssa->ops[def].op1_def == var) {
4587 switch (opline->opcode) {
4588 case ZEND_ASSIGN_REF:
4589 case ZEND_MAKE_REF:
4590 case ZEND_FE_RESET_RW:
4591 case ZEND_BIND_GLOBAL:
4592 case ZEND_SEND_REF:
4593 case ZEND_SEND_VAR_EX:
4594 case ZEND_SEND_FUNC_ARG:
4595 break;
4596 case ZEND_INIT_ARRAY:
4597 case ZEND_ADD_ARRAY_ELEMENT:
4598 if (!(opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
4599 continue;
4600 }
4601 break;
4602 case ZEND_BIND_STATIC:
4603 if (!(opline->extended_value & ZEND_BIND_REF)) {
4604 continue;
4605 }
4606 break;
4607 case ZEND_YIELD:
4608 if (!(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
4609 continue;
4610 }
4611 break;
4612 case ZEND_OP_DATA:
4613 switch ((opline-1)->opcode) {
4614 case ZEND_ASSIGN_OBJ_REF:
4615 case ZEND_ASSIGN_STATIC_PROP_REF:
4616 break;
4617 default:
4618 continue;
4619 }
4620 break;
4621 default:
4622 continue;
4623 }
4624 } else if (ssa->ops[def].op2_def == var) {
4625 switch (opline->opcode) {
4626 case ZEND_ASSIGN_REF:
4627 case ZEND_FE_FETCH_RW:
4628 break;
4629 case ZEND_BIND_LEXICAL:
4630 if (!(opline->extended_value & ZEND_BIND_REF)) {
4631 continue;
4632 }
4633 break;
4634 default:
4635 continue;
4636 }
4637 } else {
4638 ZEND_UNREACHABLE();
4639 }
4640 zend_bitset_incl(worklist, var);
4641 } else if (ssa->var_info[var].type & MAY_BE_REF) {
4642 zend_bitset_incl(worklist, var);
4643 } else if (ssa->vars[var].alias == SYMTABLE_ALIAS) {
4644 zend_bitset_incl(worklist, var);
4645 }
4646 }
4647
4648 /* Set and propagate MAY_BE_REF */
4649 WHILE_WORKLIST(worklist, worklist_len, var) {
4650
4651 ssa->var_info[var].type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
4652
4653 if (ssa->vars[var].phi_use_chain) {
4654 zend_ssa_phi *p = ssa->vars[var].phi_use_chain;
4655 do {
4656 if (!(ssa->var_info[p->ssa_var].type & MAY_BE_REF)) {
4657 zend_bitset_incl(worklist, p->ssa_var);
4658 }
4659 p = zend_ssa_next_use_phi(ssa, var, p);
4660 } while (p);
4661 }
4662
4663 if (ssa->vars[var].use_chain >= 0) {
4664 int use = ssa->vars[var].use_chain;
4665 FOREACH_USE(&ssa->vars[var], use) {
4666 zend_ssa_op *op = ssa->ops + use;
4667 if (op->op1_use == var && op->op1_def >= 0) {
4668 if (!(ssa->var_info[op->op1_def].type & MAY_BE_REF)) {
4669 /* Unset breaks references (outside global scope). */
4670 if (op_array->opcodes[use].opcode == ZEND_UNSET_CV
4671 && op_array->function_name) {
4672 continue;
4673 }
4674 zend_bitset_incl(worklist, op->op1_def);
4675 }
4676 }
4677 if (op->op2_use == var && op->op2_def >= 0) {
4678 if (!(ssa->var_info[op->op2_def].type & MAY_BE_REF)) {
4679 zend_bitset_incl(worklist, op->op2_def);
4680 }
4681 }
4682 if (op->result_use == var && op->result_def >= 0) {
4683 if (!(ssa->var_info[op->result_def].type & MAY_BE_REF)) {
4684 zend_bitset_incl(worklist, op->result_def);
4685 }
4686 }
4687 } FOREACH_USE_END();
4688 }
4689 } WHILE_WORKLIST_END();
4690
4691 free_alloca(worklist, use_heap);
4692 return SUCCESS;
4693 }
4694
zend_ssa_inference(zend_arena ** arena,const zend_op_array * op_array,const zend_script * script,zend_ssa * ssa,zend_long optimization_level)4695 ZEND_API int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level) /* {{{ */
4696 {
4697 zend_ssa_var_info *ssa_var_info;
4698 int i;
4699
4700 if (!ssa->var_info) {
4701 ssa->var_info = zend_arena_calloc(arena, ssa->vars_count, sizeof(zend_ssa_var_info));
4702 }
4703 ssa_var_info = ssa->var_info;
4704
4705 if (!op_array->function_name) {
4706 for (i = 0; i < op_array->last_var; i++) {
4707 ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
4708 ssa_var_info[i].has_range = 0;
4709 }
4710 } else {
4711 for (i = 0; i < op_array->last_var; i++) {
4712 ssa_var_info[i].type = MAY_BE_UNDEF;
4713 ssa_var_info[i].has_range = 0;
4714 if (ssa->vars[i].alias) {
4715 ssa_var_info[i].type |= get_ssa_alias_types(ssa->vars[i].alias);
4716 }
4717 }
4718 }
4719 for (i = op_array->last_var; i < ssa->vars_count; i++) {
4720 ssa_var_info[i].type = 0;
4721 ssa_var_info[i].has_range = 0;
4722 }
4723
4724 if (zend_mark_cv_references(op_array, script, ssa) != SUCCESS) {
4725 return FAILURE;
4726 }
4727
4728 if (zend_infer_ranges(op_array, ssa) != SUCCESS) {
4729 return FAILURE;
4730 }
4731
4732 if (zend_infer_types(op_array, script, ssa, optimization_level) != SUCCESS) {
4733 return FAILURE;
4734 }
4735
4736 return SUCCESS;
4737 }
4738 /* }}} */
4739
zend_may_throw_ex(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa,uint32_t t1,uint32_t t2)4740 ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, uint32_t t1, uint32_t t2)
4741 {
4742 if (opline->op1_type == IS_CV) {
4743 if (t1 & MAY_BE_UNDEF) {
4744 switch (opline->opcode) {
4745 case ZEND_UNSET_VAR:
4746 case ZEND_ISSET_ISEMPTY_VAR:
4747 return 1;
4748 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
4749 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
4750 case ZEND_ASSIGN:
4751 case ZEND_ASSIGN_DIM:
4752 case ZEND_ASSIGN_REF:
4753 case ZEND_BIND_GLOBAL:
4754 case ZEND_BIND_STATIC:
4755 case ZEND_FETCH_DIM_IS:
4756 case ZEND_FETCH_OBJ_IS:
4757 case ZEND_SEND_REF:
4758 case ZEND_UNSET_CV:
4759 case ZEND_ISSET_ISEMPTY_CV:
4760 case ZEND_MAKE_REF:
4761 case ZEND_FETCH_DIM_W:
4762 break;
4763 default:
4764 /* undefined variable warning */
4765 return 1;
4766 }
4767 }
4768 } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
4769 if ((t1 & MAY_BE_RC1)
4770 && (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
4771 switch (opline->opcode) {
4772 case ZEND_CASE:
4773 case ZEND_CASE_STRICT:
4774 case ZEND_FE_FETCH_R:
4775 case ZEND_FE_FETCH_RW:
4776 case ZEND_FETCH_LIST_R:
4777 case ZEND_QM_ASSIGN:
4778 case ZEND_SEND_VAL:
4779 case ZEND_SEND_VAL_EX:
4780 case ZEND_SEND_VAR:
4781 case ZEND_SEND_VAR_EX:
4782 case ZEND_SEND_FUNC_ARG:
4783 case ZEND_SEND_VAR_NO_REF:
4784 case ZEND_SEND_VAR_NO_REF_EX:
4785 case ZEND_SEND_REF:
4786 case ZEND_SEPARATE:
4787 case ZEND_END_SILENCE:
4788 case ZEND_MAKE_REF:
4789 break;
4790 default:
4791 /* destructor may be called */
4792 return 1;
4793 }
4794 }
4795 }
4796
4797 if (opline->op2_type == IS_CV) {
4798 if (t2 & MAY_BE_UNDEF) {
4799 switch (opline->opcode) {
4800 case ZEND_ASSIGN_REF:
4801 case ZEND_FE_FETCH_R:
4802 case ZEND_FE_FETCH_RW:
4803 break;
4804 default:
4805 /* undefined variable warning */
4806 return 1;
4807 }
4808 }
4809 } else if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
4810 if ((t2 & MAY_BE_RC1)
4811 && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
4812 switch (opline->opcode) {
4813 case ZEND_ASSIGN:
4814 case ZEND_FE_FETCH_R:
4815 case ZEND_FE_FETCH_RW:
4816 break;
4817 default:
4818 /* destructor may be called */
4819 return 1;
4820 }
4821 }
4822 }
4823
4824 switch (opline->opcode) {
4825 case ZEND_NOP:
4826 case ZEND_IS_IDENTICAL:
4827 case ZEND_IS_NOT_IDENTICAL:
4828 case ZEND_QM_ASSIGN:
4829 case ZEND_JMP:
4830 case ZEND_CHECK_VAR:
4831 case ZEND_MAKE_REF:
4832 case ZEND_BEGIN_SILENCE:
4833 case ZEND_END_SILENCE:
4834 case ZEND_FREE:
4835 case ZEND_FE_FREE:
4836 case ZEND_SEPARATE:
4837 case ZEND_TYPE_CHECK:
4838 case ZEND_DEFINED:
4839 case ZEND_ISSET_ISEMPTY_THIS:
4840 case ZEND_COALESCE:
4841 case ZEND_SWITCH_LONG:
4842 case ZEND_SWITCH_STRING:
4843 case ZEND_MATCH:
4844 case ZEND_ISSET_ISEMPTY_VAR:
4845 case ZEND_ISSET_ISEMPTY_CV:
4846 case ZEND_FUNC_NUM_ARGS:
4847 case ZEND_FUNC_GET_ARGS:
4848 case ZEND_COPY_TMP:
4849 case ZEND_CASE_STRICT:
4850 case ZEND_JMP_NULL:
4851 return 0;
4852 case ZEND_SEND_VAR:
4853 case ZEND_SEND_VAL:
4854 case ZEND_SEND_REF:
4855 case ZEND_SEND_VAR_EX:
4856 case ZEND_SEND_FUNC_ARG:
4857 case ZEND_CHECK_FUNC_ARG:
4858 /* May throw for named params. */
4859 return opline->op2_type == IS_CONST;
4860 case ZEND_INIT_FCALL:
4861 /* can't throw, because call is resolved at compile time */
4862 return 0;
4863 case ZEND_BIND_GLOBAL:
4864 if ((opline+1)->opcode == ZEND_BIND_GLOBAL) {
4865 return zend_may_throw(opline + 1, ssa_op + 1, op_array, ssa);
4866 }
4867 return 0;
4868 case ZEND_ADD:
4869 if ((t1 & MAY_BE_ANY) == MAY_BE_ARRAY
4870 && (t2 & MAY_BE_ANY) == MAY_BE_ARRAY) {
4871 return 0;
4872 }
4873 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4874 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4875 case ZEND_DIV:
4876 if (!OP2_HAS_RANGE() ||
4877 (OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4878 /* Division by zero */
4879 return 1;
4880 }
4881 ZEND_FALLTHROUGH;
4882 case ZEND_SUB:
4883 case ZEND_MUL:
4884 case ZEND_POW:
4885 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4886 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4887 /* Ops may throw if not an integer */
4888 case ZEND_MOD:
4889 if (!OP2_HAS_RANGE() ||
4890 (OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4891 /* Division by zero */
4892 return 1;
4893 }
4894 ZEND_FALLTHROUGH;
4895 case ZEND_SL:
4896 case ZEND_SR:
4897 return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4898 (t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4899 !OP2_HAS_RANGE() ||
4900 OP2_MIN_RANGE() < 0;
4901 case ZEND_CONCAT:
4902 case ZEND_FAST_CONCAT:
4903 return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) ||
4904 (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
4905 case ZEND_BW_OR:
4906 case ZEND_BW_AND:
4907 case ZEND_BW_XOR:
4908 if ((t1 & MAY_BE_ANY) == MAY_BE_STRING
4909 && (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
4910 return 0;
4911 }
4912 return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4913 (t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4914 case ZEND_BW_NOT:
4915 return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4916 case ZEND_PRE_INC:
4917 case ZEND_POST_INC:
4918 case ZEND_PRE_DEC:
4919 case ZEND_POST_DEC:
4920 return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4921 case ZEND_BOOL_NOT:
4922 case ZEND_JMPZ:
4923 case ZEND_JMPNZ:
4924 case ZEND_JMPZNZ:
4925 case ZEND_JMPZ_EX:
4926 case ZEND_JMPNZ_EX:
4927 case ZEND_BOOL:
4928 case ZEND_JMP_SET:
4929 return (t1 & MAY_BE_OBJECT);
4930 case ZEND_BOOL_XOR:
4931 return (t1 & MAY_BE_OBJECT) || (t2 & MAY_BE_OBJECT);
4932 case ZEND_IS_EQUAL:
4933 case ZEND_IS_NOT_EQUAL:
4934 case ZEND_IS_SMALLER:
4935 case ZEND_IS_SMALLER_OR_EQUAL:
4936 case ZEND_CASE:
4937 case ZEND_SPACESHIP:
4938 if ((t1 & MAY_BE_ANY) == MAY_BE_NULL
4939 || (t2 & MAY_BE_ANY) == MAY_BE_NULL) {
4940 return 0;
4941 }
4942 return (t1 & (MAY_BE_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT)) || (t2 & (MAY_BE_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT));
4943 case ZEND_ASSIGN_OP:
4944 if (opline->extended_value == ZEND_ADD) {
4945 if ((t1 & MAY_BE_ANY) == MAY_BE_ARRAY
4946 && (t2 & MAY_BE_ANY) == MAY_BE_ARRAY) {
4947 return 0;
4948 }
4949 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4950 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4951 } else if (opline->extended_value == ZEND_DIV ||
4952 opline->extended_value == ZEND_MOD) {
4953 if (!OP2_HAS_RANGE() ||
4954 (OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4955 /* Division by zero */
4956 return 1;
4957 }
4958 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4959 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4960 } else if (opline->extended_value == ZEND_SUB ||
4961 opline->extended_value == ZEND_MUL ||
4962 opline->extended_value == ZEND_POW) {
4963 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4964 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4965 } else if (opline->extended_value == ZEND_SL ||
4966 opline->extended_value == ZEND_SR) {
4967 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4968 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4969 !OP2_HAS_RANGE() ||
4970 OP2_MIN_RANGE() < 0;
4971 } else if (opline->extended_value == ZEND_CONCAT) {
4972 return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) ||
4973 (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
4974 } else if (opline->extended_value == ZEND_BW_OR ||
4975 opline->extended_value == ZEND_BW_AND ||
4976 opline->extended_value == ZEND_BW_XOR) {
4977 if ((t1 & MAY_BE_ANY) == MAY_BE_STRING
4978 && (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
4979 return 0;
4980 }
4981 return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4982 (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4983 }
4984 return 1;
4985 case ZEND_ASSIGN:
4986 if (t1 & MAY_BE_REF) {
4987 return 1;
4988 }
4989 ZEND_FALLTHROUGH;
4990 case ZEND_UNSET_VAR:
4991 return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY));
4992 case ZEND_BIND_STATIC:
4993 if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) {
4994 /* Destructor may throw. */
4995 return 1;
4996 } else {
4997 zval *value = (zval*)((char*)op_array->static_variables->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
4998 /* May throw if initializer is CONSTANT_AST. */
4999 return Z_TYPE_P(value) == IS_CONSTANT_AST;
5000 }
5001 case ZEND_ASSIGN_DIM:
5002 if ((opline+1)->op1_type == IS_CV) {
5003 if (_ssa_op1_info(op_array, ssa, opline+1, ssa_op+1) & MAY_BE_UNDEF) {
5004 return 1;
5005 }
5006 }
5007 return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED ||
5008 (t2 & (MAY_BE_UNDEF|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5009 case ZEND_ASSIGN_OBJ:
5010 if (t1 & (MAY_BE_ANY-MAY_BE_OBJECT)) {
5011 return 1;
5012 }
5013 if ((opline+1)->op1_type == IS_CV) {
5014 if (_ssa_op1_info(op_array, ssa, opline+1, ssa_op+1) & MAY_BE_UNDEF) {
5015 return 1;
5016 }
5017 }
5018 if (ssa_op->op1_use) {
5019 zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use;
5020 zend_class_entry *ce = var_info->ce;
5021
5022 if (var_info->is_instanceof ||
5023 !ce || ce->create_object || ce->__get || ce->__set || ce->parent) {
5024 return 1;
5025 }
5026
5027 if (opline->op2_type != IS_CONST) {
5028 return 1;
5029 }
5030
5031 zend_string *prop_name = Z_STR_P(CRT_CONSTANT(opline->op2));
5032 if (ZSTR_LEN(prop_name) > 0 && ZSTR_VAL(prop_name)[0] == '\0') {
5033 return 1;
5034 }
5035
5036 if (op_array->scope != ce && ce->default_properties_count) {
5037 zend_property_info *prop_info =
5038 zend_hash_find_ptr(&ce->properties_info, prop_name);
5039 if (prop_info && (!(prop_info->flags & ZEND_ACC_PUBLIC)
5040 || ZEND_TYPE_IS_SET(prop_info->type))) {
5041 return 1;
5042 }
5043 }
5044 return 0;
5045 }
5046 return 1;
5047 case ZEND_ROPE_INIT:
5048 case ZEND_ROPE_ADD:
5049 case ZEND_ROPE_END:
5050 return t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT);
5051 case ZEND_INIT_ARRAY:
5052 return (opline->op2_type != IS_UNUSED) && (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5053 case ZEND_ADD_ARRAY_ELEMENT:
5054 return (opline->op2_type == IS_UNUSED) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5055 case ZEND_STRLEN:
5056 return (t1 & MAY_BE_ANY) != MAY_BE_STRING;
5057 case ZEND_COUNT:
5058 return (t1 & MAY_BE_ANY) != MAY_BE_ARRAY;
5059 case ZEND_RECV_INIT:
5060 if (Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_CONSTANT_AST) {
5061 return 1;
5062 }
5063 if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
5064 uint32_t arg_num = opline->op1.num;
5065 zend_arg_info *cur_arg_info;
5066
5067 if (EXPECTED(arg_num <= op_array->num_args)) {
5068 cur_arg_info = &op_array->arg_info[arg_num-1];
5069 } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
5070 cur_arg_info = &op_array->arg_info[op_array->num_args];
5071 } else {
5072 return 0;
5073 }
5074 return ZEND_TYPE_IS_SET(cur_arg_info->type);
5075 } else {
5076 return 0;
5077 }
5078 case ZEND_FETCH_IS:
5079 return (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5080 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
5081 return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5082 case ZEND_FETCH_DIM_IS:
5083 return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
5084 case ZEND_CAST:
5085 switch (opline->extended_value) {
5086 case IS_LONG:
5087 case IS_DOUBLE:
5088 return (t1 & MAY_BE_OBJECT);
5089 case IS_STRING:
5090 return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT));
5091 case IS_ARRAY:
5092 return (t1 & MAY_BE_OBJECT);
5093 case IS_OBJECT:
5094 return 0;
5095 EMPTY_SWITCH_DEFAULT_CASE()
5096 }
5097 /* GCC is getting confused here for the Wimplicit-fallthrough warning with
5098 * EMPTY_SWITCH_DEFAULT_CASE() macro */
5099 return 0;
5100 case ZEND_ARRAY_KEY_EXISTS:
5101 if ((t2 & MAY_BE_ANY) != MAY_BE_ARRAY) {
5102 return 1;
5103 }
5104 if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
5105 return 1;
5106 }
5107 return 0;
5108 case ZEND_FE_RESET_R:
5109 case ZEND_FE_RESET_RW:
5110 if ((t1 & (MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5111 return 1;
5112 }
5113 return 0;
5114 case ZEND_FE_FETCH_R:
5115 if ((t1 & (MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
5116 return 1;
5117 }
5118 if (opline->op2_type == IS_CV
5119 && (t2 & MAY_BE_RC1)
5120 && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
5121 return 1;
5122 }
5123 return 0;
5124 case ZEND_FETCH_DIM_W:
5125 case ZEND_FETCH_LIST_W:
5126 if (t1 & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
5127 return 1;
5128 }
5129 if (t2 & (MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
5130 return 1;
5131 }
5132 if (opline->op2_type == IS_UNUSED) {
5133 return 1;
5134 }
5135 return 0;
5136 default:
5137 return 1;
5138 }
5139 }
5140
zend_may_throw(const zend_op * opline,const zend_ssa_op * ssa_op,const zend_op_array * op_array,zend_ssa * ssa)5141 ZEND_API int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa)
5142 {
5143 return zend_may_throw_ex(opline, ssa_op, op_array, ssa, OP1_INFO(), OP2_INFO());
5144 }
5145