time-util: make parse_sec() not accept "12.34.56"
This also changes the rational number treatment. So, the limitations introduced by8079c90333andf6a178e91dare relaxed. Fixes #10619.
This commit is contained in:
committed by
Lennart Poettering
parent
a0ca258adf
commit
ed2e7967be
+111
-102
@@ -868,7 +868,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
return tmp.return_value;
|
||||
}
|
||||
|
||||
static char* extract_multiplier(char *p, usec_t *multiplier) {
|
||||
static const char* extract_multiplier(const char *p, usec_t *multiplier) {
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
usec_t usec;
|
||||
@@ -942,8 +942,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||
|
||||
for (;;) {
|
||||
usec_t multiplier = default_unit, k;
|
||||
long long l, z = 0;
|
||||
unsigned n = 0;
|
||||
long long l;
|
||||
char *e;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
@@ -966,46 +965,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||
return -ERANGE;
|
||||
|
||||
if (*e == '.') {
|
||||
char *b = e + 1;
|
||||
|
||||
/* Don't allow "0.-0", "3.+1" or "3. 1" */
|
||||
if (IN_SET(*b, '-', '+') || isspace(*b))
|
||||
return -EINVAL;
|
||||
|
||||
errno = 0;
|
||||
z = strtoll(b, &e, 10);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (z < 0)
|
||||
return -ERANGE;
|
||||
if (e == b)
|
||||
return -EINVAL;
|
||||
|
||||
n = e - b;
|
||||
|
||||
p = e + 1;
|
||||
p += strspn(p, DIGITS);
|
||||
} else if (e == p)
|
||||
return -EINVAL;
|
||||
else
|
||||
p = e;
|
||||
|
||||
e += strspn(e, WHITESPACE);
|
||||
p = extract_multiplier(e, &multiplier);
|
||||
s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||
if (s == p && *s != '\0')
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||
return -EINVAL;
|
||||
|
||||
something = true;
|
||||
p = s;
|
||||
|
||||
|
||||
k = ((usec_t) -1) / multiplier;
|
||||
if ((usec_t) l + 1 >= k || (usec_t) z >= k)
|
||||
if ((usec_t) l >= USEC_INFINITY / multiplier)
|
||||
return -ERANGE;
|
||||
|
||||
k = (usec_t) z * multiplier;
|
||||
|
||||
for (; n > 0; n--)
|
||||
k /= 10;
|
||||
|
||||
k += (usec_t) l * multiplier;
|
||||
if (k >= ((usec_t) -1) - r)
|
||||
k = (usec_t) l * multiplier;
|
||||
if (k >= USEC_INFINITY - r)
|
||||
return -ERANGE;
|
||||
|
||||
r += k;
|
||||
|
||||
something = true;
|
||||
|
||||
if (*e == '.') {
|
||||
usec_t m = multiplier / 10;
|
||||
const char *b;
|
||||
|
||||
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
|
||||
k = (usec_t) (*b - '0') * m;
|
||||
if (k >= USEC_INFINITY - r)
|
||||
return -ERANGE;
|
||||
|
||||
r += k;
|
||||
}
|
||||
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||
if (b == e + 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*usec = r;
|
||||
@@ -1032,44 +1032,60 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int parse_nsec(const char *t, nsec_t *nsec) {
|
||||
static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
nsec_t nsec;
|
||||
} table[] = {
|
||||
{ "seconds", NSEC_PER_SEC },
|
||||
{ "second", NSEC_PER_SEC },
|
||||
{ "sec", NSEC_PER_SEC },
|
||||
{ "s", NSEC_PER_SEC },
|
||||
{ "seconds", NSEC_PER_SEC },
|
||||
{ "second", NSEC_PER_SEC },
|
||||
{ "sec", NSEC_PER_SEC },
|
||||
{ "s", NSEC_PER_SEC },
|
||||
{ "minutes", NSEC_PER_MINUTE },
|
||||
{ "minute", NSEC_PER_MINUTE },
|
||||
{ "min", NSEC_PER_MINUTE },
|
||||
{ "months", NSEC_PER_MONTH },
|
||||
{ "month", NSEC_PER_MONTH },
|
||||
{ "msec", NSEC_PER_MSEC },
|
||||
{ "ms", NSEC_PER_MSEC },
|
||||
{ "m", NSEC_PER_MINUTE },
|
||||
{ "hours", NSEC_PER_HOUR },
|
||||
{ "hour", NSEC_PER_HOUR },
|
||||
{ "hr", NSEC_PER_HOUR },
|
||||
{ "h", NSEC_PER_HOUR },
|
||||
{ "days", NSEC_PER_DAY },
|
||||
{ "day", NSEC_PER_DAY },
|
||||
{ "d", NSEC_PER_DAY },
|
||||
{ "weeks", NSEC_PER_WEEK },
|
||||
{ "week", NSEC_PER_WEEK },
|
||||
{ "w", NSEC_PER_WEEK },
|
||||
{ "years", NSEC_PER_YEAR },
|
||||
{ "year", NSEC_PER_YEAR },
|
||||
{ "y", NSEC_PER_YEAR },
|
||||
{ "usec", NSEC_PER_USEC },
|
||||
{ "us", NSEC_PER_USEC },
|
||||
{ "µs", NSEC_PER_USEC },
|
||||
{ "nsec", 1ULL },
|
||||
{ "ns", 1ULL },
|
||||
{ "", 1ULL }, /* default is nsec */
|
||||
{ "minute", NSEC_PER_MINUTE },
|
||||
{ "min", NSEC_PER_MINUTE },
|
||||
{ "months", NSEC_PER_MONTH },
|
||||
{ "month", NSEC_PER_MONTH },
|
||||
{ "M", NSEC_PER_MONTH },
|
||||
{ "msec", NSEC_PER_MSEC },
|
||||
{ "ms", NSEC_PER_MSEC },
|
||||
{ "m", NSEC_PER_MINUTE },
|
||||
{ "hours", NSEC_PER_HOUR },
|
||||
{ "hour", NSEC_PER_HOUR },
|
||||
{ "hr", NSEC_PER_HOUR },
|
||||
{ "h", NSEC_PER_HOUR },
|
||||
{ "days", NSEC_PER_DAY },
|
||||
{ "day", NSEC_PER_DAY },
|
||||
{ "d", NSEC_PER_DAY },
|
||||
{ "weeks", NSEC_PER_WEEK },
|
||||
{ "week", NSEC_PER_WEEK },
|
||||
{ "w", NSEC_PER_WEEK },
|
||||
{ "years", NSEC_PER_YEAR },
|
||||
{ "year", NSEC_PER_YEAR },
|
||||
{ "y", NSEC_PER_YEAR },
|
||||
{ "usec", NSEC_PER_USEC },
|
||||
{ "us", NSEC_PER_USEC },
|
||||
{ "µs", NSEC_PER_USEC },
|
||||
{ "nsec", 1ULL },
|
||||
{ "ns", 1ULL },
|
||||
{ "", 1ULL }, /* default is nsec */
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++) {
|
||||
char *e;
|
||||
|
||||
e = startswith(p, table[i].suffix);
|
||||
if (e) {
|
||||
*multiplier = table[i].nsec;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int parse_nsec(const char *t, nsec_t *nsec) {
|
||||
const char *p, *s;
|
||||
nsec_t r = 0;
|
||||
bool something = false;
|
||||
@@ -1091,8 +1107,8 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
long long l, z = 0;
|
||||
size_t n = 0, i;
|
||||
nsec_t multiplier = 1, k;
|
||||
long long l;
|
||||
char *e;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
@@ -1104,7 +1120,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p == '-')
|
||||
if (*p == '-') /* Don't allow "-0" */
|
||||
return -ERANGE;
|
||||
|
||||
errno = 0;
|
||||
@@ -1115,54 +1131,47 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||
return -ERANGE;
|
||||
|
||||
if (*e == '.') {
|
||||
char *b = e + 1;
|
||||
|
||||
if (IN_SET(*b, '-', '+') || isspace(*b))
|
||||
return -EINVAL;
|
||||
|
||||
errno = 0;
|
||||
z = strtoll(b, &e, 10);
|
||||
if (errno > 0)
|
||||
return -errno;
|
||||
if (z < 0)
|
||||
return -ERANGE;
|
||||
if (e == b)
|
||||
return -EINVAL;
|
||||
|
||||
n = e - b;
|
||||
|
||||
p = e + 1;
|
||||
p += strspn(p, DIGITS);
|
||||
} else if (e == p)
|
||||
return -EINVAL;
|
||||
else
|
||||
p = e;
|
||||
|
||||
e += strspn(e, WHITESPACE);
|
||||
s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||
if (s == p && *s != '\0')
|
||||
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++)
|
||||
if (startswith(e, table[i].suffix)) {
|
||||
nsec_t k;
|
||||
p = s;
|
||||
|
||||
k = ((nsec_t) -1) / table[i].nsec;
|
||||
if ((nsec_t) l + 1 >= k || (nsec_t) z >= k)
|
||||
return -ERANGE;
|
||||
if ((nsec_t) l >= NSEC_INFINITY / multiplier)
|
||||
return -ERANGE;
|
||||
|
||||
k = (nsec_t) z * table[i].nsec;
|
||||
k = (nsec_t) l * multiplier;
|
||||
if (k >= NSEC_INFINITY - r)
|
||||
return -ERANGE;
|
||||
|
||||
for (; n > 0; n--)
|
||||
k /= 10;
|
||||
r += k;
|
||||
|
||||
k += (nsec_t) l * table[i].nsec;
|
||||
if (k >= ((nsec_t) -1) - r)
|
||||
something = true;
|
||||
|
||||
if (*e == '.') {
|
||||
nsec_t m = multiplier / 10;
|
||||
const char *b;
|
||||
|
||||
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
|
||||
k = (nsec_t) (*b - '0') * m;
|
||||
if (k >= NSEC_INFINITY - r)
|
||||
return -ERANGE;
|
||||
|
||||
r += k;
|
||||
p = e + strlen(table[i].suffix);
|
||||
|
||||
something = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ELEMENTSOF(table))
|
||||
return -EINVAL;
|
||||
|
||||
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||
if (b == e + 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*nsec = r;
|
||||
|
||||
@@ -39,6 +39,14 @@ static void test_parse_sec(void) {
|
||||
assert_se(u == USEC_INFINITY);
|
||||
assert_se(parse_sec("+3.1s", &u) >= 0);
|
||||
assert_se(u == 3100 * USEC_PER_MSEC);
|
||||
assert_se(parse_sec("3.1s.2", &u) >= 0);
|
||||
assert_se(u == 3300 * USEC_PER_MSEC);
|
||||
assert_se(parse_sec("3.1 .2", &u) >= 0);
|
||||
assert_se(u == 3300 * USEC_PER_MSEC);
|
||||
assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0);
|
||||
assert_se(u == 3300 * USEC_PER_MSEC);
|
||||
assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0);
|
||||
assert_se(u == 4300 * USEC_PER_MSEC);
|
||||
|
||||
assert_se(parse_sec(" xyz ", &u) < 0);
|
||||
assert_se(parse_sec("", &u) < 0);
|
||||
@@ -56,6 +64,10 @@ static void test_parse_sec(void) {
|
||||
assert_se(parse_sec("3.+1s", &u) < 0);
|
||||
assert_se(parse_sec("3. 1s", &u) < 0);
|
||||
assert_se(parse_sec("3.s", &u) < 0);
|
||||
assert_se(parse_sec("12.34.56", &u) < 0);
|
||||
assert_se(parse_sec("12..34", &u) < 0);
|
||||
assert_se(parse_sec("..1234", &u) < 0);
|
||||
assert_se(parse_sec("1234..", &u) < 0);
|
||||
}
|
||||
|
||||
static void test_parse_sec_fix_0(void) {
|
||||
@@ -97,7 +109,7 @@ static void test_parse_time(void) {
|
||||
assert_se(u == 5 * USEC_PER_SEC);
|
||||
|
||||
assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE);
|
||||
assert_se(parse_time("1.1111111111111y", &u, 1) == -ERANGE);
|
||||
assert_se(parse_time("1.1111111111111y", &u, 1) >= 0);
|
||||
}
|
||||
|
||||
static void test_parse_nsec(void) {
|
||||
@@ -129,6 +141,14 @@ static void test_parse_nsec(void) {
|
||||
assert_se(u == NSEC_INFINITY);
|
||||
assert_se(parse_nsec("+3.1s", &u) >= 0);
|
||||
assert_se(u == 3100 * NSEC_PER_MSEC);
|
||||
assert_se(parse_nsec("3.1s.2", &u) >= 0);
|
||||
assert_se(u == 3100 * NSEC_PER_MSEC);
|
||||
assert_se(parse_nsec("3.1 .2s", &u) >= 0);
|
||||
assert_se(u == 200 * NSEC_PER_MSEC + 3);
|
||||
assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0);
|
||||
assert_se(u == 3300 * NSEC_PER_MSEC);
|
||||
assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0);
|
||||
assert_se(u == 4300 * NSEC_PER_MSEC);
|
||||
|
||||
assert_se(parse_nsec(" xyz ", &u) < 0);
|
||||
assert_se(parse_nsec("", &u) < 0);
|
||||
@@ -148,8 +168,12 @@ static void test_parse_nsec(void) {
|
||||
assert_se(parse_nsec("3.+1s", &u) < 0);
|
||||
assert_se(parse_nsec("3. 1s", &u) < 0);
|
||||
assert_se(parse_nsec("3.s", &u) < 0);
|
||||
assert_se(parse_nsec("12.34.56", &u) < 0);
|
||||
assert_se(parse_nsec("12..34", &u) < 0);
|
||||
assert_se(parse_nsec("..1234", &u) < 0);
|
||||
assert_se(parse_nsec("1234..", &u) < 0);
|
||||
assert_se(parse_nsec("1111111111111y", &u) == -ERANGE);
|
||||
assert_se(parse_nsec("1.111111111111y", &u) == -ERANGE);
|
||||
assert_se(parse_nsec("1.111111111111y", &u) >= 0);
|
||||
}
|
||||
|
||||
static void test_format_timespan_one(usec_t x, usec_t accuracy) {
|
||||
|
||||
Reference in New Issue
Block a user