From fe66edb8254a4af4af3a69a32884178e2263c421 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 23 Oct 2020 10:53:16 -0400 Subject: [PATCH] Freeze block body after parsing completes --- Gemfile | 2 +- lib/liquid/block.rb | 1 + lib/liquid/block_body.rb | 9 +++++++++ lib/liquid/document.rb | 1 + lib/liquid/tags/case.rb | 6 +++++- lib/liquid/tags/for.rb | 2 ++ lib/liquid/tags/if.rb | 1 + 7 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 14537c6..338fe56 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,6 @@ group :test do gem 'rubocop-performance', require: false platform :mri, :truffleruby do - gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'master' + gem 'liquid-c', github: 'Shopify/liquid-c', ref: 'pz-block-body-buffer' end end diff --git a/lib/liquid/block.rb b/lib/liquid/block.rb index 47d5f25..d6619f9 100644 --- a/lib/liquid/block.rb +++ b/lib/liquid/block.rb @@ -13,6 +13,7 @@ module Liquid @body = new_body while parse_body(@body, tokens) end + @body.freeze(parse_context) end # For backwards compatibility diff --git a/lib/liquid/block_body.rb b/lib/liquid/block_body.rb index 67d5d63..f61ae87 100644 --- a/lib/liquid/block_body.rb +++ b/lib/liquid/block_body.rb @@ -16,9 +16,12 @@ module Liquid def initialize @nodelist = [] @blank = true + @frozen = false end def parse(tokenizer, parse_context, &block) + raise FrozenError, "can't modify frozen Liquid::BlockBody" if @frozen + parse_context.line_number = tokenizer.line_number if tokenizer.for_liquid_tag @@ -28,6 +31,10 @@ module Liquid end end + def freeze(_context) + @frozen = true + end + private def parse_for_liquid_tag(tokenizer, parse_context) while (token = tokenizer.shift) unless token.empty? || token =~ WhitespaceOrNothing @@ -192,6 +199,8 @@ module Liquid end def render_to_output_buffer(context, output) + raise "Can only render when frozen" unless @frozen + context.resource_limits.increment_render_score(@nodelist.length) idx = 0 diff --git a/lib/liquid/document.rb b/lib/liquid/document.rb index 2e47ffb..21ddec2 100644 --- a/lib/liquid/document.rb +++ b/lib/liquid/document.rb @@ -22,6 +22,7 @@ module Liquid def parse(tokenizer, parse_context) while parse_body(tokenizer) end + @body.freeze(parse_context) rescue SyntaxError => e e.line_number ||= parse_context.line_number raise diff --git a/lib/liquid/tags/case.rb b/lib/liquid/tags/case.rb index b46fa05..cc85ed4 100644 --- a/lib/liquid/tags/case.rb +++ b/lib/liquid/tags/case.rb @@ -20,7 +20,11 @@ module Liquid def parse(tokens) body = new_body - body = @blocks.last.attachment while parse_body(body, tokens) + while parse_body(body, tokens) + body.freeze(parse_context) + body = @blocks.last.attachment + end + body.freeze(parse_context) if blank? @blocks.each { |condition| condition.attachment.remove_blank_strings } end diff --git a/lib/liquid/tags/for.rb b/lib/liquid/tags/for.rb index 6f66ebd..9a81b4d 100644 --- a/lib/liquid/tags/for.rb +++ b/lib/liquid/tags/for.rb @@ -61,7 +61,9 @@ module Liquid def parse(tokens) if parse_body(@for_block, tokens) parse_body(@else_block, tokens) + @else_block.freeze(parse_context) end + @for_block.freeze(parse_context) if blank? @for_block.remove_blank_strings @else_block&.remove_blank_strings diff --git a/lib/liquid/tags/if.rb b/lib/liquid/tags/if.rb index c910b0b..7632be9 100644 --- a/lib/liquid/tags/if.rb +++ b/lib/liquid/tags/if.rb @@ -31,6 +31,7 @@ module Liquid def parse(tokens) while parse_body(@blocks.last.attachment, tokens) end + @blocks.each { |block| block.attachment.freeze(parse_context) } if blank? @blocks.each { |condition| condition.attachment.remove_blank_strings } end