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