summaryrefslogtreecommitdiff
path: root/test/ruby
diff options
context:
space:
mode:
authorDaniel Colson <danieljamescolson@gmail.com>2024-04-24 22:20:48 -0400
committerPeter Zhu <peter@peterzhu.ca>2024-04-25 10:28:18 -0400
commitd292a9b98ce03c76dbe13138d20b9fbf613cc02d (patch)
tree5b2919050b343a900176ecfc9280416e2ed6323d /test/ruby
parent7ab1a608e7413cdb0f93243eb3e6e20a32cec44e (diff)
[Bug #20453] segfault in Regexp timeout
https://bugs.ruby-lang.org/issues/20228 started freeing `stk_base` to avoid a memory leak. But `stk_base` is sometimes stack allocated (using `xalloca`), so the free only works if the regex stack has grown enough to hit `stack_double` (which uses `xmalloc` and `xrealloc`). To reproduce the problem on master and 3.3.1: ```ruby Regexp.timeout = 0.001 /^(a*)x$/ =~ "a" * 1000000 + "x"' ``` Some details about this potential fix: `stk_base == stk_alloc` on [init](https://github.com/ruby/ruby/blob/dde99215f2bc60c22a00fc941ff7f714f011e920/regexec.c#L1153), so if `stk_base != stk_alloc` we can be sure we called [`stack_double`](https://github.com/ruby/ruby/blob/dde99215f2bc60c22a00fc941ff7f714f011e920/regexec.c#L1210) and it's safe to free. It's also safe to free if we've [saved](https://github.com/ruby/ruby/blob/dde99215f2bc60c22a00fc941ff7f714f011e920/regexec.c#L1187-L1189) the stack to `msa->stack_p`, since we do the `stk_base != stk_alloc` check before saving. This matches the check we do inside [`stack_double`](https://github.com/ruby/ruby/blob/dde99215f2bc60c22a00fc941ff7f714f011e920/regexec.c#L1221)
Diffstat (limited to 'test/ruby')
-rw-r--r--test/ruby/test_regexp.rb11
1 files changed, 11 insertions, 0 deletions
diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb
index c996b1785a..03d96954b4 100644
--- a/test/ruby/test_regexp.rb
+++ b/test/ruby/test_regexp.rb
@@ -1827,6 +1827,17 @@ class TestRegexp < Test::Unit::TestCase
end;
end
+ def test_bug_20453
+ assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
+ begin;
+ Regexp.timeout = 0.001
+
+ assert_raise(Regexp::TimeoutError) do
+ /^(a*)x$/ =~ "a" * 1000000 + "x"
+ end
+ end;
+ end
+
def per_instance_redos_test(global_timeout, per_instance_timeout, expected_timeout)
assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
global_timeout = #{ EnvUtil.apply_timeout_scale(global_timeout).inspect }