hush: more rodust detection of unterminated strings etc;
fix a case where we forget to copy `cmd` text; optimize nommu heredoc helper by not passing environment to it; add several tests function old new delta add_till_closing_paren 256 308 +52 parse_stream 2337 2378 +41 add_till_backquote 82 111 +29 re_execute_shell 269 284 +15 handle_dollar 802 812 +10 parse_stream_dquoted 316 320 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/0 up/down: 151/0) Total: 151 bytes
This commit is contained in:
parent
ffe6f80851
commit
5c090a96f9
96
shell/hush.c
96
shell/hush.c
@ -2241,7 +2241,10 @@ static void re_execute_shell(const char *s, int is_heredoc)
|
|||||||
|
|
||||||
debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
|
debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s);
|
||||||
sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
|
sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
|
||||||
execv(bb_busybox_exec_path, G.argv_from_re_execing);
|
execve(bb_busybox_exec_path,
|
||||||
|
G.argv_from_re_execing,
|
||||||
|
(is_heredoc ? pp /* points to NULL ptr */ : environ)
|
||||||
|
);
|
||||||
/* Fallback. Useful for init=/bin/hush usage etc */
|
/* Fallback. Useful for init=/bin/hush usage etc */
|
||||||
if (G.argv0_for_re_execing[0] == '/')
|
if (G.argv0_for_re_execing[0] == '/')
|
||||||
execv(G.argv0_for_re_execing, G.argv_from_re_execing);
|
execv(G.argv0_for_re_execing, G.argv_from_re_execing);
|
||||||
@ -4402,35 +4405,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
|
|||||||
|
|
||||||
#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT
|
#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT
|
||||||
/* Subroutines for copying $(...) and `...` things */
|
/* Subroutines for copying $(...) and `...` things */
|
||||||
static void add_till_backquote(o_string *dest, struct in_str *input);
|
static int add_till_backquote(o_string *dest, struct in_str *input);
|
||||||
/* '...' */
|
/* '...' */
|
||||||
static void add_till_single_quote(o_string *dest, struct in_str *input)
|
static int add_till_single_quote(o_string *dest, struct in_str *input)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
if (ch == EOF)
|
if (ch == EOF) {
|
||||||
break;
|
syntax("unterminated '");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (ch == '\'')
|
if (ch == '\'')
|
||||||
break;
|
return 0;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
|
/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
|
||||||
static void add_till_double_quote(o_string *dest, struct in_str *input)
|
static int add_till_double_quote(o_string *dest, struct in_str *input)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
|
if (ch == EOF) {
|
||||||
|
syntax("unterminated \"");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (ch == '"')
|
if (ch == '"')
|
||||||
break;
|
return 0;
|
||||||
if (ch == '\\') { /* \x. Copy both chars. */
|
if (ch == '\\') { /* \x. Copy both chars. */
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
}
|
}
|
||||||
if (ch == EOF)
|
|
||||||
break;
|
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
if (ch == '`') {
|
if (ch == '`') {
|
||||||
add_till_backquote(dest, input);
|
if (add_till_backquote(dest, input))
|
||||||
|
return 1;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -4451,20 +4459,27 @@ static void add_till_double_quote(o_string *dest, struct in_str *input)
|
|||||||
* Example Output
|
* Example Output
|
||||||
* echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
|
* echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
|
||||||
*/
|
*/
|
||||||
static void add_till_backquote(o_string *dest, struct in_str *input)
|
static int add_till_backquote(o_string *dest, struct in_str *input)
|
||||||
{
|
{
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
|
if (ch == EOF) {
|
||||||
|
syntax("unterminated `");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (ch == '`')
|
if (ch == '`')
|
||||||
break;
|
return 0;
|
||||||
if (ch == '\\') { /* \x. Copy both chars unless it is \` */
|
if (ch == '\\') {
|
||||||
|
/* \x. Copy both chars unless it is \` */
|
||||||
int ch2 = i_getch(input);
|
int ch2 = i_getch(input);
|
||||||
|
if (ch2 == EOF) {
|
||||||
|
syntax("unterminated `");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (ch2 != '`' && ch2 != '$' && ch2 != '\\')
|
if (ch2 != '`' && ch2 != '$' && ch2 != '\\')
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
ch = ch2;
|
ch = ch2;
|
||||||
}
|
}
|
||||||
if (ch == EOF)
|
|
||||||
break;
|
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4480,13 +4495,15 @@ static void add_till_backquote(o_string *dest, struct in_str *input)
|
|||||||
* echo $(echo 'TEST)' BEST) TEST) BEST
|
* echo $(echo 'TEST)' BEST) TEST) BEST
|
||||||
* echo $(echo \(\(TEST\) BEST) ((TEST) BEST
|
* echo $(echo \(\(TEST\) BEST) ((TEST) BEST
|
||||||
*/
|
*/
|
||||||
static void add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl)
|
static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
int ch = i_getch(input);
|
int ch = i_getch(input);
|
||||||
if (ch == EOF)
|
if (ch == EOF) {
|
||||||
break;
|
syntax("unterminated )");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (ch == '(')
|
if (ch == '(')
|
||||||
count++;
|
count++;
|
||||||
if (ch == ')') {
|
if (ch == ')') {
|
||||||
@ -4501,23 +4518,29 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db
|
|||||||
}
|
}
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
if (ch == '\'') {
|
if (ch == '\'') {
|
||||||
add_till_single_quote(dest, input);
|
if (add_till_single_quote(dest, input))
|
||||||
|
return 1;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '"') {
|
if (ch == '"') {
|
||||||
add_till_double_quote(dest, input);
|
if (add_till_double_quote(dest, input))
|
||||||
|
return 1;
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ch == '\\') { /* \x. Copy verbatim. Important for \(, \) */
|
if (ch == '\\') {
|
||||||
|
/* \x. Copy verbatim. Important for \(, \) */
|
||||||
ch = i_getch(input);
|
ch = i_getch(input);
|
||||||
if (ch == EOF)
|
if (ch == EOF) {
|
||||||
break;
|
syntax("unterminated )");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
o_addchr(dest, ch);
|
o_addchr(dest, ch);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */
|
#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */
|
||||||
|
|
||||||
@ -4658,7 +4681,8 @@ static int handle_dollar(o_string *as_string,
|
|||||||
# if !BB_MMU
|
# if !BB_MMU
|
||||||
pos = dest->length;
|
pos = dest->length;
|
||||||
# endif
|
# endif
|
||||||
add_till_closing_paren(dest, input, true);
|
if (add_till_closing_paren(dest, input, true))
|
||||||
|
return 1;
|
||||||
# if !BB_MMU
|
# if !BB_MMU
|
||||||
if (as_string) {
|
if (as_string) {
|
||||||
o_addstr(as_string, dest->data + pos);
|
o_addstr(as_string, dest->data + pos);
|
||||||
@ -4671,20 +4695,19 @@ static int handle_dollar(o_string *as_string,
|
|||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
# if ENABLE_HUSH_TICK
|
# if ENABLE_HUSH_TICK
|
||||||
//int pos = dest->length;
|
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, quote_mask | '`');
|
o_addchr(dest, quote_mask | '`');
|
||||||
# if !BB_MMU
|
# if !BB_MMU
|
||||||
pos = dest->length;
|
pos = dest->length;
|
||||||
# endif
|
# endif
|
||||||
add_till_closing_paren(dest, input, false);
|
if (add_till_closing_paren(dest, input, false))
|
||||||
|
return 1;
|
||||||
# if !BB_MMU
|
# if !BB_MMU
|
||||||
if (as_string) {
|
if (as_string) {
|
||||||
o_addstr(as_string, dest->data + pos);
|
o_addstr(as_string, dest->data + pos);
|
||||||
o_addchr(as_string, '`');
|
o_addchr(as_string, '`');
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
//debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos);
|
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
@ -4778,7 +4801,8 @@ static int parse_stream_dquoted(o_string *as_string,
|
|||||||
//int pos = dest->length;
|
//int pos = dest->length;
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(dest, 0x80 | '`');
|
o_addchr(dest, 0x80 | '`');
|
||||||
add_till_backquote(dest, input);
|
if (add_till_backquote(dest, input))
|
||||||
|
return 1;
|
||||||
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(dest, SPECIAL_VAR_SYMBOL);
|
||||||
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
//debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
|
||||||
goto again;
|
goto again;
|
||||||
@ -5043,10 +5067,20 @@ static struct pipe *parse_stream(char **pstring,
|
|||||||
break;
|
break;
|
||||||
#if ENABLE_HUSH_TICK
|
#if ENABLE_HUSH_TICK
|
||||||
case '`': {
|
case '`': {
|
||||||
//int pos = dest.length;
|
#if !BB_MMU
|
||||||
|
int pos;
|
||||||
|
#endif
|
||||||
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
||||||
o_addchr(&dest, '`');
|
o_addchr(&dest, '`');
|
||||||
add_till_backquote(&dest, input);
|
#if !BB_MMU
|
||||||
|
pos = dest.length;
|
||||||
|
#endif
|
||||||
|
if (add_till_backquote(&dest, input))
|
||||||
|
goto parse_error;
|
||||||
|
#if !BB_MMU
|
||||||
|
o_addstr(&ctx.as_string, dest.data + pos);
|
||||||
|
o_addchr(&ctx.as_string, '`');
|
||||||
|
#endif
|
||||||
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
o_addchr(&dest, SPECIAL_VAR_SYMBOL);
|
||||||
//debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos);
|
//debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos);
|
||||||
break;
|
break;
|
||||||
|
3
shell/hush_test/hush-misc/heredoc_huge.right
Normal file
3
shell/hush_test/hush-misc/heredoc_huge.right
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
546ed3f5c81c780d3ab86ada14824237 -
|
||||||
|
546ed3f5c81c780d3ab86ada14824237 -
|
||||||
|
End
|
9
shell/hush_test/hush-misc/heredoc_huge.tests
Executable file
9
shell/hush_test/hush-misc/heredoc_huge.tests
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
# This creates 120k heredoc
|
||||||
|
echo 'cat <<HERE | md5sum' >"$0.tmp"
|
||||||
|
yes "123456789 123456789 123456789 123456789" | head -3000 >>"$0.tmp"
|
||||||
|
echo 'HERE' >>"$0.tmp"
|
||||||
|
|
||||||
|
yes "123456789 123456789 123456789 123456789" | head -3000 | md5sum
|
||||||
|
. "$0.tmp"
|
||||||
|
rm "$0.tmp"
|
||||||
|
echo End
|
3
shell/hush_test/hush-psubst/tick_huge.right
Normal file
3
shell/hush_test/hush-psubst/tick_huge.right
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
546ed3f5c81c780d3ab86ada14824237 -
|
||||||
|
546ed3f5c81c780d3ab86ada14824237 -
|
||||||
|
End
|
7
shell/hush_test/hush-psubst/tick_huge.tests
Executable file
7
shell/hush_test/hush-psubst/tick_huge.tests
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
# This creates 120k file
|
||||||
|
yes "123456789 123456789 123456789 123456789" | head -3000 >>"$0.tmp"
|
||||||
|
|
||||||
|
echo "`cat $0.tmp`" | md5sum
|
||||||
|
rm "$0.tmp"
|
||||||
|
yes "123456789 123456789 123456789 123456789" | head -3000 | md5sum
|
||||||
|
echo End
|
3
shell/hush_test/hush-z_slow/leak_all2.right
Normal file
3
shell/hush_test/hush-z_slow/leak_all2.right
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Warm up
|
||||||
|
Measuring memory leak...
|
||||||
|
Ok
|
87
shell/hush_test/hush-z_slow/leak_all2.tests
Executable file
87
shell/hush_test/hush-z_slow/leak_all2.tests
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
# "Check many leaks" test #2
|
||||||
|
# Cramming all kinds of weird commands in here.
|
||||||
|
# As you find leaks, please create separate, small test
|
||||||
|
# for each leak.
|
||||||
|
# Narrowing down the leak using this large test may be difficult.
|
||||||
|
# It is intended to be a blanket "is everything ok?" test
|
||||||
|
|
||||||
|
echo "Warm up"
|
||||||
|
local_var="local val"
|
||||||
|
export dev_null="/dev/null"
|
||||||
|
>$dev_null
|
||||||
|
echo hi1 $local_var `echo ho` >>/dev/null
|
||||||
|
echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null
|
||||||
|
{ echo hi4 $local_var `echo ho` 1<>/dev/null; }
|
||||||
|
( echo hi4 $local_var `echo ho` 1<>/dev/null )
|
||||||
|
if echo $local_var; false
|
||||||
|
then echo not run
|
||||||
|
elif false <$dev_null
|
||||||
|
then none
|
||||||
|
else cat 0<>$dev_null 1<>"$dev_null"
|
||||||
|
fi >>/dev/null
|
||||||
|
{
|
||||||
|
if echo $local_var; then cat <<HERE
|
||||||
|
Hi cat
|
||||||
|
HERE
|
||||||
|
fi >>/dev/null
|
||||||
|
} 1<>/dev/null
|
||||||
|
while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done
|
||||||
|
( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null
|
||||||
|
|
||||||
|
memleak
|
||||||
|
|
||||||
|
echo "Measuring memory leak..."
|
||||||
|
# Please copy the entire block from above verbatim
|
||||||
|
local_var="local val"
|
||||||
|
export dev_null="/dev/null"
|
||||||
|
>$dev_null
|
||||||
|
echo hi1 $local_var `echo ho` >>/dev/null
|
||||||
|
echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null
|
||||||
|
{ echo hi4 $local_var `echo ho` 1<>/dev/null; }
|
||||||
|
( echo hi4 $local_var `echo ho` 1<>/dev/null )
|
||||||
|
if echo $local_var; false
|
||||||
|
then echo not run
|
||||||
|
elif false <$dev_null
|
||||||
|
then none
|
||||||
|
else cat 0<>$dev_null 1<>"$dev_null"
|
||||||
|
fi >>/dev/null
|
||||||
|
{
|
||||||
|
if echo $local_var; then cat <<HERE
|
||||||
|
Hi cat
|
||||||
|
HERE
|
||||||
|
fi >>/dev/null
|
||||||
|
} 1<>/dev/null
|
||||||
|
while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done
|
||||||
|
( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null
|
||||||
|
|
||||||
|
# And same again
|
||||||
|
|
||||||
|
local_var="local val"
|
||||||
|
export dev_null="/dev/null"
|
||||||
|
>$dev_null
|
||||||
|
echo hi1 $local_var `echo ho` >>/dev/null
|
||||||
|
echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null
|
||||||
|
{ echo hi4 $local_var `echo ho` 1<>/dev/null; }
|
||||||
|
( echo hi4 $local_var `echo ho` 1<>/dev/null )
|
||||||
|
if echo $local_var; false
|
||||||
|
then echo not run
|
||||||
|
elif false <$dev_null
|
||||||
|
then none
|
||||||
|
else cat 0<>$dev_null 1<>"$dev_null"
|
||||||
|
fi >>/dev/null
|
||||||
|
{
|
||||||
|
if echo $local_var; then cat <<HERE
|
||||||
|
Hi cat
|
||||||
|
HERE
|
||||||
|
fi >>/dev/null
|
||||||
|
} 1<>/dev/null
|
||||||
|
while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done
|
||||||
|
( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null
|
||||||
|
|
||||||
|
memleak
|
||||||
|
kb=$?
|
||||||
|
if test $kb -le 4; then
|
||||||
|
echo Ok #$kb
|
||||||
|
else
|
||||||
|
echo "Bad: $kb kb (or more) leaked"
|
||||||
|
fi
|
Loading…
x
Reference in New Issue
Block a user