[Feature #18033] More strict checks
This commit is contained in:
parent
0a2f300a8a
commit
67c589afa0
Notes:
git
2022-12-16 13:53:20 +00:00
@ -76,6 +76,42 @@ class TestTime < Test::Unit::TestCase
|
||||
assert_raise_with_message(ArgumentError, "subsecond expected after dot: 00:56:17. ") {
|
||||
Time.new("2020-12-25 00:56:17. +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /year must be 2 or 4\+/) {
|
||||
Time.new("021-12-25 00:00:00.123456 +09:00")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /fraction min is.*56\./) {
|
||||
Time.new("2020-12-25 00:56. +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /fraction hour is.*00\./) {
|
||||
Time.new("2020-12-25 00. +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits sec.*:017\b/) {
|
||||
Time.new("2020-12-25 00:56:017 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits sec.*:9\b/) {
|
||||
Time.new("2020-12-25 00:56:9 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits min.*:056\b/) {
|
||||
Time.new("2020-12-25 00:056:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits min.*:5\b/) {
|
||||
Time.new("2020-12-25 00:5:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits hour.*\b000\b/) {
|
||||
Time.new("2020-12-25 000:56:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits hour.*\b0\b/) {
|
||||
Time.new("2020-12-25 0:56:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits mday.*\b025\b/) {
|
||||
Time.new("2020-12-025 00:56:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits mon.*\b012\b/) {
|
||||
Time.new("2020-012-25 00:56:17 +0900")
|
||||
}
|
||||
assert_raise_with_message(ArgumentError, /two digits mon.*\b1\b/) {
|
||||
Time.new("2020-1-25 00:56:17 +0900")
|
||||
}
|
||||
end
|
||||
|
||||
def test_time_add()
|
||||
|
36
time.c
36
time.c
@ -2449,12 +2449,18 @@ time_init_args(rb_execution_context_t *ec, VALUE time, VALUE year, VALUE mon, VA
|
||||
}
|
||||
|
||||
static int
|
||||
two_digits(const char *ptr, const char *end, const char **endp)
|
||||
two_digits(const char *ptr, const char *end, const char **endp, const char *name)
|
||||
{
|
||||
ssize_t len = end - ptr;
|
||||
if (len < 2) return -1;
|
||||
if (!ISDIGIT(ptr[0]) || !ISDIGIT(ptr[1])) return -1;
|
||||
if ((len > 2) && ISDIGIT(ptr[2])) return -1;
|
||||
if (len < 2 || (!ISDIGIT(ptr[0]) || !ISDIGIT(ptr[1])) ||
|
||||
((len > 2) && ISDIGIT(ptr[2]))) {
|
||||
VALUE mesg = rb_sprintf("two digits %s is expected", name);
|
||||
if (ptr[-1] == '-' || ptr[-1] == ':') {
|
||||
rb_str_catf(mesg, " after `%c'", ptr[-1]);
|
||||
}
|
||||
rb_str_catf(mesg, ": %.*s", ((len > 10) ? 10 : (int)(end - ptr)) + 1, ptr - 1);
|
||||
rb_exc_raise(rb_exc_new_str(rb_eArgError, mesg));
|
||||
}
|
||||
*endp = ptr + 2;
|
||||
return (ptr[0] - '0') * 10 + (ptr[1] - '0');
|
||||
}
|
||||
@ -2487,22 +2493,34 @@ time_init_parse(rb_execution_context_t *ec, VALUE time, VALUE str, VALUE zone)
|
||||
if (NIL_P(year)) {
|
||||
rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str);
|
||||
}
|
||||
else if (ndigits != 2 && ndigits < 4) {
|
||||
rb_raise(rb_eArgError, "year must be 2 or 4+ digits: %.*s", (int)ndigits, ptr - ndigits);
|
||||
}
|
||||
do {
|
||||
#define peek_n(c, n) ((ptr + n < end) && ((unsigned char)ptr[n] == (c)))
|
||||
#define peek(c) peek_n(c, 0)
|
||||
#define peekc_n(n) ((ptr + n < end) ? (int)(unsigned char)ptr[n] : -1)
|
||||
#define peekc() peekc_n(0)
|
||||
#define expect_two_digits(x) (x = two_digits(ptr + 1, end, &ptr, #x))
|
||||
if (!peek('-')) break;
|
||||
if ((mon = two_digits(ptr + 1, end, &ptr)) < 0) break;
|
||||
expect_two_digits(mon);
|
||||
if (!peek('-')) break;
|
||||
if ((mday = two_digits(ptr + 1, end, &ptr)) < 0) break;
|
||||
expect_two_digits(mday);
|
||||
if (!peek(' ') && !peek('T')) break;
|
||||
const char *const time_part = ptr + 1;
|
||||
if ((hour = two_digits(ptr + 1, end, &ptr)) < 0) break;
|
||||
if (!ISDIGIT(peekc_n(1))) break;
|
||||
#define nofraction(x) \
|
||||
if (peek('.')) { \
|
||||
rb_raise(rb_eArgError, "fraction %s is not supported: %.*s", #x, \
|
||||
(int)(ptr + 1 - time_part), time_part); \
|
||||
}
|
||||
expect_two_digits(hour);
|
||||
nofraction(hour);
|
||||
if (!peek(':')) break;
|
||||
if ((min = two_digits(ptr + 1, end, &ptr)) < 0) break;
|
||||
expect_two_digits(min);
|
||||
nofraction(min);
|
||||
if (!peek(':')) break;
|
||||
if ((sec = two_digits(ptr + 1, end, &ptr)) < 0) break;
|
||||
expect_two_digits(sec);
|
||||
if (peek('.')) {
|
||||
ptr++;
|
||||
for (ndigits = 0; ndigits < 45 && ISDIGIT(peekc_n(ndigits)); ++ndigits);
|
||||
|
Loading…
x
Reference in New Issue
Block a user