Skip to content

Commit 7585cf6

Browse files
committed
Fix GH-12953: SSA integrity verification failed when loading composer classmaps with more than 11k elements
This is a false positive. The cycle detection code stops at 10.000 iterations. Instead of stopping at a fixed amount, make it more robust by implementing Floyd's cycle detection algorithm. Closes GH-12954.
1 parent 731734d commit 7585cf6

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

Diff for: NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.2.15
44

5+
- Core:
6+
. Fixed bug GH-12953 (false positive SSA integrity verification failed when
7+
loading composer classmaps with more than 11k elements). (nielsdos)
8+
59
- Cli:
610
. Fix incorrect timeout in built-in web server when using router script and
711
max_input_time. (ilutov)

Diff for: Zend/Optimizer/ssa_integrity.c

+29-7
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ void ssa_verify_integrity(zend_op_array *op_array, zend_ssa *ssa, const char *ex
122122
/* Vars */
123123
for (i = 0; i < ssa->vars_count; i++) {
124124
zend_ssa_var *var = &ssa->vars[i];
125-
int use, c;
125+
int use;
126126
uint32_t type = ssa->var_info[i].type;
127127

128128
if (var->definition < 0 && !var->definition_phi && i > op_array->last_var) {
@@ -148,23 +148,45 @@ void ssa_verify_integrity(zend_op_array *op_array, zend_ssa *ssa, const char *ex
148148
}
149149
}
150150

151-
c = 0;
152-
FOREACH_USE(var, use) {
153-
if (++c > 10000) {
151+
/* Floyd's cycle detection algorithm, applied for use chain. */
152+
use = var->use_chain;
153+
int second_use = use;
154+
while (use >= 0 && second_use >= 0) {
155+
use = zend_ssa_next_use(ssa->ops, var - ssa->vars, use);
156+
second_use = zend_ssa_next_use(ssa->ops, var - ssa->vars, second_use);
157+
if (second_use < 0) {
158+
break;
159+
}
160+
second_use = zend_ssa_next_use(ssa->ops, var - ssa->vars, second_use);
161+
if (use == second_use) {
154162
FAIL("cycle in uses of " VARFMT "\n", VAR(i));
155163
goto finish;
156164
}
165+
}
166+
167+
FOREACH_USE(var, use) {
157168
if (!is_used_by_op(ssa, use, i)) {
158169
fprintf(stderr, "var " VARFMT " not in uses of op %d\n", VAR(i), use);
159170
}
160171
} FOREACH_USE_END();
161172

162-
c = 0;
163-
FOREACH_PHI_USE(var, phi) {
164-
if (++c > 10000) {
173+
/* Floyd's cycle detection algorithm, applied for phi nodes. */
174+
phi = var->phi_use_chain;
175+
zend_ssa_phi *second_phi = phi;
176+
while (phi && second_phi) {
177+
phi = zend_ssa_next_use_phi(ssa, var - ssa->vars, phi);
178+
second_phi = zend_ssa_next_use_phi(ssa, var - ssa->vars, second_phi);
179+
if (!second_phi) {
180+
break;
181+
}
182+
second_phi = zend_ssa_next_use_phi(ssa, var - ssa->vars, second_phi);
183+
if (phi == second_phi) {
165184
FAIL("cycle in phi uses of " VARFMT "\n", VAR(i));
166185
goto finish;
167186
}
187+
}
188+
189+
FOREACH_PHI_USE(var, phi) {
168190
if (!is_in_phi_sources(ssa, phi, i)) {
169191
FAIL("var " VARFMT " not in phi sources of %d\n", VAR(i), phi->ssa_var);
170192
}

0 commit comments

Comments
 (0)