[libxslt] Clamp seconds field of durations
- From: Nick Wellnhofer <nwellnhof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxslt] Clamp seconds field of durations
- Date: Thu, 18 May 2017 16:25:21 +0000 (UTC)
commit 0b76032b595e162bfb8222bc694e4e876d23e84c
Author: Nick Wellnhofer <wellnhofer aevum de>
Date: Thu May 18 01:07:25 2017 +0200
Clamp seconds field of durations
Clamp seconds field of durations to range 0..SECS_PER_DAY, simplifying
some calculations.
Also add overflow checks in _exsltDateAddDurCalc.
libexslt/date.c | 110 +++++++++++++++++++++++++++++--------------------------
1 files changed, 58 insertions(+), 52 deletions(-)
---
diff --git a/libexslt/date.c b/libexslt/date.c
index 29c611f..64678ad 100644
--- a/libexslt/date.c
+++ b/libexslt/date.c
@@ -101,9 +101,10 @@ struct _exsltDateValDate {
typedef struct _exsltDateValDuration exsltDateValDuration;
typedef exsltDateValDuration *exsltDateValDurationPtr;
struct _exsltDateValDuration {
- long mon; /* mon stores years also */
+ long mon; /* mon stores years also */
long day;
- double sec; /* sec stores min and hour also */
+ double sec; /* sec stores min and hour also
+ 0 <= sec < SECS_PER_DAY */
};
typedef struct _exsltDateVal exsltDateVal;
@@ -1052,7 +1053,7 @@ exsltDateParseDuration (const xmlChar *duration)
double num;
int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
- const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
+ const double multi[] = { 0.0, 0.0, 0.0, 3600.0, 60.0, 1.0, 0.0};
/* input string should be empty or invalid date/time item */
if (seq >= sizeof(desig))
@@ -1089,6 +1090,8 @@ exsltDateParseDuration (const xmlChar *duration)
case 1:
dur->value.dur.mon += (long)num;
break;
+ case 2:
+ dur->value.dur.day = (long)num;
default:
/* convert to seconds using multiplier */
dur->value.dur.sec += num * multi[seq];
@@ -1105,10 +1108,17 @@ exsltDateParseDuration (const xmlChar *duration)
cur++;
}
+ /* Clamp seconds to 0..SECS_PER_DAY range. */
+ dur->value.dur.day += (long)(dur->value.dur.sec / SECS_PER_DAY);
+ dur->value.dur.sec = fmod(dur->value.dur.sec, SECS_PER_DAY);
+
if (isneg) {
dur->value.dur.mon = -dur->value.dur.mon;
dur->value.dur.day = -dur->value.dur.day;
- dur->value.dur.sec = -dur->value.dur.sec;
+ if (dur->value.dur.sec != 0.0) {
+ dur->value.dur.sec = SECS_PER_DAY - dur->value.dur.sec;
+ dur->value.dur.day -= 1;
+ }
}
#ifdef DEBUG_EXSLT_DATE
@@ -1170,11 +1180,11 @@ exsltDateFormatDuration (const exsltDateValDurationPtr dt)
months = (double)(dt->mon % 12);
*cur = '\0';
- if (secs < 0.0) {
- secs = -secs;
- *cur = '-';
- }
if (days < 0) {
+ if (secs != 0.0) {
+ secs = SECS_PER_DAY - secs;
+ days += 1;
+ }
days = -days;
*cur = '-';
}
@@ -1199,12 +1209,6 @@ exsltDateFormatDuration (const exsltDateValDurationPtr dt)
FORMAT_ITEM(months, cur, 1, 'M');
}
- if (secs >= SECS_PER_DAY) {
- double tmp = floor(secs / SECS_PER_DAY);
- days += tmp;
- secs -= (tmp * SECS_PER_DAY);
- }
-
FORMAT_ITEM(days, cur, 1, 'D');
if (secs > 0.0) {
*cur++ = 'T';
@@ -1467,7 +1471,7 @@ _exsltDateAdd (exsltDateValPtr dt, exsltDateValPtr dur)
{
exsltDateValPtr ret;
long carry, temp;
- double sum, quot;
+ double sum;
exsltDateValDatePtr r, d;
exsltDateValDurationPtr u;
@@ -1521,18 +1525,13 @@ _exsltDateAdd (exsltDateValPtr dt, exsltDateValPtr dur)
/* seconds */
sum = d->sec + u->sec;
- quot = floor(sum / 60.0);
- r->sec = sum - quot * 60.0;
- carry = (long)quot;
+ r->sec = fmod(sum, 60.0);
+ carry = (long)(sum / 60.0);
/* minute */
temp = d->min + carry % 60;
carry = carry / 60;
- if (temp < 0) {
- temp += 60;
- carry -= 1;
- }
- else if (temp >= 60) {
+ if (temp >= 60) {
temp -= 60;
carry += 1;
}
@@ -1541,11 +1540,7 @@ _exsltDateAdd (exsltDateValPtr dt, exsltDateValPtr dur)
/* hours */
temp = d->hour + carry % 24;
carry = carry / 24;
- if (temp < 0) {
- temp += 24;
- carry -= 1;
- }
- else if (temp >= 24) {
+ if (temp >= 24) {
temp -= 24;
carry += 1;
}
@@ -1662,21 +1657,13 @@ _exsltDateDifference (exsltDateValPtr x, exsltDateValPtr y, int flag)
ret->value.dur.sec = TIME_TO_NUMBER(y) - TIME_TO_NUMBER(x);
ret->value.dur.sec += (x->value.date.tzo - y->value.date.tzo) *
SECS_PER_MIN;
- carry = (long)(ret->value.dur.sec / SECS_PER_DAY);
- ret->value.dur.sec = fmod(ret->value.dur.sec, SECS_PER_DAY);
+ carry = (long)floor(ret->value.dur.sec / SECS_PER_DAY);
+ ret->value.dur.sec = ret->value.dur.sec - carry * SECS_PER_DAY;
ret->value.dur.day = _exsltDateCastYMToDays(y) -
_exsltDateCastYMToDays(x);
ret->value.dur.day += y->value.date.day - x->value.date.day;
ret->value.dur.day += carry;
-
- if (ret->value.dur.day > 0.0 && ret->value.dur.sec < 0.0) {
- ret->value.dur.day -= 1;
- ret->value.dur.sec = ret->value.dur.sec + SECS_PER_DAY;
- } else if (ret->value.dur.day < 0.0 && ret->value.dur.sec > 0.0) {
- ret->value.dur.day += 1;
- ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY;
- }
}
return ret;
@@ -1697,27 +1684,44 @@ static int
_exsltDateAddDurCalc (exsltDateValDurationPtr ret, exsltDateValDurationPtr x,
exsltDateValDurationPtr y)
{
- double sum;
- long carry;
-
/* months */
+ if ((x->mon > 0 && y->mon > LONG_MAX - x->mon) ||
+ (x->mon < 0 && y->mon < LONG_MIN - x->mon)) {
+ /* Overflow */
+ return 0;
+ }
ret->mon = x->mon + y->mon;
- /* seconds */
- sum = x->sec + y->sec;
- carry = (long)(sum / SECS_PER_DAY);
- ret->sec = fmod(sum, SECS_PER_DAY);
-
/* days */
- ret->day = x->day + y->day + carry;
+ if ((x->day > 0 && y->day > LONG_MAX - x->day) ||
+ (x->day < 0 && y->day < LONG_MIN - x->day)) {
+ /* Overflow */
+ return 0;
+ }
+ ret->day = x->day + y->day;
+
+ /* seconds */
+ ret->sec = x->sec + y->sec;
+ if (ret->sec >= SECS_PER_DAY) {
+ if (ret->day == LONG_MAX) {
+ /* Overflow */
+ return 0;
+ }
+ ret->sec -= SECS_PER_DAY;
+ ret->day += 1;
+ }
/*
* are the results indeterminate? i.e. how do you subtract days from
* months or years?
*/
- if ((((ret->day > 0) || (ret->sec > 0)) && (ret->mon < 0)) ||
- (((ret->day < 0) || (ret->sec < 0)) && (ret->mon > 0))) {
- return 0;
+ if (ret->day >= 0) {
+ if (((ret->day > 0) || (ret->sec > 0)) && (ret->mon < 0))
+ return 0;
+ }
+ else {
+ if (ret->mon > 0)
+ return 0;
}
return 1;
}
@@ -3062,7 +3066,7 @@ static xmlChar *
exsltDateDuration (const xmlChar *number)
{
exsltDateValPtr dur;
- double secs;
+ double secs, days;
xmlChar *ret;
if (number == NULL)
@@ -3077,7 +3081,9 @@ exsltDateDuration (const xmlChar *number)
if (dur == NULL)
return NULL;
- dur->value.dur.sec = secs;
+ days = floor(secs / SECS_PER_DAY);
+ dur->value.dur.day = (long)days;
+ dur->value.dur.sec = secs - days * SECS_PER_DAY;
ret = exsltDateFormatDuration(&(dur->value.dur));
exsltDateFreeDate(dur);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]