[libxml2] Copy xs:duration parser from libexslt
- From: Nick Wellnhofer <nwellnhof src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml2] Copy xs:duration parser from libexslt
- Date: Tue, 23 Jun 2020 14:32:38 +0000 (UTC)
commit c0440868c3a86aa2a488aa226cde34d606f0511d
Author: Nick Wellnhofer <wellnhofer aevum de>
Date: Mon Jun 22 13:08:11 2020 +0200
Copy xs:duration parser from libexslt
The duration parser in libexslt checks for integer overflows.
xmlschemastypes.c | 140 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 98 insertions(+), 42 deletions(-)
---
diff --git a/xmlschemastypes.c b/xmlschemastypes.c
index 164db94b..4249d700 100644
--- a/xmlschemastypes.c
+++ b/xmlschemastypes.c
@@ -1160,9 +1160,12 @@ static const unsigned int daysInMonthLeap[12] =
#define VALID_DATETIME(dt) \
(VALID_DATE(dt) && VALID_TIME(dt))
-#define SECS_PER_MIN (60)
-#define SECS_PER_HOUR (60 * SECS_PER_MIN)
-#define SECS_PER_DAY (24 * SECS_PER_HOUR)
+#define SECS_PER_MIN 60
+#define MINS_PER_HOUR 60
+#define HOURS_PER_DAY 24
+#define SECS_PER_HOUR (MINS_PER_HOUR * SECS_PER_MIN)
+#define SECS_PER_DAY (HOURS_PER_DAY * SECS_PER_HOUR)
+#define MINS_PER_DAY (HOURS_PER_DAY * MINS_PER_HOUR)
static const long dayInYearByMonth[12] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
@@ -1798,10 +1801,8 @@ xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
xmlSchemaValPtr dur;
int isneg = 0;
unsigned int seq = 0;
- 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};
+ long days, secs = 0;
+ double sec_frac = 0.0;
if (duration == NULL)
return -1;
@@ -1826,6 +1827,10 @@ xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
return -1;
while (*cur != 0) {
+ long num = 0;
+ size_t has_digits = 0;
+ int has_frac = 0;
+ const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
/* input string should be empty or invalid date/time item */
if (seq >= sizeof(desig))
@@ -1833,53 +1838,104 @@ xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
/* T designator must be present for time items */
if (*cur == 'T') {
- if (seq <= 3) {
- seq = 3;
- cur++;
- } else
- return 1;
+ if (seq > 3)
+ goto error;
+ cur++;
+ seq = 3;
} else if (seq == 3)
goto error;
- /* parse the number portion of the item */
- PARSE_NUM(num, cur, num_type);
+ /* Parse integral part. */
+ while (*cur >= '0' && *cur <= '9') {
+ long digit = *cur - '0';
- if ((num_type == -1) || (*cur == 0))
- goto error;
-
- /* update duration based on item type */
- while (seq < sizeof(desig)) {
- if (*cur == desig[seq]) {
-
- /* verify numeric type; only seconds can be float */
- if ((num_type != 0) && (seq < (sizeof(desig)-1)))
- goto error;
+ if (num > LONG_MAX / 10)
+ goto error;
+ num *= 10;
+ if (num > LONG_MAX - digit)
+ goto error;
+ num += digit;
- switch (seq) {
- case 0:
- dur->value.dur.mon = (long)num * 12;
- break;
- case 1:
- dur->value.dur.mon += (long)num;
- break;
- default:
- /* convert to seconds using multiplier */
- dur->value.dur.sec += num * multi[seq];
- seq++;
- break;
- }
+ has_digits = 1;
+ cur++;
+ }
- break; /* exit loop */
+ if (*cur == '.') {
+ /* Parse fractional part. */
+ double mult = 1.0;
+ cur++;
+ has_frac = 1;
+ while (*cur >= '0' && *cur <= '9') {
+ mult /= 10.0;
+ sec_frac += (*cur - '0') * mult;
+ has_digits = 1;
+ cur++;
}
- /* no date designators found? */
- if ((++seq == 3) || (seq == 6))
+ }
+
+ while (*cur != desig[seq]) {
+ seq++;
+ /* No T designator or invalid char. */
+ if (seq == 3 || seq == sizeof(desig))
goto error;
}
cur++;
- if (collapse)
- while IS_WSP_BLANK_CH(*cur) cur++;
+
+ if (!has_digits || (has_frac && (seq != 5)))
+ goto error;
+
+ switch (seq) {
+ case 0:
+ /* Year */
+ if (num > LONG_MAX / 12)
+ goto error;
+ dur->value.dur.mon = num * 12;
+ break;
+ case 1:
+ /* Month */
+ if (dur->value.dur.mon > LONG_MAX - num)
+ goto error;
+ dur->value.dur.mon += num;
+ break;
+ case 2:
+ /* Day */
+ dur->value.dur.day = num;
+ break;
+ case 3:
+ /* Hour */
+ days = num / HOURS_PER_DAY;
+ if (dur->value.dur.day > LONG_MAX - days)
+ goto error;
+ dur->value.dur.day += days;
+ secs = (num % HOURS_PER_DAY) * SECS_PER_HOUR;
+ break;
+ case 4:
+ /* Minute */
+ days = num / MINS_PER_DAY;
+ if (dur->value.dur.day > LONG_MAX - days)
+ goto error;
+ dur->value.dur.day += days;
+ secs += (num % MINS_PER_DAY) * SECS_PER_MIN;
+ break;
+ case 5:
+ /* Second */
+ days = num / SECS_PER_DAY;
+ if (dur->value.dur.day > LONG_MAX - days)
+ goto error;
+ dur->value.dur.day += days;
+ secs += num % SECS_PER_DAY;
+ break;
+ }
+
+ seq++;
}
+ days = secs / SECS_PER_DAY;
+ if (dur->value.dur.day > LONG_MAX - days)
+ goto error;
+ dur->value.dur.day += days;
+ dur->value.dur.sec = (secs % SECS_PER_DAY) + sec_frac;
+
if (isneg) {
dur->value.dur.mon = -dur->value.dur.mon;
dur->value.dur.day = -dur->value.dur.day;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]