hush: fix handling of } which is not a closing one in { cmd; }

function                                             old     new   delta
parse_stream                                        2176    2302    +126
builtin_unset                                        381     387      +6
This commit is contained in:
Denis Vlasenko 2009-04-19 13:57:51 +00:00
parent a29c935442
commit bf25fbccb9
6 changed files with 45 additions and 18 deletions

View File

@ -1822,7 +1822,7 @@ static int o_glob(o_string *o, int n)
goto literal; goto literal;
} }
if (gr != 0) { /* GLOB_ABORTED ? */ if (gr != 0) { /* GLOB_ABORTED ? */
//TODO: testcase for bad glob pattern behavior /* TODO: testcase for bad glob pattern behavior */
bb_error_msg("glob(3) error %d on '%s'", gr, pattern); bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
} }
if (globdata.gl_pathv && globdata.gl_pathv[0]) { if (globdata.gl_pathv && globdata.gl_pathv[0]) {
@ -2339,7 +2339,8 @@ static char* expand_strvec_to_string(char **argv)
if (HUSH_DEBUG) if (HUSH_DEBUG)
if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
bb_error_msg_and_die("BUG in varexp3"); bb_error_msg_and_die("BUG in varexp3");
list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */ /* bash uses ' ' regardless of $IFS contents */
list[n][-1] = ' ';
n++; n++;
} }
} }
@ -5128,14 +5129,16 @@ static int handle_dollar(o_string *as_string,
while (1) { while (1) {
ch = i_getch(input); ch = i_getch(input);
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
if (ch == '}') if (ch == '}') {
break; break;
}
if (first_char) { if (first_char) {
if (ch == '#') if (ch == '#') {
/* ${#var}: length of var contents */ /* ${#var}: length of var contents */
goto char_ok; goto char_ok;
else if (isdigit(ch)) { }
if (isdigit(ch)) {
all_digits = true; all_digits = true;
goto char_ok; goto char_ok;
} }
@ -5186,7 +5189,7 @@ static int handle_dollar(o_string *as_string,
o_addchr(dest, ch | quote_mask); o_addchr(dest, ch | quote_mask);
quote_mask = 0; quote_mask = 0;
first_char = false; first_char = false;
} } /* while (1) */
o_addchr(dest, SPECIAL_VAR_SYMBOL); o_addchr(dest, SPECIAL_VAR_SYMBOL);
break; break;
} }
@ -5432,6 +5435,7 @@ static struct pipe *parse_stream(char **pstring,
, ch); , ch);
if (!is_special && !is_ifs) { /* ordinary char */ if (!is_special && !is_ifs) { /* ordinary char */
ordinary_char:
o_addQchr(&dest, ch); o_addQchr(&dest, ch);
if ((dest.o_assignment == MAYBE_ASSIGNMENT if ((dest.o_assignment == MAYBE_ASSIGNMENT
|| dest.o_assignment == WORD_IS_KEYWORD) || dest.o_assignment == WORD_IS_KEYWORD)
@ -5475,6 +5479,19 @@ static struct pipe *parse_stream(char **pstring,
if (end_trigger && end_trigger == ch if (end_trigger && end_trigger == ch
&& (heredoc_cnt == 0 || end_trigger != ';') && (heredoc_cnt == 0 || end_trigger != ';')
) { ) {
/* "{ cmd}" or "{ cmd }..." without semicolon or &:
* } is an ordinary char in this case.
* Pathological example: { ""}; } should exec "}" cmd
*/
if (ch == '}'
&& !(IS_NULL_PIPE(ctx.pipe)
&& IS_NULL_CMD(ctx.command)
&& dest.length == 0
&& !dest.o_quoted
)
) {
goto ordinary_char;
}
if (heredoc_cnt) { if (heredoc_cnt) {
/* This is technically valid: /* This is technically valid:
* { cat <<HERE; }; echo Ok * { cat <<HERE; }; echo Ok
@ -5491,15 +5508,6 @@ static struct pipe *parse_stream(char **pstring,
if (done_word(&dest, &ctx)) { if (done_word(&dest, &ctx)) {
goto parse_error; goto parse_error;
} }
/* Disallow "{ cmd }" without semicolon or & */
//debug_printf_parse("null pi %d\n", IS_NULL_PIPE(ctx.pipe))
//debug_printf_parse("null cmd %d\n", IS_NULL_CMD(ctx.command))
if (ch == '}'
&& !(IS_NULL_PIPE(ctx.pipe) && IS_NULL_CMD(ctx.command))
) {
syntax_error_unexpected_ch(ch);
goto parse_error;
}
done_pipe(&ctx, PIPE_SEQ); done_pipe(&ctx, PIPE_SEQ);
dest.o_assignment = MAYBE_ASSIGNMENT; dest.o_assignment = MAYBE_ASSIGNMENT;
/* Do we sit outside of any if's, loops or case's? */ /* Do we sit outside of any if's, loops or case's? */
@ -5749,6 +5757,16 @@ static struct pipe *parse_stream(char **pstring,
goto case_semi; goto case_semi;
#endif #endif
case '}': case '}':
if (!(IS_NULL_PIPE(ctx.pipe)
&& IS_NULL_CMD(ctx.command)
&& dest.length == 0
&& !dest.o_quoted
)
) {
/* } not preceded by ; or & is an ordinary
* char, example: "echo }" */
goto ordinary_char;
}
/* proper use of this character is caught by end_trigger: /* proper use of this character is caught by end_trigger:
* if we see {, we call parse_group(..., end_trigger='}') * if we see {, we call parse_group(..., end_trigger='}')
* and it will match } earlier (not here). */ * and it will match } earlier (not here). */
@ -6858,7 +6876,8 @@ static int builtin_unset(char **argv)
var = 0; var = 0;
while ((arg = *argv) != NULL && arg[0] == '-') { while ((arg = *argv) != NULL && arg[0] == '-') {
while (*++arg) { arg++;
do {
switch (*arg) { switch (*arg) {
case 'v': case 'v':
case 'f': case 'f':
@ -6872,7 +6891,7 @@ static int builtin_unset(char **argv)
bb_error_msg("unset: %s: invalid option", *argv); bb_error_msg("unset: %s: invalid option", *argv);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} } while (*++arg);
argv++; argv++;
} }

View File

@ -1,5 +1,5 @@
export aaa1="'''" export aaa1="'''"
export aaa2= export aaa2=''
export aaa3="'''"'abc' export aaa3="'''"'abc'
export aaa4='def'"'''" export aaa4='def'"'''"
export aaa5="'''"'abc'"'''"'def'"'''" export aaa5="'''"'abc'"'''"'def'"'''"

View File

@ -0,0 +1 @@
word} }

View File

@ -0,0 +1 @@
{ echo word} }; }

View File

@ -22,6 +22,7 @@ babcdcd
babcdcd babcdcd
ababcdcd ababcdcd
Empty: Empty:
ababcdcd}_tail
ababcd ababcd
ababcd ababcd
ababcd ababcd
@ -30,4 +31,5 @@ ababcdc
ababcdc ababcdc
ababcdcd ababcdcd
Empty: Empty:
ababcdcd}_tail
end end

View File

@ -30,6 +30,8 @@ echo ${var#?}
echo ${var##?} echo ${var##?}
echo ${var#*} echo ${var#*}
echo Empty:${var##*} echo Empty:${var##*}
echo ${var#}}_tail
# UNFIXED BUG: echo ${var#\}}_tail
echo ${var%cd} echo ${var%cd}
echo ${var%%cd} echo ${var%%cd}
@ -39,5 +41,7 @@ echo ${var%?}
echo ${var%%?} echo ${var%%?}
echo ${var%*} echo ${var%*}
echo Empty:${var%%*} echo Empty:${var%%*}
echo ${var#}}_tail
# UNFIXED BUG: echo ${var#\}}_tail
echo end echo end