mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-20 11:20:41 -07:00
Improve no Symbol leak tests to be more reliable
This commit is contained in:
@@ -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