date_core.c: check conversion

* ext/date/date_core.c (offset_to_sec, d_lite_plus): check
  conversion results, to get rid of infinite recursion.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62685 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-03-07 08:07:24 +00:00
parent 7a363dd91f
commit 7ab3f98604
2 changed files with 36 additions and 19 deletions

View File

@ -2333,6 +2333,9 @@ VALUE date_zone_to_diff(VALUE);
static int static int
offset_to_sec(VALUE vof, int *rof) offset_to_sec(VALUE vof, int *rof)
{ {
int try_rational = 1;
again:
switch (TYPE(vof)) { switch (TYPE(vof)) {
case T_FIXNUM: case T_FIXNUM:
{ {
@ -2359,10 +2362,11 @@ offset_to_sec(VALUE vof, int *rof)
default: default:
expect_numeric(vof); expect_numeric(vof);
vof = f_to_r(vof); vof = f_to_r(vof);
#ifdef CANONICALIZATION_FOR_MATHN if (!k_rational_p(vof)) {
if (!k_rational_p(vof)) if (!try_rational) Check_Type(vof, T_RATIONAL);
return offset_to_sec(vof, rof); try_rational = 0;
#endif goto again;
}
/* fall through */ /* fall through */
case T_RATIONAL: case T_RATIONAL:
{ {
@ -2371,17 +2375,10 @@ offset_to_sec(VALUE vof, int *rof)
vs = day_to_sec(vof); vs = day_to_sec(vof);
#ifdef CANONICALIZATION_FOR_MATHN
if (!k_rational_p(vs)) { if (!k_rational_p(vs)) {
if (!FIXNUM_P(vs)) vn = vs;
return 0; goto rounded;
n = FIX2LONG(vs);
if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS)
return 0;
*rof = (int)n;
return 1;
} }
#endif
vn = rb_rational_num(vs); vn = rb_rational_num(vs);
vd = rb_rational_den(vs); vd = rb_rational_den(vs);
@ -2391,6 +2388,7 @@ offset_to_sec(VALUE vof, int *rof)
vn = f_round(vs); vn = f_round(vs);
if (!f_eqeq_p(vn, vs)) if (!f_eqeq_p(vn, vs))
rb_warning("fraction of offset is ignored"); rb_warning("fraction of offset is ignored");
rounded:
if (!FIXNUM_P(vn)) if (!FIXNUM_P(vn))
return 0; return 0;
n = FIX2LONG(vn); n = FIX2LONG(vn);
@ -5513,8 +5511,10 @@ d_lite_new_offset(int argc, VALUE *argv, VALUE self)
static VALUE static VALUE
d_lite_plus(VALUE self, VALUE other) d_lite_plus(VALUE self, VALUE other)
{ {
int try_rational = 1;
get_d1(self); get_d1(self);
again:
switch (TYPE(other)) { switch (TYPE(other)) {
case T_FIXNUM: case T_FIXNUM:
{ {
@ -5724,18 +5724,21 @@ d_lite_plus(VALUE self, VALUE other)
default: default:
expect_numeric(other); expect_numeric(other);
other = f_to_r(other); other = f_to_r(other);
#ifdef CANONICALIZATION_FOR_MATHN if (!k_rational_p(other)) {
if (!k_rational_p(other)) if (!try_rational) Check_Type(other, T_RATIONAL);
return d_lite_plus(self, other); try_rational = 0;
#endif goto again;
}
/* fall through */ /* fall through */
case T_RATIONAL: case T_RATIONAL:
{ {
VALUE nth, sf, t; VALUE nth, sf, t;
int jd, df, s; int jd, df, s;
if (wholenum_p(other)) if (wholenum_p(other)) {
return d_lite_plus(self, rb_rational_num(other)); other = rb_rational_num(other);
goto again;
}
if (f_positive_p(other)) if (f_positive_p(other))
s = +1; s = +1;

View File

@ -3,11 +3,18 @@ require 'test/unit'
require 'date' require 'date'
class TestDateArith < Test::Unit::TestCase class TestDateArith < Test::Unit::TestCase
class Rat < Numeric
def to_r; self; end
end
def test_new_offset def test_new_offset
d = DateTime.new(2002, 3, 14) d = DateTime.new(2002, 3, 14)
assert_equal(Rational(9, 24), d.new_offset(Rational(9, 24)).offset) assert_equal(Rational(9, 24), d.new_offset(Rational(9, 24)).offset)
assert_equal(Rational(9, 24), d.new_offset('+0900').offset) assert_equal(Rational(9, 24), d.new_offset('+0900').offset)
n = Rat.new
assert_raise(TypeError) do
Timeout.timeout(1) {d.new_offset(n)}
end
end end
def test__plus def test__plus
@ -37,6 +44,13 @@ class TestDateArith < Test::Unit::TestCase
assert_raise(e) do assert_raise(e) do
DateTime.new(2000,2,29) + Time.mktime(2000,2,29) DateTime.new(2000,2,29) + Time.mktime(2000,2,29)
end end
n = Rat.new
assert_raise(e) do
Timeout.timeout(1) {Date.new(2000,2,29) + n}
end
assert_raise(e) do
Timeout.timeout(1) {DateTime.new(2000,2,29) + n}
end
end end
def test__minus def test__minus