sync fmt_scaled.c with OpenBSD
revision 1.13 date: 2017/03/11 23:37:23; author: djm; state: Exp; lines: +14 -1; commitid: jnFKyHkB3CEiEZ2R; fix signed integer overflow in scan_scaled. Found by Nicolas Iooss using AFL against ssh_config. ok deraadt@ millert@ ---------------------------- revision 1.12 date: 2013/11/29 19:00:51; author: deraadt; state: Exp; lines: +6 -5; fairly simple unsigned char casts for ctype ok krw ---------------------------- revision 1.11 date: 2012/11/12 14:07:20; author: halex; state: Exp; lines: +4 -2; make scan_scaled set errno to EINVAL rather than ERANGE if it encounters an invalid multiplier, like the man page says it should "looks sensible" deraadt@, ok ian@ ---------------------------- revision 1.10 date: 2009/06/20 15:00:04; author: martynas; state: Exp; lines: +4 -4; use llabs instead of the home-grown version; and some comment changes ok ian@, millert@ ----------------------------
This commit is contained in:
parent
894221a63f
commit
d94c1dfef2
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $ */
|
/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
|
* Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
|
||||||
|
@ -69,7 +69,7 @@ static long long scale_factors[] = {
|
||||||
|
|
||||||
#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */
|
#define MAX_DIGITS (SCALE_LENGTH * 3) /* XXX strlen(sprintf("%lld", -1)? */
|
||||||
|
|
||||||
/** Convert the given input string "scaled" into numeric in "result".
|
/* Convert the given input string "scaled" into numeric in "result".
|
||||||
* Return 0 on success, -1 and errno set on error.
|
* Return 0 on success, -1 and errno set on error.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -81,7 +81,7 @@ scan_scaled(char *scaled, long long *result)
|
||||||
long long scale_fact = 1, whole = 0, fpart = 0;
|
long long scale_fact = 1, whole = 0, fpart = 0;
|
||||||
|
|
||||||
/* Skip leading whitespace */
|
/* Skip leading whitespace */
|
||||||
while (isascii(*p) && isspace(*p))
|
while (isascii((unsigned char)*p) && isspace((unsigned char)*p))
|
||||||
++p;
|
++p;
|
||||||
|
|
||||||
/* Then at most one leading + or - */
|
/* Then at most one leading + or - */
|
||||||
|
@ -108,7 +108,8 @@ scan_scaled(char *scaled, long long *result)
|
||||||
* (but note that E for Exa might look like e to some!).
|
* (but note that E for Exa might look like e to some!).
|
||||||
* Advance 'p' to end, to get scale factor.
|
* Advance 'p' to end, to get scale factor.
|
||||||
*/
|
*/
|
||||||
for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) {
|
for (; isascii((unsigned char)*p) &&
|
||||||
|
(isdigit((unsigned char)*p) || *p=='.'); ++p) {
|
||||||
if (*p == '.') {
|
if (*p == '.') {
|
||||||
if (fract_digits > 0) { /* oops, more than one '.' */
|
if (fract_digits > 0) { /* oops, more than one '.' */
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
@ -124,6 +125,10 @@ scan_scaled(char *scaled, long long *result)
|
||||||
/* ignore extra fractional digits */
|
/* ignore extra fractional digits */
|
||||||
continue;
|
continue;
|
||||||
fract_digits++; /* for later scaling */
|
fract_digits++; /* for later scaling */
|
||||||
|
if (fpart >= LLONG_MAX / 10) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
fpart *= 10;
|
fpart *= 10;
|
||||||
fpart += i;
|
fpart += i;
|
||||||
} else { /* normal digit */
|
} else { /* normal digit */
|
||||||
|
@ -131,6 +136,10 @@ scan_scaled(char *scaled, long long *result)
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (whole >= LLONG_MAX / 10) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
whole *= 10;
|
whole *= 10;
|
||||||
whole += i;
|
whole += i;
|
||||||
}
|
}
|
||||||
|
@ -150,17 +159,22 @@ scan_scaled(char *scaled, long long *result)
|
||||||
/* Validate scale factor, and scale whole and fraction by it. */
|
/* Validate scale factor, and scale whole and fraction by it. */
|
||||||
for (i = 0; i < SCALE_LENGTH; i++) {
|
for (i = 0; i < SCALE_LENGTH; i++) {
|
||||||
|
|
||||||
/** Are we there yet? */
|
/* Are we there yet? */
|
||||||
if (*p == scale_chars[i] ||
|
if (*p == scale_chars[i] ||
|
||||||
*p == tolower(scale_chars[i])) {
|
*p == tolower((unsigned char)scale_chars[i])) {
|
||||||
|
|
||||||
/* If it ends with alphanumerics after the scale char, bad. */
|
/* If it ends with alphanumerics after the scale char, bad. */
|
||||||
if (isalnum(*(p+1))) {
|
if (isalnum((unsigned char)*(p+1))) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
scale_fact = scale_factors[i];
|
scale_fact = scale_factors[i];
|
||||||
|
|
||||||
|
if (whole >= LLONG_MAX / scale_fact) {
|
||||||
|
errno = ERANGE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* scale whole part */
|
/* scale whole part */
|
||||||
whole *= scale_fact;
|
whole *= scale_fact;
|
||||||
|
|
||||||
|
@ -181,7 +195,9 @@ scan_scaled(char *scaled, long long *result)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errno = ERANGE;
|
|
||||||
|
/* Invalid unit or character */
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +212,7 @@ fmt_scaled(long long number, char *result)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unit_type unit = NONE;
|
unit_type unit = NONE;
|
||||||
|
|
||||||
abval = (number < 0LL) ? -number : number; /* no long long_abs yet */
|
abval = llabs(number);
|
||||||
|
|
||||||
/* Not every negative long long has a positive representation.
|
/* Not every negative long long has a positive representation.
|
||||||
* Also check for numbers that are just too darned big to format
|
* Also check for numbers that are just too darned big to format
|
||||||
|
|
Loading…
Reference in New Issue