From 8393a0e9a8a9e6d8dbfa16ef8d6513f1d182087a Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 9 Jul 2021 06:19:03 +0900 Subject: [PATCH 1/7] Extracted common leading pattern --- ext/date/date_parse.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index 5fa036e..91e294e 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -652,24 +652,27 @@ parse_time(VALUE str, VALUE hash) { static const char pat_source[] = "(" + "\\d+\\s*" "(?:" - "\\d+\\s*:\\s*\\d+" "(?:" + ":\\s*\\d+" + "(?:" #ifndef TIGHT_PARSER - "\\s*:\\s*\\d+(?:[,.]\\d*)?" + "\\s*:\\s*\\d+(?:[,.]\\d*)?" #else - "\\s*:\\s*\\d+(?:[,.]\\d+)?" + "\\s*:\\s*\\d+(?:[,.]\\d+)?" #endif + ")?" + "|" + "h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?" + ")" + "(?:" + "\\s*" + "[ap](?:m\\b|\\.m\\.)" ")?" "|" - "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?" - ")" - "(?:" - "\\s*" "[ap](?:m\\b|\\.m\\.)" - ")?" - "|" - "\\d+\\s*[ap](?:m\\b|\\.m\\.)" + ")" ")" "(?:" "\\s*" From 06301af9fa8749084427e66afa445b3a05f98037 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 9 Jul 2021 06:35:58 +0900 Subject: [PATCH 2/7] Use possessive match Reduce backtracks at the same character classes arounding an optional pattern. --- ext/date/date_parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index 91e294e..0e7067f 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -922,8 +922,8 @@ parse_us(VALUE str, VALUE hash) COM_FPT #endif "(?:" - "\\s*,?" - "\\s*" + "\\s*+,?" + "\\s*+" #ifndef TIGHT_PARSER "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?" "\\s*" From 76656a12e0baea03647fd3e472e18e7aa8069217 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Fri, 9 Jul 2021 06:41:29 +0900 Subject: [PATCH 3/7] Separate era from preceding word --- ext/date/date_parse.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index 0e7067f..021df37 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -694,6 +694,9 @@ parse_time(VALUE str, VALUE hash) #endif } +#define BEGIN_ERA "\\b" +#define END_ERA "(?!(? Date: Fri, 9 Jul 2021 07:21:27 +0900 Subject: [PATCH 4/7] Anchor at beginning of numbers https://hackerone.com/reports/1254844 --- ext/date/date_parse.c | 16 +++++++++------- test/date/test_date_parse.rb | 7 +++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index 021df37..9511bed 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -253,6 +253,8 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) #define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat" #define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec" +#define NUMBER "(? Date: Fri, 9 Jul 2021 07:21:27 +0900 Subject: [PATCH 5/7] Anchor at beginning of numbers https://hackerone.com/reports/1254844 --- ext/date/date_parse.c | 2 +- test/date/test_date_parse.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c index 9511bed..95274d5 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -980,7 +980,7 @@ parse_iso(VALUE str, VALUE hash) { static const char pat_source[] = #ifndef TIGHT_PARSER - "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)" + "('?[-+]?" NUMBER "+)-(\\d+)-('?-?\\d+)" #else BOS FPW_COM FPT_COM diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb index a87b165..8876104 100644 --- a/test/date/test_date_parse.rb +++ b/test/date/test_date_parse.rb @@ -590,6 +590,11 @@ def test__parse_too_long_year h = Timeout.timeout(1) {Date._parse(str)} assert_equal(100_000, Math.log10(h[:year])) assert_equal(1, h[:mon]) + + str = "Jan - 1" + "0" * 100_000 + h = Timeout.timeout(1) {Date._parse(str)} + assert_equal(1, h[:mon]) + assert_not_include(h, :year) end require 'time' From 72da893db7935a64bbd079518ac82ed503dee8d8 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 24 Nov 2021 18:05:12 +0900 Subject: [PATCH 6/7] Update tests --- test/date/test_date_parse.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb index 8876104..9a03ca8 100644 --- a/test/date/test_date_parse.rb +++ b/test/date/test_date_parse.rb @@ -587,12 +587,12 @@ def test__parse_odd_offset def test__parse_too_long_year str = "Jan 1" + "0" * 100_000 - h = Timeout.timeout(1) {Date._parse(str)} + h = Timeout.timeout(1) {Date._parse(str, limit: 100_010)} assert_equal(100_000, Math.log10(h[:year])) assert_equal(1, h[:mon]) str = "Jan - 1" + "0" * 100_000 - h = Timeout.timeout(1) {Date._parse(str)} + h = Timeout.timeout(1) {Date._parse(str, limit: 100_010)} assert_equal(1, h[:mon]) assert_not_include(h, :year) end @@ -1309,6 +1309,5 @@ def test_length_limit assert_raise(ArgumentError) { DateTime.jisx0301("1" * 1000) } assert_raise(ArgumentError) { Date._parse("Jan " + "9" * 1000000) } - assert_raise(Timeout::Error) { Timeout.timeout(1) { Date._parse("Jan " + "9" * 1000000, limit: nil) } } end end From 2c00fcec38d0dabd7bb003ec9f66503304968817 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 24 Nov 2021 18:08:42 +0900 Subject: [PATCH 7/7] Scale timeouts --- test/date/test_date_parse.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb index 9a03ca8..574ead3 100644 --- a/test/date/test_date_parse.rb +++ b/test/date/test_date_parse.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'test/unit' require 'date' -require 'timeout' +require 'envutil' class TestDateParse < Test::Unit::TestCase @@ -587,12 +587,12 @@ def test__parse_odd_offset def test__parse_too_long_year str = "Jan 1" + "0" * 100_000 - h = Timeout.timeout(1) {Date._parse(str, limit: 100_010)} + h = EnvUtil.timeout(1) {Date._parse(str, limit: 100_010)} assert_equal(100_000, Math.log10(h[:year])) assert_equal(1, h[:mon]) str = "Jan - 1" + "0" * 100_000 - h = Timeout.timeout(1) {Date._parse(str, limit: 100_010)} + h = EnvUtil.timeout(1) {Date._parse(str, limit: 100_010)} assert_equal(1, h[:mon]) assert_not_include(h, :year) end