ext/oj/object.c in oj-3.16.1 vs ext/oj/object.c in oj-3.16.2
- old
+ new
@@ -81,12 +81,13 @@
return n;
}
VALUE
oj_parse_xml_time(const char *str, int len) {
- VALUE args[8];
- const char *end = str + len;
+ VALUE args[7];
+ const char *end = str + len;
+ const char *orig = str;
int n;
// year
if (0 > (n = parse_num(str, end, 4))) {
return Qnil;
@@ -142,20 +143,27 @@
args[6] = LONG2NUM(0);
} else {
char c = *str++;
if ('.' == c) {
- long long nsec = 0;
+ unsigned long long num = 0;
+ unsigned long long den = 1;
+ const unsigned long long last_den_limit = ULLONG_MAX / 10;
for (; str < end; str++) {
c = *str;
if (c < '0' || '9' < c) {
str++;
break;
}
- nsec = nsec * 10 + (c - '0');
+ if (den > last_den_limit) {
+ // bail to Time.parse if there are more fractional digits than a ULLONG rational can hold
+ return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(orig, len));
+ }
+ num = num * 10 + (c - '0');
+ den *= 10;
}
- args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
+ args[5] = rb_funcall(INT2NUM(n), oj_plus_id, 1, rb_rational_new(ULL2NUM(num), ULL2NUM(den)));
} else {
args[5] = rb_ll2inum(n);
}
if (end < str) {
args[6] = LONG2NUM(0);