hush: fix segfault in ${?:N:M}
function old new delta expand_vars_to_list 2374 2409 +35 builtin_umask 132 133 +1 builtin_exit 47 48 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 37/0) Total: 37 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
8a33679694
commit
e85248afa2
81
shell/hush.c
81
shell/hush.c
@ -179,9 +179,13 @@
|
|||||||
|
|
||||||
#define ERR_PTR ((void*)(long)1)
|
#define ERR_PTR ((void*)(long)1)
|
||||||
|
|
||||||
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
|
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
|
||||||
|
|
||||||
#define SPECIAL_VAR_SYMBOL 3
|
#define _SPECIAL_VARS_STR "_*@$!?#"
|
||||||
|
#define SPECIAL_VARS_STR ("_*@$!?#" + 1)
|
||||||
|
#define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3)
|
||||||
|
|
||||||
|
#define SPECIAL_VAR_SYMBOL 3
|
||||||
|
|
||||||
struct variable;
|
struct variable;
|
||||||
|
|
||||||
@ -2472,21 +2476,6 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
|||||||
|
|
||||||
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 */
|
|
||||||
val = utoa(G.root_pid);
|
|
||||||
break;
|
|
||||||
case '!': /* bg pid */
|
|
||||||
val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)"";
|
|
||||||
break;
|
|
||||||
case '?': /* exitcode */
|
|
||||||
val = utoa(G.last_exitcode);
|
|
||||||
break;
|
|
||||||
case '#': /* argc */
|
|
||||||
if (arg[1] != SPECIAL_VAR_SYMBOL)
|
|
||||||
/* actually, it's a ${#var} */
|
|
||||||
goto case_default;
|
|
||||||
val = utoa(G.global_argc ? G.global_argc-1 : 0);
|
|
||||||
break;
|
|
||||||
case '*':
|
case '*':
|
||||||
case '@':
|
case '@':
|
||||||
i = 1;
|
i = 1;
|
||||||
@ -2581,27 +2570,35 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
|
default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */
|
||||||
case_default: {
|
char *var;
|
||||||
char *var = arg;
|
char first_char;
|
||||||
char exp_len; /* '#' if it's ${#var} */
|
|
||||||
char exp_op;
|
char exp_op;
|
||||||
char exp_save = exp_save; /* for compiler */
|
char exp_save = exp_save; /* for compiler */
|
||||||
char *exp_saveptr = exp_saveptr; /* points to expansion operator */
|
char *exp_saveptr; /* points to expansion operator */
|
||||||
char *exp_word = exp_word; /* for compiler */
|
char *exp_word = exp_word; /* for compiler */
|
||||||
|
|
||||||
|
var = arg;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
arg[0] = first_ch & 0x7f;
|
exp_saveptr = arg[1] ? strchr("%#:-=+?", arg[1]) : NULL;
|
||||||
|
first_char = arg[0] = first_ch & 0x7f;
|
||||||
/* prepare for expansions */
|
|
||||||
exp_op = 0;
|
exp_op = 0;
|
||||||
exp_len = var[0];
|
|
||||||
if (exp_len == '#') {
|
if (first_char == '#' && arg[1] && !exp_saveptr) {
|
||||||
/* handle length expansion ${#var} */
|
/* handle length expansion ${#var} */
|
||||||
var++;
|
var++;
|
||||||
|
exp_op = 'L';
|
||||||
} else {
|
} else {
|
||||||
/* maybe handle parameter expansion */
|
/* maybe handle parameter expansion */
|
||||||
exp_saveptr = var + strcspn(var, "%#:-=+?");
|
if (exp_saveptr /* if 2nd char is one of expansion operators */
|
||||||
|
&& strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */
|
||||||
|
) {
|
||||||
|
/* ${?:0}, ${#[:]%0} etc */
|
||||||
|
exp_saveptr = var + 1;
|
||||||
|
} else {
|
||||||
|
/* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */
|
||||||
|
exp_saveptr = var+1 + strcspn(var+1, "%#:-=+?");
|
||||||
|
}
|
||||||
exp_op = exp_save = *exp_saveptr;
|
exp_op = exp_save = *exp_saveptr;
|
||||||
if (exp_op) {
|
if (exp_op) {
|
||||||
exp_word = exp_saveptr + 1;
|
exp_word = exp_saveptr + 1;
|
||||||
@ -2616,7 +2613,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*exp_saveptr = '\0';
|
*exp_saveptr = '\0';
|
||||||
}
|
} /* else: it's not an expansion op, but bare ${var} */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup the variable in question */
|
/* lookup the variable in question */
|
||||||
@ -2626,11 +2623,27 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
|||||||
if (i < G.global_argc)
|
if (i < G.global_argc)
|
||||||
val = G.global_argv[i];
|
val = G.global_argv[i];
|
||||||
/* else val remains NULL: $N with too big N */
|
/* else val remains NULL: $N with too big N */
|
||||||
} else
|
} else {
|
||||||
val = get_local_var_value(var);
|
switch (var[0]) {
|
||||||
|
case '$': /* pid */
|
||||||
|
val = utoa(G.root_pid);
|
||||||
|
break;
|
||||||
|
case '!': /* bg pid */
|
||||||
|
val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)"";
|
||||||
|
break;
|
||||||
|
case '?': /* exitcode */
|
||||||
|
val = utoa(G.last_exitcode);
|
||||||
|
break;
|
||||||
|
case '#': /* argc */
|
||||||
|
val = utoa(G.global_argc ? G.global_argc-1 : 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
val = get_local_var_value(var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* handle any expansions */
|
/* handle any expansions */
|
||||||
if (exp_len == '#') {
|
if (exp_op == 'L') {
|
||||||
debug_printf_expand("expand: length(%s)=", val);
|
debug_printf_expand("expand: length(%s)=", val);
|
||||||
val = utoa(val ? strlen(val) : 0);
|
val = utoa(val ? strlen(val) : 0);
|
||||||
debug_printf_expand("%s\n", val);
|
debug_printf_expand("%s\n", val);
|
||||||
@ -2761,7 +2774,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} /* one of "-=+?" */
|
||||||
|
|
||||||
*exp_saveptr = exp_save;
|
*exp_saveptr = exp_save;
|
||||||
} /* if (exp_op) */
|
} /* if (exp_op) */
|
||||||
@ -6031,7 +6044,7 @@ static int handle_dollar(o_string *as_string,
|
|||||||
* or even ${?+subst} - operator acting on a special variable,
|
* or even ${?+subst} - operator acting on a special variable,
|
||||||
* or the beginning of variable name.
|
* or the beginning of variable name.
|
||||||
*/
|
*/
|
||||||
if (!strchr("$!?#*@_", ch) && !isalnum(ch)) { /* not one of those */
|
if (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch)) { /* not one of those */
|
||||||
bad_dollar_syntax:
|
bad_dollar_syntax:
|
||||||
syntax_error_unterm_str("${name}");
|
syntax_error_unterm_str("${name}");
|
||||||
debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
|
debug_printf_parse("handle_dollar return 1: unterminated ${name}\n");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
hush: syntax error: unterminated ${name}
|
hush: syntax error: unterminated ${name}
|
||||||
hush: syntax error: unterminated ${name}
|
hush: syntax error: unterminated ${name}
|
||||||
_0 _0
|
__ __
|
||||||
_ _ _ _ _
|
_ _ _ _ _
|
||||||
_aaaa _ _ _word _word
|
_aaaa _ _ _word _word
|
||||||
_ _ _ _ _
|
_ _ _ _ _
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
"$THIS_SH" -c 'echo ${+} ; echo moo'
|
"$THIS_SH" -c 'echo ${+} ; echo moo'
|
||||||
"$THIS_SH" -c 'echo ${:+} ; echo moo'
|
"$THIS_SH" -c 'echo ${:+} ; echo moo'
|
||||||
|
|
||||||
# now some funky ones
|
# now some funky ones. (bash doesn't accept ${#+})
|
||||||
echo _${#+} _${#:+}
|
echo _${#+}_ _${#:+}_
|
||||||
|
|
||||||
# now some valid ones
|
# now some valid ones
|
||||||
set --
|
set --
|
||||||
|
@ -39,6 +39,19 @@ f:1:2=|12|
|
|||||||
f::2 =|01|
|
f::2 =|01|
|
||||||
f:1: =||
|
f:1: =||
|
||||||
f:: =||
|
f:: =||
|
||||||
|
Substrings from special vars
|
||||||
|
? =|0|
|
||||||
|
?:1 =||
|
||||||
|
?:1:2=||
|
||||||
|
?::2 =|0|
|
||||||
|
?:1: =||
|
||||||
|
?:: =||
|
||||||
|
# =|11|
|
||||||
|
#:1 =|1|
|
||||||
|
#:1:2=|1|
|
||||||
|
#::2 =|11|
|
||||||
|
#:1: =||
|
||||||
|
#:: =||
|
||||||
Substrings with expressions
|
Substrings with expressions
|
||||||
f =|01234567|
|
f =|01234567|
|
||||||
f:1+1:2+2 =|2345|
|
f:1+1:2+2 =|2345|
|
||||||
|
@ -55,6 +55,21 @@ f=0123456789; echo "f::2 =|${f::2}|"
|
|||||||
f=0123456789; echo "f:1: =|${f:1:}|"
|
f=0123456789; echo "f:1: =|${f:1:}|"
|
||||||
f=0123456789; echo "f:: =|${f::}|"
|
f=0123456789; echo "f:: =|${f::}|"
|
||||||
|
|
||||||
|
echo "Substrings from special vars"
|
||||||
|
echo '? '"=|$?|"
|
||||||
|
echo '?:1 '"=|${?:1}|"
|
||||||
|
echo '?:1:2'"=|${?:1:2}|"
|
||||||
|
echo '?::2 '"=|${?::2}|"
|
||||||
|
echo '?:1: '"=|${?:1:}|"
|
||||||
|
echo '?:: '"=|${?::}|"
|
||||||
|
set -- 1 2 3 4 5 6 7 8 9 10 11
|
||||||
|
echo '# '"=|$#|"
|
||||||
|
echo '#:1 '"=|${#:1}|"
|
||||||
|
echo '#:1:2'"=|${#:1:2}|"
|
||||||
|
echo '#::2 '"=|${#::2}|"
|
||||||
|
echo '#:1: '"=|${#:1:}|"
|
||||||
|
echo '#:: '"=|${#::}|"
|
||||||
|
|
||||||
echo "Substrings with expressions"
|
echo "Substrings with expressions"
|
||||||
f=01234567; echo 'f '"=|$f|"
|
f=01234567; echo 'f '"=|$f|"
|
||||||
f=01234567; echo 'f:1+1:2+2 '"=|${f:1+1:2+2}|"
|
f=01234567; echo 'f:1+1:2+2 '"=|${f:1+1:2+2}|"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user