summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2023-07-23 12:20:12 +0900
committernagachika <nagachika@ruby-lang.org>2023-07-23 12:20:12 +0900
commit0b3ed6043c9d091d499ca1caed604a983c7e285b (patch)
tree7294b31aa3fcd86585c6302309f24df8e1a5a575
parent3354aacb73c65420a10cb41c0696e62dd1ba279b (diff)
merge revision(s) 5d4fff845602872eef072e7611558b5f8762efe0: [Backport #19293]
Tighten Time.new(string) parsing Disallow: * Only year-month * Only year-month-day * Preceding whitespace * Trailing whitespace Fixes [Bug #19293] --- test/ruby/test_time.rb | 13 +++++++++++++ time.c | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-)
-rw-r--r--test/ruby/test_time.rb13
-rw-r--r--time.c13
-rw-r--r--version.h2
3 files changed, 26 insertions, 2 deletions
diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb
index f47a49d3e0..0faad878fc 100644
--- a/test/ruby/test_time.rb
+++ b/test/ruby/test_time.rb
@@ -75,6 +75,7 @@ class TestTime < Test::Unit::TestCase
Time.new("2020-12-25 00 +09:00")
}
+ assert_equal(Time.new(2021), Time.new("2021"))
assert_equal(Time.new(2021, 12, 25, in: "+09:00"), Time.new("2021-12-25+09:00"))
assert_equal(0.123456r, Time.new("2021-12-25 00:00:00.123456 +09:00").subsec)
@@ -138,6 +139,18 @@ class TestTime < Test::Unit::TestCase
assert_raise_with_message(ArgumentError, /mon out of range/) {
Time.new("2020-17-25 00:56:17 +0900")
}
+ assert_raise_with_message(ArgumentError, /no time information/) {
+ Time.new("2020-12")
+ }
+ assert_raise_with_message(ArgumentError, /no time information/) {
+ Time.new("2020-12-02")
+ }
+ assert_raise_with_message(ArgumentError, /can't parse/) {
+ Time.new(" 2020-12-02 00:00:00")
+ }
+ assert_raise_with_message(ArgumentError, /can't parse/) {
+ Time.new("2020-12-02 00:00:00 ")
+ }
end
def test_time_add()
diff --git a/time.c b/time.c
index f1d327f501..50bdb2bf6b 100644
--- a/time.c
+++ b/time.c
@@ -2525,7 +2525,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
size_t ndigits;
size_t prec = NIL_P(precision) ? SIZE_MAX : NUM2SIZET(precision);
- while ((ptr < end) && ISSPACE(*ptr)) ptr++;
+ if ((ptr < end) && (ISSPACE(*ptr) || ISSPACE(*(end-1)))) {
+ rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str);
+ }
year = parse_int(ptr, end, &ptr, &ndigits, true);
if (NIL_P(year)) {
rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str);
@@ -2533,6 +2535,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
else if (ndigits < 4) {
rb_raise(rb_eArgError, "year must be 4 or more digits: %.*s", (int)ndigits, ptr - ndigits);
}
+ else if (ptr == end) {
+ goto only_year;
+ }
do {
#define peekable_p(n) ((ptrdiff_t)(n) < (end - ptr))
#define peek_n(c, n) (peekable_p(n) && ((unsigned char)ptr[n] == (c)))
@@ -2593,6 +2598,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
if (zend > zstr) {
zone = rb_str_subseq(str, zstr - begin, zend - zstr);
}
+ else if (hour == -1) {
+ rb_raise(rb_eArgError, "no time information");
+ }
if (!NIL_P(subsec)) {
/* subseconds is the last using ndigits */
static const size_t TIME_SCALE_NUMDIGITS =
@@ -2609,6 +2617,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone,
}
}
+only_year:
+ ;
+
struct vtm vtm = {
.wday = VTM_WDAY_INITVAL,
.yday = 0,
diff --git a/version.h b/version.h
index 5532e4cf36..35c6adfc97 100644
--- a/version.h
+++ b/version.h
@@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 2
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 104
+#define RUBY_PATCHLEVEL 105
#include "ruby/version.h"
#include "ruby/internal/abi.h"