-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix large for-loop collection #1071
base: main
Are you sure you want to change the base?
Conversation
A large collection in a for loop results in a crash or large memory usage during render.
If a large collection is given to a for block, this may crash the render process of the template. Setting of resource_limits does not help because these are tested at a later stage. This can be prevented by adding a simple check to the Liquid::For block which makes sure that a collection size does never exceed the set render_score_limit.
BTW: You can checkout this branch to show the behavior for a large given collection without the fix: https://github.com/stayhero/liquid/tree/large_forloop_failing_test?files=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch!
Long-term I think it would make sense to iterate ranges more efficiently without constructing the intermediate array. Some range math can be done for the common cases to handle reverse and offsets. This patch makes sense as a solution for now though.
Resource limit gets triggered without a nested loop in the test for a large collection range.
@pushrax Anything missing to merge the PR? |
@pushrax: ping |
👋 Friendly bump to see what it would take to merge. |
When a large Range is given in a for-loop (e.g. 1..100000000000000), it may crash the Ruby process or at least eats a lot of memory and takes a significant amount of time to render the template.
I added the following testcase to template_test.rb:
The render_score_limit does not help here because it's more of a Ruby performance problem in for.rb, where the
collection = collection.to_a if collection.is_a?(Range)
happens.A fix may be to check if the given Range is larger than the given render_score_limit. I'm actually not sure if there may be a better fix (e.g. checking the resource limits somewhere else) but at least it works for the given test case.