mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-12 23:40:45 -07:00
Merge pull request #2038 from eregon/truffleruby-ci
Add TruffleRuby in CI
This commit is contained in:
@@ -22,6 +22,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
- { ruby: 4.0, allowed-failure: false, rubyopt: "--yjit" }
|
- { ruby: 4.0, allowed-failure: false, rubyopt: "--yjit" }
|
||||||
- { ruby: 4.0, allowed-failure: false, rubyopt: "--zjit" }
|
- { ruby: 4.0, allowed-failure: false, rubyopt: "--zjit" }
|
||||||
|
- { ruby: truffleruby, allowed-failure: false }
|
||||||
|
|
||||||
# Head can have failures due to being in development
|
# Head can have failures due to being in development
|
||||||
- { ruby: head, allowed-failure: true }
|
- { ruby: head, allowed-failure: true }
|
||||||
|
|||||||
@@ -8,10 +8,19 @@ module Liquid
|
|||||||
MAX_I32 = (1 << 31) - 1
|
MAX_I32 = (1 << 31) - 1
|
||||||
private_constant :MAX_I32
|
private_constant :MAX_I32
|
||||||
|
|
||||||
MIN_I64 = -(1 << 63)
|
supports_64bit_indices = begin
|
||||||
MAX_I64 = (1 << 63) - 1
|
[][1 << 33, 1 << 33]
|
||||||
I64_RANGE = MIN_I64..MAX_I64
|
true
|
||||||
private_constant :MIN_I64, :MAX_I64, :I64_RANGE
|
rescue RangeError
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
INDEX_RANGE = if supports_64bit_indices
|
||||||
|
(-(1 << 63))..((1 << 63) - 1)
|
||||||
|
else
|
||||||
|
(-(1 << 31))..((1 << 31) - 1)
|
||||||
|
end
|
||||||
|
private_constant :INDEX_RANGE
|
||||||
|
|
||||||
HTML_ESCAPE = {
|
HTML_ESCAPE = {
|
||||||
'&' => '&',
|
'&' => '&',
|
||||||
@@ -214,11 +223,11 @@ module Liquid
|
|||||||
Utils.to_s(input).slice(offset, length) || ''
|
Utils.to_s(input).slice(offset, length) || ''
|
||||||
end
|
end
|
||||||
rescue RangeError
|
rescue RangeError
|
||||||
if I64_RANGE.cover?(length) && I64_RANGE.cover?(offset)
|
if INDEX_RANGE.cover?(length) && INDEX_RANGE.cover?(offset)
|
||||||
raise # unexpected error
|
raise # unexpected error
|
||||||
end
|
end
|
||||||
offset = offset.clamp(I64_RANGE)
|
offset = offset.clamp(INDEX_RANGE)
|
||||||
length = length.clamp(I64_RANGE)
|
length = length.clamp(INDEX_RANGE)
|
||||||
retry
|
retry
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -44,32 +44,39 @@ class SecurityTest < Minitest::Test
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_permanently_add_filters_to_symbol_table
|
def test_does_not_permanently_add_filters_to_symbol_table
|
||||||
current_symbols = Symbol.all_symbols
|
assert_no_new_symbols do
|
||||||
|
# MRI imprecisely marks objects found on the C stack, which can result
|
||||||
|
# in uninitialized memory being marked. This can even result in the test failing
|
||||||
|
# deterministically for a given compilation of ruby. Using a separate thread will
|
||||||
|
# keep these writes of the symbol pointer on a separate stack that will be garbage
|
||||||
|
# collected after Thread#join.
|
||||||
|
Thread.new do
|
||||||
|
test = %( {{ "some_string" | a_bad_filter }} )
|
||||||
|
Template.parse(test).render!
|
||||||
|
nil
|
||||||
|
end.join
|
||||||
|
|
||||||
# MRI imprecisely marks objects found on the C stack, which can result
|
GC.start
|
||||||
# in uninitialized memory being marked. This can even result in the test failing
|
end
|
||||||
# deterministically for a given compilation of ruby. Using a separate thread will
|
|
||||||
# keep these writes of the symbol pointer on a separate stack that will be garbage
|
|
||||||
# collected after Thread#join.
|
|
||||||
Thread.new do
|
|
||||||
test = %( {{ "some_string" | a_bad_filter }} )
|
|
||||||
Template.parse(test).render!
|
|
||||||
nil
|
|
||||||
end.join
|
|
||||||
|
|
||||||
GC.start
|
|
||||||
|
|
||||||
assert_equal([], Symbol.all_symbols - current_symbols)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_does_not_add_drop_methods_to_symbol_table
|
def test_does_not_add_drop_methods_to_symbol_table
|
||||||
|
assert_no_new_symbols do
|
||||||
|
assigns = { 'drop' => Drop.new }
|
||||||
|
assert_equal("", Template.parse("{{ drop.custom_method_1 }}", assigns).render!)
|
||||||
|
assert_equal("", Template.parse("{{ drop.custom_method_2 }}", assigns).render!)
|
||||||
|
assert_equal("", Template.parse("{{ drop.custom_method_3 }}", assigns).render!)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_no_new_symbols
|
||||||
|
# Run once to trigger any first-time initialization which might create some symbols,
|
||||||
|
# for example autoload or lazy method parsing might create symbols on first execution.
|
||||||
|
yield
|
||||||
|
|
||||||
|
# Ensure no new symbols for further runs, i.e. the code does not leak symbols
|
||||||
current_symbols = Symbol.all_symbols
|
current_symbols = Symbol.all_symbols
|
||||||
|
yield
|
||||||
assigns = { 'drop' => Drop.new }
|
|
||||||
assert_equal("", Template.parse("{{ drop.custom_method_1 }}", assigns).render!)
|
|
||||||
assert_equal("", Template.parse("{{ drop.custom_method_2 }}", assigns).render!)
|
|
||||||
assert_equal("", Template.parse("{{ drop.custom_method_3 }}", assigns).render!)
|
|
||||||
|
|
||||||
assert_equal([], Symbol.all_symbols - current_symbols)
|
assert_equal([], Symbol.all_symbols - current_symbols)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user