From ad393b9be8e094ff9c71146bc65ee7cb7adbddc1 Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 24 Mar 2016 03:43:06 +0000 Subject: date_core.c: fix jisx0301 and iso8601 * ext/date/date_core.c (d_lite_jisx0301, iso8601_timediv), (dt_lite_jisx0301): format by the format string in local buffer to prevent intermediate strings from GC. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54242 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++- ext/date/date_core.c | 117 ++++++++++++++++++++++++++------------------------- ext/date/depend | 1 + 3 files changed, 66 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8e8a356abf..491b182da3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -Thu Mar 24 12:42:36 2016 Nobuyoshi Nakada +Thu Mar 24 12:43:05 2016 Nobuyoshi Nakada + + * ext/date/date_core.c (d_lite_jisx0301, iso8601_timediv), + (dt_lite_jisx0301): format by the format string in local buffer + to prevent intermediate strings from GC. * ext/date/date_core.c (mk_inspect_raw, mk_inspect): inspect by "%+"PRIsVALUE, to prevent intermediate strings from GC. diff --git a/ext/date/date_core.c b/ext/date/date_core.c index 15cac8cc4f..dbe8cb97da 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -4,6 +4,7 @@ #include "ruby.h" #include "ruby/encoding.h" +#include "ruby/util.h" #include #include #if defined(HAVE_SYS_TIME_H) @@ -6880,6 +6881,7 @@ strftimev(const char *fmt, VALUE self, (*func)(self, &tmx); len = date_strftime_alloc(&buf, fmt, &tmx); + RB_GC_GUARD(self); str = rb_usascii_str_new(buf, len); if (buf != buffer) xfree(buf); return str; @@ -6953,30 +6955,40 @@ d_lite_httpdate(VALUE self) return strftimev("%a, %d %b %Y %T GMT", dup, set_tmx); } -static VALUE -jisx0301_date(VALUE jd, VALUE y) -{ - VALUE a[2]; +enum { + DECIMAL_SIZE_OF_LONG = DECIMAL_SIZE_OF_BITS(CHAR_BIT*sizeof(long)), + JISX0301_DATE_SIZE = DECIMAL_SIZE_OF_LONG+8 +}; - if (f_lt_p(jd, INT2FIX(2405160))) - return rb_usascii_str_new2("%Y-%m-%d"); - if (f_lt_p(jd, INT2FIX(2419614))) { - a[0] = rb_usascii_str_new2("M%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1867)); - } - else if (f_lt_p(jd, INT2FIX(2424875))) { - a[0] = rb_usascii_str_new2("T%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1911)); - } - else if (f_lt_p(jd, INT2FIX(2447535))) { - a[0] = rb_usascii_str_new2("S%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1925)); - } - else { - a[0] = rb_usascii_str_new2("H%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1988)); +static const char * +jisx0301_date_format(char *fmt, size_t size, VALUE jd, VALUE y) +{ + if (FIXNUM_P(jd)) { + long d = FIX2INT(jd); + long s; + char c; + if (d < 2405160) + return "%Y-%m-%d"; + if (d < 2419614) { + c = 'M'; + s = 1867; + } + else if (d < 2424875) { + c = 'T'; + s = 1911; + } + else if (d < 2447535) { + c = 'S'; + s = 1925; + } + else { + c = 'H'; + s = 1988; + } + snprintf(fmt, size, "%c%02ld" ".%%m.%%d", c, FIX2INT(y) - s); + return fmt; } - return rb_f_sprintf(2, a); + return "%Y-%m-%d"; } /* @@ -6990,12 +7002,14 @@ jisx0301_date(VALUE jd, VALUE y) static VALUE d_lite_jisx0301(VALUE self) { - VALUE s; + char fmtbuf[JISX0301_DATE_SIZE]; + const char *fmt; get_d1(self); - s = jisx0301_date(m_real_local_jd(dat), - m_real_year(dat)); - return strftimev(RSTRING_PTR(s), self, set_tmx); + fmt = jisx0301_date_format(fmtbuf, sizeof(fmtbuf), + m_real_local_jd(dat), + m_real_year(dat)); + return strftimev(fmt, self, set_tmx); } #ifndef NDEBUG @@ -8301,26 +8315,19 @@ dt_lite_strftime(int argc, VALUE *argv, VALUE self) } static VALUE -iso8601_timediv(VALUE self, VALUE n) +iso8601_timediv(VALUE self, long n) { - VALUE fmt; + static const char timefmt[] = "T%H:%M:%S"; + static const char zone[] = "%:z"; + char fmt[sizeof(timefmt) + sizeof(zone) + rb_strlen_lit(".%N") + + DECIMAL_SIZE_OF_LONG]; + char *p = fmt; - n = to_integer(n); - fmt = rb_usascii_str_new2("T%H:%M:%S"); - if (f_gt_p(n, INT2FIX(0))) { - VALUE argv[3]; - - get_d1(self); - - argv[0] = rb_usascii_str_new2(".%0*d"); - argv[1] = n; - argv[2] = f_round(f_quo(m_sf_in_sec(dat), - f_quo(INT2FIX(1), - f_expt(INT2FIX(10), n)))); - rb_str_append(fmt, rb_f_sprintf(3, argv)); - } - rb_str_append(fmt, rb_usascii_str_new2("%:z")); - return strftimev(RSTRING_PTR(fmt), self, set_tmx); + memcpy(p, timefmt, sizeof(timefmt)-1); + p += sizeof(timefmt)-1; + if (n > 0) p += snprintf(p, fmt+sizeof(fmt)-p, ".%%%ldN", n); + memcpy(p, zone, sizeof(zone)); + return strftimev(fmt, self, set_tmx); } /* @@ -8337,12 +8344,11 @@ iso8601_timediv(VALUE self, VALUE n) static VALUE dt_lite_iso8601(int argc, VALUE *argv, VALUE self) { - VALUE n; - - rb_scan_args(argc, argv, "01", &n); + long n = 0; - if (argc < 1) - n = INT2FIX(0); + rb_check_arity(argc, 0, 1); + if (argc >= 1) + n = NUM2LONG(argv[0]); return f_add(strftimev("%Y-%m-%d", self, set_tmx), iso8601_timediv(self, n)); @@ -8377,18 +8383,15 @@ dt_lite_rfc3339(int argc, VALUE *argv, VALUE self) static VALUE dt_lite_jisx0301(int argc, VALUE *argv, VALUE self) { - VALUE n, s; - - rb_scan_args(argc, argv, "01", &n); + long n = 0; - if (argc < 1) - n = INT2FIX(0); + rb_check_arity(argc, 0, 1); + if (argc >= 1) + n = NUM2LONG(argv[0]); { get_d1(self); - s = jisx0301_date(m_real_local_jd(dat), - m_real_year(dat)); - return rb_str_append(strftimev(RSTRING_PTR(s), self, set_tmx), + return rb_str_append(d_lite_jisx0301(self), iso8601_timediv(self, n)); } } diff --git a/ext/date/depend b/ext/date/depend index a5444e3ed9..8e8af3882b 100644 --- a/ext/date/depend +++ b/ext/date/depend @@ -9,6 +9,7 @@ date_core.o: $(hdrdir)/ruby/oniguruma.h date_core.o: $(hdrdir)/ruby/ruby.h date_core.o: $(hdrdir)/ruby/st.h date_core.o: $(hdrdir)/ruby/subst.h +date_core.o: $(hdrdir)/ruby/util.h date_core.o: $(top_srcdir)/include/ruby.h date_core.o: date_core.c date_core.o: date_tmx.h -- cgit v1.2.3