Skip to content

Fix GH-11240: PHP crashes on big file with array inside - #11272

Closed
ndossche wants to merge 3 commits into
php:PHP-8.1from
ndossche:iterative-scc-squashed
Closed

ndossche wants to merge 3 commits into
php:PHP-8.1from
ndossche:iterative-scc-squashed

Conversation

@ndossche

@ndossche ndossche commented May 18, 2023 •

Copy link
Copy Markdown
Member

The crash happens because there's a stack overflow in the recursive SCC algorithm. Fix this by transforming it into an iterative implementation of the same algorithm. We manually keep the recursion stack now.

I tested the correctness by running the CI test suite using both the old implementation and the new implementation and letting the test fail if the SCC values differ. The tests passed without failure.

For the test case of OP, I benchmarked the performance:
With this patch

  Time (mean ± σ):     645.9 ms ±   7.4 ms    [User: 603.7 ms, System: 40.7 ms]
  Range (min … max):   634.0 ms … 659.3 ms    10 runs

Without this patch

  Time (mean ± σ):     755.3 ms ±  18.1 ms    [User: 698.8 ms, System: 55.2 ms]
  Range (min … max):   737.6 ms … 784.4 ms    10 runs

We can see an improvement in performance as well because the function call overhead and control transfer overhead is eliminated now.

The crash happens because there's a stack overflow in the recursive SCC
algorithm. Fix this by transforming it into an iterative implementation
of the same algorithm. We manually keep the recursion stack now.

I tested the correctness by running the CI test suite using both the old
implementation and the new implementation and letting the test fail if
the SCC values differ. The tests passed without failure.

For the test case of OP, I benchmarked the performance:
With this patch
  Time (mean ± σ):     645.9 ms ±   7.4 ms    [User: 603.7 ms, System: 40.7 ms]
  Range (min … max):   634.0 ms … 659.3 ms    10 runs
Without this patch
  Time (mean ± σ):     755.3 ms ±  18.1 ms    [User: 698.8 ms, System: 55.2 ms]
  Range (min … max):   737.6 ms … 784.4 ms    10 runs

We can see an improvement in performance as well because the function
call overhead and control transfer overhead is eliminated now.
@ndossche
ndossche requested review from dstogov and iluuu1994 May 18, 2023 23:38
@ndossche ndossche linked an issue May 18, 2023 that may be closed by this pull request

@dstogov dstogov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to spend a bit more time converting this algorithm or finding the reference iterative implementation. See https://arxiv.org/pdf/1703.10023.pdf for example.

Comment thread Zend/Optimizer/zend_inference.c
Comment thread Zend/Optimizer/zend_inference.c Outdated
Comment on lines +87 to +101
/* Need to come back from "recursion" */ \
recursion_stack[recursion_stack_idx].var = var; \
recursion_stack[recursion_stack_idx].current_use = use; \
recursion_stack[recursion_stack_idx].current_phi = p; \
STORE_CURRENT_SYM; \
recursion_stack_idx++; \
/* "Recurse" on next var */ \
var = var2; \
use = ssa->vars[var].use_chain; \
p = ssa->vars[var].phi_use_chain; \
sym_p = ssa->vars[var].sym_use_chain; \
dfs[var] = *index; \
(*index)++; \
root[var] = var; \
goto recurse; \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintaining of stack with 3 additional lists looks a bit weird to me.
Did you use some reference algorithm implementation or invent this yourself?

@dstogov

dstogov commented May 22, 2023

Copy link
Copy Markdown
Member

Also see an implementation of improved algorithm https://github.com/DavePearce/StronglyConnectedComponents

@ndossche

Copy link
Copy Markdown
Member Author

I checked out https://arxiv.org/pdf/1703.10023.pdf. It does provide some optimisation ideas, one of which already happens (combine visited[] and dfs[] into a single array dfs). And it also gives some more ideas. It does not however provide a reference algorithm for iterative SCC.

Maintaining of stack with 3 additional lists looks a bit weird to me.
Did you use some reference algorithm implementation or invent this yourself?

I did it myself. Let me explain the additional items on the stack.
It's not strictly necessary to push the items on the stack, this is just a performance improvement.
The reason: when we return to a var on the recursion stack, we want to resume the iteration of the uses from the last use or phi node that caused the recursion. Iterating from the start of the use list is also correct, but wasteful of performance: it just updates the root but since the root was already updated this doesn't do anything new.

In Dave Pearce's algorithm we'd still have to maintain the additional items on the stack.
Dave Pearce does however improve the space cost of Tarjan's algorithm by merging two lists into one. I can probably take a look at implementing this if you want.

@dstogov

dstogov commented May 29, 2023

Copy link
Copy Markdown
Member

Let me know when I should review this once again.

@dstogov

dstogov commented Oct 27, 2023

Copy link
Copy Markdown
Member

Closed in favour of #12528

@dstogov dstogov closed this Oct 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants