ash: make ${v:N:M} more robust for very large M by clamping to MIN/MAX_INT
Before this patch, "${v:2:0x100000001}" = "${v:2:1}", and similarly, constructs like "${v:2:9999999999}" may give wrong result due to int overflows. function old new delta substr_atoi - 43 +43 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
2c876774a9
commit
baa41c7855
38
shell/ash.c
38
shell/ash.c
@ -5780,6 +5780,26 @@ ash_arith(const char *s)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#if BASH_SUBSTR
|
||||
# if ENABLE_FEATURE_SH_MATH
|
||||
static int substr_atoi(const char *s)
|
||||
{
|
||||
arith_t t = ash_arith(s);
|
||||
if (sizeof(t) > sizeof(int)) {
|
||||
/* clamp very large or very large negative nums for ${v:N:M}:
|
||||
* else "${v:0:0x100000001}" would work as "${v:0:1}"
|
||||
*/
|
||||
if (t > INT_MAX)
|
||||
t = INT_MAX;
|
||||
if (t < INT_MIN)
|
||||
t = INT_MIN;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
# else
|
||||
# define substr_atoi(s) number(s)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* expandarg flags
|
||||
@ -6816,13 +6836,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||
|
||||
loc = str = stackblock() + strloc;
|
||||
|
||||
# if !ENABLE_FEATURE_SH_MATH
|
||||
# define ash_arith number
|
||||
# endif
|
||||
/* Read POS in ${var:POS:LEN} */
|
||||
colon = strchr(loc, ':');
|
||||
if (colon) *colon = '\0';
|
||||
pos = ash_arith(loc);
|
||||
pos = substr_atoi(loc);
|
||||
if (colon) *colon = ':';
|
||||
|
||||
/* Read LEN in ${var:POS:LEN} */
|
||||
@ -6830,7 +6847,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||
/* *loc != '\0', guaranteed by parser */
|
||||
if (quotes) {
|
||||
char *ptr;
|
||||
|
||||
/* Adjust the length by the number of escapes */
|
||||
for (ptr = startp; ptr < (str - 1); ptr++) {
|
||||
if ((unsigned char)*ptr == CTLESC) {
|
||||
@ -6842,19 +6858,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
|
||||
orig_len = len;
|
||||
if (*loc++ == ':') {
|
||||
/* ${var::LEN} */
|
||||
len = ash_arith(loc);
|
||||
len = substr_atoi(loc);
|
||||
} else {
|
||||
/* Skip POS in ${var:POS:LEN} */
|
||||
len = orig_len;
|
||||
while (*loc && *loc != ':') {
|
||||
while (*loc && *loc != ':')
|
||||
loc++;
|
||||
}
|
||||
if (*loc++ == ':') {
|
||||
len = ash_arith(loc);
|
||||
}
|
||||
if (*loc++ == ':')
|
||||
len = substr_atoi(loc);
|
||||
}
|
||||
# undef ash_arith
|
||||
|
||||
if (pos < 0) {
|
||||
/* ${VAR:$((-n)):l} starts n chars from the end */
|
||||
pos = orig_len + pos;
|
||||
|
Loading…
Reference in New Issue
Block a user