[ruby/date] Check time zone offset elements
Too big parts of fractional hour time zone offset can cause assertion failures. https://github.com/ruby/date/commit/06bcfb2729
This commit is contained in:
parent
cd77e71bba
commit
d12fce7af3
@ -473,27 +473,53 @@ date_zone_to_diff(VALUE str)
|
|||||||
s++;
|
s++;
|
||||||
l--;
|
l--;
|
||||||
|
|
||||||
|
#define out_of_range(v, min, max) ((v) < (min) || (max) < (v))
|
||||||
hour = STRTOUL(s, &p, 10);
|
hour = STRTOUL(s, &p, 10);
|
||||||
if (*p == ':') {
|
if (*p == ':') {
|
||||||
|
if (out_of_range(sec, 0, 59)) return Qnil;
|
||||||
s = ++p;
|
s = ++p;
|
||||||
min = STRTOUL(s, &p, 10);
|
min = STRTOUL(s, &p, 10);
|
||||||
|
if (out_of_range(min, 0, 59)) return Qnil;
|
||||||
if (*p == ':') {
|
if (*p == ':') {
|
||||||
s = ++p;
|
s = ++p;
|
||||||
sec = STRTOUL(s, &p, 10);
|
sec = STRTOUL(s, &p, 10);
|
||||||
|
if (out_of_range(hour, 0, 23)) return Qnil;
|
||||||
}
|
}
|
||||||
goto num;
|
|
||||||
}
|
}
|
||||||
if (*p == ',' || *p == '.') {
|
else if (*p == ',' || *p == '.') {
|
||||||
char *e = 0;
|
/* fractional hour */
|
||||||
p++;
|
size_t n;
|
||||||
min = STRTOUL(p, &e, 10) * 3600;
|
int ov;
|
||||||
|
/* no over precision for offset; 10**-7 hour = 0.36
|
||||||
|
* milliseconds should be enough. */
|
||||||
|
const size_t max_digits = 7; /* 36 * 10**7 < 32-bit FIXNUM_MAX */
|
||||||
|
|
||||||
|
if (out_of_range(hour, 0, 23)) return Qnil;
|
||||||
|
|
||||||
|
n = (s + l) - ++p;
|
||||||
|
if (n > max_digits) n = max_digits;
|
||||||
|
sec = ruby_scan_digits(p, n, 10, &n, &ov);
|
||||||
|
if ((p += n) < s + l && *p >= ('5' + !(sec & 1)) && *p <= '9') {
|
||||||
|
/* round half to even */
|
||||||
|
sec++;
|
||||||
|
}
|
||||||
|
sec *= 36;
|
||||||
if (sign) {
|
if (sign) {
|
||||||
hour = -hour;
|
hour = -hour;
|
||||||
min = -min;
|
sec = -sec;
|
||||||
|
}
|
||||||
|
if (n <= 2) {
|
||||||
|
/* HH.nn or HH.n */
|
||||||
|
if (n == 1) sec *= 10;
|
||||||
|
offset = INT2FIX(sec + hour * 3600);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE denom = rb_int_positive_pow(10, (int)(n - 2));
|
||||||
|
offset = f_add(rb_rational_new(INT2FIX(sec), denom), INT2FIX(hour * 3600));
|
||||||
|
if (rb_rational_den(offset) == INT2FIX(1)) {
|
||||||
|
offset = rb_rational_num(offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
offset = rb_rational_new(INT2FIX(min),
|
|
||||||
rb_int_positive_pow(10, (int)(e - p)));
|
|
||||||
offset = f_add(INT2FIX(hour * 3600), offset);
|
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
else if (l > 2) {
|
else if (l > 2) {
|
||||||
@ -506,12 +532,11 @@ date_zone_to_diff(VALUE str)
|
|||||||
min = ruby_scan_digits(&s[2 - l % 2], 2, 10, &n, &ov);
|
min = ruby_scan_digits(&s[2 - l % 2], 2, 10, &n, &ov);
|
||||||
if (l >= 5)
|
if (l >= 5)
|
||||||
sec = ruby_scan_digits(&s[4 - l % 2], 2, 10, &n, &ov);
|
sec = ruby_scan_digits(&s[4 - l % 2], 2, 10, &n, &ov);
|
||||||
goto num;
|
|
||||||
}
|
}
|
||||||
num:
|
|
||||||
sec += min * 60 + hour * 3600;
|
sec += min * 60 + hour * 3600;
|
||||||
if (sign) sec = -sec;
|
if (sign) sec = -sec;
|
||||||
offset = INT2FIX(sec);
|
offset = INT2FIX(sec);
|
||||||
|
#undef out_of_range
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,10 @@ class TestDateStrptime < Test::Unit::TestCase
|
|||||||
|
|
||||||
[['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]],
|
[['fri1feb034pm+5', '%a%d%b%y%H%p%Z'], [2003,2,1,16,nil,nil,'+5',5*3600,5]],
|
||||||
[['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__],
|
[['E. Australia Standard Time', '%Z'], [nil,nil,nil,nil,nil,nil,'E. Australia Standard Time',10*3600,nil], __LINE__],
|
||||||
|
|
||||||
|
# out of range
|
||||||
|
[['+0.9999999999999999999999', '%Z'], [nil,nil,nil,nil,nil,nil,'+0.9999999999999999999999',+1*3600,nil], __LINE__],
|
||||||
|
[['+9999999999999999999999.0', '%Z'], [nil,nil,nil,nil,nil,nil,'+9999999999999999999999.0',nil,nil], __LINE__],
|
||||||
].each do |x, y|
|
].each do |x, y|
|
||||||
h = Date._strptime(*x)
|
h = Date._strptime(*x)
|
||||||
a = h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday)
|
a = h.values_at(:year,:mon,:mday,:hour,:min,:sec,:zone,:offset,:wday)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user