From 63f98999aa2535d52ae4696324718bdc78fa6fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Jul 2022 12:19:43 +0200 Subject: [PATCH 1/4] gh-94675: Add a regression test for rjsmin re slowdown --- Lib/test/test_re.py | 15 +++++++++++++++ .../2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 1 + 2 files changed, 16 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 9f734d47c544991..86e704aae033591 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2407,6 +2407,21 @@ def test_template_function_and_flag_is_deprecated(self): self.assertTrue(template_re1.match('ahoy')) self.assertFalse(template_re1.match('nope')) + def test_regression_gh94675(self): + start = time.perf_counter() + pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' + r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' + r'[^/\[]*)*/))((((//[^\n]*)?[\n])' + r'([\000-\040]|(/\*[^*]*\*+' + r'([^/*]\*+)*/))*)+(?=[^\000-\040);\]}]))') + input_js = '''a(function() { + /////////////////////////////////////////////////////////////////// + });''' + _ = pattern.sub('', input_js) + t = time.perf_counter() - start + # Without optimization it takes 0.017 second on my computer. + self.assertLess(t, 0.5) + def get_debug_out(pat): with captured_stdout() as out: diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst new file mode 100644 index 000000000000000..f43bc717e4252ff --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst @@ -0,0 +1 @@ +Add a regreesion test for :mod:`re` exponencional slowdon when using rjsmin. From ee602ea326e01c4f03805f612434d3e0e65e06a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Jul 2022 12:45:33 +0200 Subject: [PATCH 2/4] fixup! gh-94675: Add a regression test for rjsmin re slowdown Use multiprocessing to kill the test after SHORT_TIMEOUT. --- Lib/test/test_re.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 86e704aae033591..6567ace42a5bfff 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1,6 +1,8 @@ from test.support import (gc_collect, bigmemtest, _2G, cpython_only, captured_stdout, - check_disallow_instantiation, is_emscripten, is_wasi) + check_disallow_instantiation, is_emscripten, is_wasi, + SHORT_TIMEOUT) +import multiprocessing import locale import re import string @@ -2408,7 +2410,6 @@ def test_template_function_and_flag_is_deprecated(self): self.assertFalse(template_re1.match('nope')) def test_regression_gh94675(self): - start = time.perf_counter() pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))' r'[^/\[]*)*/))((((//[^\n]*)?[\n])' @@ -2417,10 +2418,15 @@ def test_regression_gh94675(self): input_js = '''a(function() { /////////////////////////////////////////////////////////////////// });''' - _ = pattern.sub('', input_js) - t = time.perf_counter() - start - # Without optimization it takes 0.017 second on my computer. - self.assertLess(t, 0.5) + p = multiprocessing.Process(target=pattern.sub, args=('', input_js)) + p.start() + p.join(SHORT_TIMEOUT) + try: + self.assertFalse(p.is_alive(), 'pattern.sub() timed out') + finally: + if p.is_alive(): + p.terminate() + p.join() def get_debug_out(pat): From c8a850e5fb3ecf8ef2b23a779b71f3eef68d8e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Jul 2022 13:22:20 +0200 Subject: [PATCH 3/4] Fix typos Co-authored-by: Oleg Iarygin --- .../next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst index f43bc717e4252ff..d0005d9f6014cd7 100644 --- a/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst +++ b/Misc/NEWS.d/next/Tests/2022-07-08-12-22-00.gh-issue-94675.IiTs5f.rst @@ -1 +1 @@ -Add a regreesion test for :mod:`re` exponencional slowdon when using rjsmin. +Add a regression test for :mod:`re` exponentional slowdown when using rjsmin. From 7a039473276a497eb8676a954d3c1afe26a14a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Fri, 8 Jul 2022 17:12:01 +0200 Subject: [PATCH 4/4] Skip the test without multiprocessing --- Lib/test/test_re.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 6567ace42a5bfff..3f0f84ea8cee6fa 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -2,7 +2,6 @@ cpython_only, captured_stdout, check_disallow_instantiation, is_emscripten, is_wasi, SHORT_TIMEOUT) -import multiprocessing import locale import re import string @@ -13,6 +12,14 @@ from re import Scanner from weakref import proxy +# some platforms lack working multiprocessing +try: + import _multiprocessing +except ImportError: + multiprocessing = None +else: + import multiprocessing + # Misc tests from Tim Peters' re.doc # WARNING: Don't change details in these tests if you don't know @@ -2409,6 +2416,7 @@ def test_template_function_and_flag_is_deprecated(self): self.assertTrue(template_re1.match('ahoy')) self.assertFalse(template_re1.match('nope')) + @unittest.skipIf(multiprocessing is None, 'test requires multiprocessing') def test_regression_gh94675(self): pattern = re.compile(r'(?<=[({}])(((//[^\n]*)?[\n])([\000-\040])*)*' r'((/[^/\[\n]*(([^\n]|(\[\n]*(]*)*\]))'