hush: fix SEGV in % expansion
function old new delta expand_variables 2203 2217 +14
This commit is contained in:
parent
80e57eb7d5
commit
5b7589eb27
24
shell/hush.c
24
shell/hush.c
|
@ -1990,12 +1990,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
||||||
* (expansion of right-hand side of assignment == 1-element expand.
|
* (expansion of right-hand side of assignment == 1-element expand.
|
||||||
* It will also do no globbing, and thus we must not backslash-quote!) */
|
* It will also do no globbing, and thus we must not backslash-quote!) */
|
||||||
|
|
||||||
char first_ch, ored_ch;
|
char ored_ch;
|
||||||
int i;
|
char *p;
|
||||||
const char *val;
|
|
||||||
char *dyn_val, *p;
|
|
||||||
|
|
||||||
dyn_val = NULL;
|
|
||||||
ored_ch = 0;
|
ored_ch = 0;
|
||||||
|
|
||||||
debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
|
debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
|
||||||
|
@ -2004,6 +2001,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
||||||
debug_print_list("expand_vars_to_list[0]", output, n);
|
debug_print_list("expand_vars_to_list[0]", output, n);
|
||||||
|
|
||||||
while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
|
while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
|
||||||
|
char first_ch;
|
||||||
|
int i;
|
||||||
|
char *dyn_val = NULL;
|
||||||
|
const char *val = NULL;
|
||||||
#if ENABLE_HUSH_TICK
|
#if ENABLE_HUSH_TICK
|
||||||
o_string subst_result = NULL_O_STRING;
|
o_string subst_result = NULL_O_STRING;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2021,7 +2022,6 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
||||||
if ((first_ch & 0x7f) != '@')
|
if ((first_ch & 0x7f) != '@')
|
||||||
ored_ch |= first_ch;
|
ored_ch |= first_ch;
|
||||||
|
|
||||||
val = NULL;
|
|
||||||
switch (first_ch & 0x7f) {
|
switch (first_ch & 0x7f) {
|
||||||
/* Highest bit in first_ch indicates that var is double-quoted */
|
/* Highest bit in first_ch indicates that var is double-quoted */
|
||||||
case '$': /* pid */
|
case '$': /* pid */
|
||||||
|
@ -2194,16 +2194,16 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
||||||
if (exp_op == '%' || exp_op == '#') {
|
if (exp_op == '%' || exp_op == '#') {
|
||||||
if (val) {
|
if (val) {
|
||||||
/* we need to do a pattern match */
|
/* we need to do a pattern match */
|
||||||
bool zero;
|
bool match_at_left;
|
||||||
char *loc;
|
char *loc;
|
||||||
scan_t scan = pick_scan(exp_op, *exp_word, &zero);
|
scan_t scan = pick_scan(exp_op, *exp_word, &match_at_left);
|
||||||
if (exp_op == *exp_word) /* ## or %% */
|
if (exp_op == *exp_word) /* ## or %% */
|
||||||
++exp_word;
|
++exp_word;
|
||||||
val = dyn_val = xstrdup(val);
|
val = dyn_val = xstrdup(val);
|
||||||
loc = scan(dyn_val, exp_word, zero);
|
loc = scan(dyn_val, exp_word, match_at_left);
|
||||||
if (zero)
|
if (match_at_left) /* # or ## */
|
||||||
val = loc;
|
val = loc;
|
||||||
else
|
else if (loc) /* % or %% and match was found */
|
||||||
*loc = '\0';
|
*loc = '\0';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2263,11 +2263,11 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
|
||||||
}
|
}
|
||||||
} /* default: */
|
} /* default: */
|
||||||
} /* switch (char after <SPECIAL_VAR_SYMBOL>) */
|
} /* switch (char after <SPECIAL_VAR_SYMBOL>) */
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
o_addQstr(output, val, strlen(val));
|
o_addQstr(output, val, strlen(val));
|
||||||
}
|
}
|
||||||
free(dyn_val);
|
free(dyn_val);
|
||||||
dyn_val = NULL;
|
|
||||||
/* Do the check to avoid writing to a const string */
|
/* Do the check to avoid writing to a const string */
|
||||||
if (*p != SPECIAL_VAR_SYMBOL)
|
if (*p != SPECIAL_VAR_SYMBOL)
|
||||||
*p = SPECIAL_VAR_SYMBOL;
|
*p = SPECIAL_VAR_SYMBOL;
|
||||||
|
|
|
@ -63,9 +63,9 @@ hush: error in arithmetic
|
||||||
40 40
|
40 40
|
||||||
hush: error in arithmetic
|
hush: error in arithmetic
|
||||||
hush: divide by 0
|
hush: divide by 0
|
||||||
hush: can't exec 'let': No such file or directory
|
hush: can't execute 'let': No such file or directory
|
||||||
hush: error in arithmetic
|
hush: error in arithmetic
|
||||||
hush: can't exec 'let': No such file or directory
|
hush: can't execute 'let': No such file or directory
|
||||||
abc
|
abc
|
||||||
def
|
def
|
||||||
ghi
|
ghi
|
||||||
|
@ -135,4 +135,4 @@ hush: error in arithmetic
|
||||||
42
|
42
|
||||||
42
|
42
|
||||||
42
|
42
|
||||||
hush: can't exec 'a[b[c]d]=e': No such file or directory
|
hush: can't execute 'a[b[c]d]=e': No such file or directory
|
||||||
|
|
|
@ -32,4 +32,5 @@ ababcdc
|
||||||
ababcdcd
|
ababcdcd
|
||||||
Empty:
|
Empty:
|
||||||
ababcdcd}_tail
|
ababcdcd}_tail
|
||||||
|
ababcdcd
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,5 +43,6 @@ echo ${var%*}
|
||||||
echo Empty:${var%%*}
|
echo Empty:${var%%*}
|
||||||
echo ${var#}}_tail
|
echo ${var#}}_tail
|
||||||
# UNFIXED BUG: echo ${var#\}}_tail
|
# UNFIXED BUG: echo ${var#\}}_tail
|
||||||
|
echo ${var%\\*}
|
||||||
|
|
||||||
echo end
|
echo end
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
* Kenneth Almquist.
|
* Kenneth Almquist.
|
||||||
*
|
*
|
||||||
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
* Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
||||||
*
|
|
||||||
* Original BSD copyright notice is retained at the end of this file.
|
|
||||||
*/
|
*/
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
|
@ -28,7 +26,7 @@
|
||||||
|
|
||||||
#define pmatch(a, b) !fnmatch((a), (b), 0)
|
#define pmatch(a, b) !fnmatch((a), (b), 0)
|
||||||
|
|
||||||
char *scanleft(char *string, char *pattern, bool zero)
|
char *scanleft(char *string, char *pattern, bool match_at_left)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
char *loc = string;
|
char *loc = string;
|
||||||
|
@ -38,7 +36,7 @@ char *scanleft(char *string, char *pattern, bool zero)
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
c = *loc;
|
c = *loc;
|
||||||
if (zero) {
|
if (match_at_left) {
|
||||||
*loc = '\0';
|
*loc = '\0';
|
||||||
s = string;
|
s = string;
|
||||||
} else
|
} else
|
||||||
|
@ -55,7 +53,7 @@ char *scanleft(char *string, char *pattern, bool zero)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *scanright(char *string, char *pattern, bool zero)
|
char *scanright(char *string, char *pattern, bool match_at_left)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
char *loc = string + strlen(string);
|
char *loc = string + strlen(string);
|
||||||
|
@ -65,7 +63,7 @@ char *scanright(char *string, char *pattern, bool zero)
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
c = *loc;
|
c = *loc;
|
||||||
if (zero) {
|
if (match_at_left) {
|
||||||
*loc = '\0';
|
*loc = '\0';
|
||||||
s = string;
|
s = string;
|
||||||
} else
|
} else
|
||||||
|
@ -88,7 +86,7 @@ int main(int argc, char *argv[])
|
||||||
char *string;
|
char *string;
|
||||||
char *op;
|
char *op;
|
||||||
char *pattern;
|
char *pattern;
|
||||||
bool zero;
|
bool match_at_left;
|
||||||
char *loc;
|
char *loc;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
@ -117,15 +115,15 @@ int main(int argc, char *argv[])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
op = string + off;
|
op = string + off;
|
||||||
scan = pick_scan(op[0], op[1], &zero);
|
scan = pick_scan(op[0], op[1], &match_at_left);
|
||||||
pattern = op + 1;
|
pattern = op + 1;
|
||||||
if (op[0] == op[1])
|
if (op[0] == op[1])
|
||||||
op[1] = '\0', ++pattern;
|
op[1] = '\0', ++pattern;
|
||||||
op[0] = '\0';
|
op[0] = '\0';
|
||||||
|
|
||||||
loc = scan(string, pattern, zero);
|
loc = scan(string, pattern, match_at_left);
|
||||||
|
|
||||||
if (zero) {
|
if (match_at_left) {
|
||||||
printf("'%s'\n", loc);
|
printf("'%s'\n", loc);
|
||||||
} else {
|
} else {
|
||||||
*loc = '\0';
|
*loc = '\0';
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
|
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
|
||||||
|
|
||||||
typedef char *(*scan_t)(char *string, char *match, bool zero);
|
typedef char *(*scan_t)(char *string, char *match, bool match_at_left);
|
||||||
|
|
||||||
char *scanleft(char *string, char *match, bool zero);
|
char *scanleft(char *string, char *match, bool match_at_left);
|
||||||
char *scanright(char *string, char *match, bool zero);
|
char *scanright(char *string, char *match, bool match_at_left);
|
||||||
|
|
||||||
static inline scan_t pick_scan(char op1, char op2, bool *zero)
|
static inline scan_t pick_scan(char op1, char op2, bool *match_at_left)
|
||||||
{
|
{
|
||||||
/* # - scanleft
|
/* # - scanleft
|
||||||
* ## - scanright
|
* ## - scanright
|
||||||
|
@ -15,10 +15,10 @@ static inline scan_t pick_scan(char op1, char op2, bool *zero)
|
||||||
* %% - scanleft
|
* %% - scanleft
|
||||||
*/
|
*/
|
||||||
if (op1 == '#') {
|
if (op1 == '#') {
|
||||||
*zero = true;
|
*match_at_left = true;
|
||||||
return op1 == op2 ? scanright : scanleft;
|
return op1 == op2 ? scanright : scanleft;
|
||||||
} else {
|
} else {
|
||||||
*zero = false;
|
*match_at_left = false;
|
||||||
return op1 == op2 ? scanleft : scanright;
|
return op1 == op2 ? scanleft : scanright;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user