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