diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-22 06:20:26 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-05-22 06:20:26 +0200 |
commit | e85248afa23434b78e48fe09b57eea5f6657410d (patch) | |
tree | 8e4ddbead7f630a6cf3f5e224fb05952818b76a2 /shell/hush.c | |
parent | 8a33679694b0fdf459d69868f85c081cab5687cb (diff) | |
download | busybox-w32-e85248afa23434b78e48fe09b57eea5f6657410d.tar.gz busybox-w32-e85248afa23434b78e48fe09b57eea5f6657410d.tar.bz2 busybox-w32-e85248afa23434b78e48fe09b57eea5f6657410d.zip |
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>
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 81 |
1 files changed, 47 insertions, 34 deletions
diff --git a/shell/hush.c b/shell/hush.c index 7645a34a4..08e63785d 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -179,9 +179,13 @@ | |||
179 | 179 | ||
180 | #define ERR_PTR ((void*)(long)1) | 180 | #define ERR_PTR ((void*)(long)1) |
181 | 181 | ||
182 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" | 182 | #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" |
183 | 183 | ||
184 | #define SPECIAL_VAR_SYMBOL 3 | 184 | #define _SPECIAL_VARS_STR "_*@$!?#" |
185 | #define SPECIAL_VARS_STR ("_*@$!?#" + 1) | ||
186 | #define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) | ||
187 | |||
188 | #define SPECIAL_VAR_SYMBOL 3 | ||
185 | 189 | ||
186 | struct variable; | 190 | struct variable; |
187 | 191 | ||
@@ -2472,21 +2476,6 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2472 | 2476 | ||
2473 | switch (first_ch & 0x7f) { | 2477 | switch (first_ch & 0x7f) { |
2474 | /* Highest bit in first_ch indicates that var is double-quoted */ | 2478 | /* Highest bit in first_ch indicates that var is double-quoted */ |
2475 | case '$': /* pid */ | ||
2476 | val = utoa(G.root_pid); | ||
2477 | break; | ||
2478 | case '!': /* bg pid */ | ||
2479 | val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)""; | ||
2480 | break; | ||
2481 | case '?': /* exitcode */ | ||
2482 | val = utoa(G.last_exitcode); | ||
2483 | break; | ||
2484 | case '#': /* argc */ | ||
2485 | if (arg[1] != SPECIAL_VAR_SYMBOL) | ||
2486 | /* actually, it's a ${#var} */ | ||
2487 | goto case_default; | ||
2488 | val = utoa(G.global_argc ? G.global_argc-1 : 0); | ||
2489 | break; | ||
2490 | case '*': | 2479 | case '*': |
2491 | case '@': | 2480 | case '@': |
2492 | i = 1; | 2481 | i = 1; |
@@ -2581,27 +2570,35 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2581 | break; | 2570 | break; |
2582 | } | 2571 | } |
2583 | #endif | 2572 | #endif |
2584 | default: /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ | 2573 | default: { /* <SPECIAL_VAR_SYMBOL>varname<SPECIAL_VAR_SYMBOL> */ |
2585 | case_default: { | 2574 | char *var; |
2586 | char *var = arg; | 2575 | char first_char; |
2587 | char exp_len; /* '#' if it's ${#var} */ | ||
2588 | char exp_op; | 2576 | char exp_op; |
2589 | char exp_save = exp_save; /* for compiler */ | 2577 | char exp_save = exp_save; /* for compiler */ |
2590 | char *exp_saveptr = exp_saveptr; /* points to expansion operator */ | 2578 | char *exp_saveptr; /* points to expansion operator */ |
2591 | char *exp_word = exp_word; /* for compiler */ | 2579 | char *exp_word = exp_word; /* for compiler */ |
2592 | 2580 | ||
2581 | var = arg; | ||
2593 | *p = '\0'; | 2582 | *p = '\0'; |
2594 | arg[0] = first_ch & 0x7f; | 2583 | exp_saveptr = arg[1] ? strchr("%#:-=+?", arg[1]) : NULL; |
2595 | 2584 | first_char = arg[0] = first_ch & 0x7f; | |
2596 | /* prepare for expansions */ | ||
2597 | exp_op = 0; | 2585 | exp_op = 0; |
2598 | exp_len = var[0]; | 2586 | |
2599 | if (exp_len == '#') { | 2587 | if (first_char == '#' && arg[1] && !exp_saveptr) { |
2600 | /* handle length expansion ${#var} */ | 2588 | /* handle length expansion ${#var} */ |
2601 | var++; | 2589 | var++; |
2590 | exp_op = 'L'; | ||
2602 | } else { | 2591 | } else { |
2603 | /* maybe handle parameter expansion */ | 2592 | /* maybe handle parameter expansion */ |
2604 | exp_saveptr = var + strcspn(var, "%#:-=+?"); | 2593 | if (exp_saveptr /* if 2nd char is one of expansion operators */ |
2594 | && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ | ||
2595 | ) { | ||
2596 | /* ${?:0}, ${#[:]%0} etc */ | ||
2597 | exp_saveptr = var + 1; | ||
2598 | } else { | ||
2599 | /* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */ | ||
2600 | exp_saveptr = var+1 + strcspn(var+1, "%#:-=+?"); | ||
2601 | } | ||
2605 | exp_op = exp_save = *exp_saveptr; | 2602 | exp_op = exp_save = *exp_saveptr; |
2606 | if (exp_op) { | 2603 | if (exp_op) { |
2607 | exp_word = exp_saveptr + 1; | 2604 | exp_word = exp_saveptr + 1; |
@@ -2616,7 +2613,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2616 | } | 2613 | } |
2617 | } | 2614 | } |
2618 | *exp_saveptr = '\0'; | 2615 | *exp_saveptr = '\0'; |
2619 | } | 2616 | } /* else: it's not an expansion op, but bare ${var} */ |
2620 | } | 2617 | } |
2621 | 2618 | ||
2622 | /* lookup the variable in question */ | 2619 | /* lookup the variable in question */ |
@@ -2626,11 +2623,27 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char | |||
2626 | if (i < G.global_argc) | 2623 | if (i < G.global_argc) |
2627 | val = G.global_argv[i]; | 2624 | val = G.global_argv[i]; |
2628 | /* else val remains NULL: $N with too big N */ | 2625 | /* else val remains NULL: $N with too big N */ |
2629 | } else | 2626 | } else { |
2630 | val = get_local_var_value(var); | 2627 | switch (var[0]) { |
2628 | case '$': /* pid */ | ||
2629 | val = utoa(G.root_pid); | ||
2630 | break; | ||
2631 | case '!': /* bg pid */ | ||
2632 | val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)""; | ||
2633 | break; | ||
2634 | case '?': /* exitcode */ | ||
2635 | val = utoa(G.last_exitcode); | ||
2636 | break; | ||
2637 | case '#': /* argc */ | ||
2638 | val = utoa(G.global_argc ? G.global_argc-1 : 0); | ||
2639 | break; | ||
2640 | default: | ||
2641 | val = get_local_var_value(var); | ||
2642 | } | ||
2643 | } | ||
2631 | 2644 | ||
2632 | /* handle any expansions */ | 2645 | /* handle any expansions */ |
2633 | if (exp_len == '#') { | 2646 | if (exp_op == 'L') { |
2634 | debug_printf_expand("expand: length(%s)=", val); | 2647 | debug_printf_expand("expand: length(%s)=", val); |
2635 | val = utoa(val ? strlen(val) : 0); | 2648 | val = utoa(val ? strlen(val) : 0); |
2636 | debug_printf_expand("%s\n", val); | 2649 | 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 | |||
2761 | } | 2774 | } |
2762 | } | 2775 | } |
2763 | } | 2776 | } |
2764 | } | 2777 | } /* one of "-=+?" */ |
2765 | 2778 | ||
2766 | *exp_saveptr = exp_save; | 2779 | *exp_saveptr = exp_save; |
2767 | } /* if (exp_op) */ | 2780 | } /* if (exp_op) */ |
@@ -6031,7 +6044,7 @@ static int handle_dollar(o_string *as_string, | |||
6031 | * or even ${?+subst} - operator acting on a special variable, | 6044 | * or even ${?+subst} - operator acting on a special variable, |
6032 | * or the beginning of variable name. | 6045 | * or the beginning of variable name. |
6033 | */ | 6046 | */ |
6034 | if (!strchr("$!?#*@_", ch) && !isalnum(ch)) { /* not one of those */ | 6047 | if (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch)) { /* not one of those */ |
6035 | bad_dollar_syntax: | 6048 | bad_dollar_syntax: |
6036 | syntax_error_unterm_str("${name}"); | 6049 | syntax_error_unterm_str("${name}"); |
6037 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); | 6050 | debug_printf_parse("handle_dollar return 1: unterminated ${name}\n"); |