diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-16 14:35:57 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-16 14:35:57 +0000 |
| commit | ccce59d5622dd32101e396580f7a148dfb3cb2d8 (patch) | |
| tree | 86ac723e88dd0756a808d3b8e7981c0acd45fe56 /shell | |
| parent | 32d8423e63258b8a0d0a30b8c52397d02489cad4 (diff) | |
| download | busybox-w32-ccce59d5622dd32101e396580f7a148dfb3cb2d8.tar.gz busybox-w32-ccce59d5622dd32101e396580f7a148dfb3cb2d8.tar.bz2 busybox-w32-ccce59d5622dd32101e396580f7a148dfb3cb2d8.zip | |
hush: fixing fallout from last big glob fix:
fix segfault; identify where we leak memory
function old new delta
expand_strvec_to_strvec 353 336 -17
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 160 |
1 files changed, 80 insertions, 80 deletions
diff --git a/shell/hush.c b/shell/hush.c index 7c5a44274..0e1976443 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -148,6 +148,11 @@ static const char *indenter(int i) | |||
| 148 | * Leak hunting. Use hush_leaktool.sh for post-processing. | 148 | * Leak hunting. Use hush_leaktool.sh for post-processing. |
| 149 | */ | 149 | */ |
| 150 | #ifdef FOR_HUSH_LEAKTOOL | 150 | #ifdef FOR_HUSH_LEAKTOOL |
| 151 | /* suppress "warning: no previous prototype..." */ | ||
| 152 | void *xxmalloc(int lineno, size_t size); | ||
| 153 | void *xxrealloc(int lineno, void *ptr, size_t size); | ||
| 154 | char *xxstrdup(int lineno, const char *str); | ||
| 155 | void xxfree(void *ptr); | ||
| 151 | void *xxmalloc(int lineno, size_t size) | 156 | void *xxmalloc(int lineno, size_t size) |
| 152 | { | 157 | { |
| 153 | void *ptr = xmalloc((size + 0xff) & ~0xff); | 158 | void *ptr = xmalloc((size + 0xff) & ~0xff); |
| @@ -2474,72 +2479,6 @@ static int run_and_free_list(struct pipe *pi) | |||
| 2474 | return rcode; | 2479 | return rcode; |
| 2475 | } | 2480 | } |
| 2476 | 2481 | ||
| 2477 | /* Remove non-backslashed backslashes and add to "strings" vector. | ||
| 2478 | * XXX broken if the last character is '\\', check that before calling. | ||
| 2479 | */ | ||
| 2480 | static char **add_unq_string_to_strings(char **strings, const char *src) | ||
| 2481 | { | ||
| 2482 | int cnt; | ||
| 2483 | const char *s; | ||
| 2484 | char *v, *dest; | ||
| 2485 | |||
| 2486 | for (cnt = 1, s = src; s && *s; s++) { | ||
| 2487 | if (*s == '\\') s++; | ||
| 2488 | cnt++; | ||
| 2489 | } | ||
| 2490 | v = dest = xmalloc(cnt); | ||
| 2491 | for (s = src; s && *s; s++, dest++) { | ||
| 2492 | if (*s == '\\') s++; | ||
| 2493 | *dest = *s; | ||
| 2494 | } | ||
| 2495 | *dest = '\0'; | ||
| 2496 | |||
| 2497 | return add_string_to_strings(strings, v); | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | /* XXX broken if the last character is '\\', check that before calling */ | ||
| 2501 | static int glob_needed(const char *s) | ||
| 2502 | { | ||
| 2503 | for (; *s; s++) { | ||
| 2504 | if (*s == '\\') | ||
| 2505 | s++; | ||
| 2506 | if (strchr("*[?", *s)) | ||
| 2507 | return 1; | ||
| 2508 | } | ||
| 2509 | return 0; | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | static int xglob(char ***pglob, const char *pattern) | ||
| 2513 | { | ||
| 2514 | if (glob_needed(pattern)) { | ||
| 2515 | glob_t globdata; | ||
| 2516 | int gr; | ||
| 2517 | |||
| 2518 | memset(&globdata, 0, sizeof(globdata)); | ||
| 2519 | gr = glob(pattern, 0, NULL, &globdata); | ||
| 2520 | debug_printf("glob returned %d\n", gr); | ||
| 2521 | if (gr == GLOB_NOSPACE) | ||
| 2522 | bb_error_msg_and_die("out of memory during glob"); | ||
| 2523 | if (gr == GLOB_NOMATCH) { | ||
| 2524 | globfree(&globdata); | ||
| 2525 | goto literal; | ||
| 2526 | } | ||
| 2527 | if (gr != 0) { /* GLOB_ABORTED ? */ | ||
| 2528 | bb_error_msg("glob(3) error %d", gr); | ||
| 2529 | } | ||
| 2530 | if (globdata.gl_pathv && globdata.gl_pathv[0]) | ||
| 2531 | *pglob = add_strings_to_strings(1, *pglob, globdata.gl_pathv); | ||
| 2532 | globfree(&globdata); | ||
| 2533 | return gr; | ||
| 2534 | } | ||
| 2535 | |||
| 2536 | literal: | ||
| 2537 | /* quote removal, or more accurately, backslash removal */ | ||
| 2538 | *pglob = add_unq_string_to_strings(*pglob, pattern); | ||
| 2539 | debug_print_strings("after xglob", *pglob); | ||
| 2540 | return 0; | ||
| 2541 | } | ||
| 2542 | |||
| 2543 | /* expand_strvec_to_strvec() takes a list of strings, expands | 2482 | /* expand_strvec_to_strvec() takes a list of strings, expands |
| 2544 | * all variable references within and returns a pointer to | 2483 | * all variable references within and returns a pointer to |
| 2545 | * a list of expanded strings, possibly with larger number | 2484 | * a list of expanded strings, possibly with larger number |
| @@ -2596,7 +2535,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2596 | o_debug_list("expand_vars_to_list[0]", output, n); | 2535 | o_debug_list("expand_vars_to_list[0]", output, n); |
| 2597 | 2536 | ||
| 2598 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { | 2537 | while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { |
| 2538 | #if ENABLE_HUSH_TICK | ||
| 2599 | o_string subst_result = NULL_O_STRING; | 2539 | o_string subst_result = NULL_O_STRING; |
| 2540 | #endif | ||
| 2600 | 2541 | ||
| 2601 | o_addQstr(output, arg, p - arg); | 2542 | o_addQstr(output, arg, p - arg); |
| 2602 | o_debug_list("expand_vars_to_list[1]", output, n); | 2543 | o_debug_list("expand_vars_to_list[1]", output, n); |
| @@ -2661,10 +2602,12 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2661 | } | 2602 | } |
| 2662 | } | 2603 | } |
| 2663 | break; | 2604 | break; |
| 2605 | #if ENABLE_HUSH_TICK | ||
| 2664 | case '`': { | 2606 | case '`': { |
| 2665 | struct in_str input; | 2607 | struct in_str input; |
| 2666 | *p = '\0'; | 2608 | *p = '\0'; |
| 2667 | arg++; | 2609 | arg++; |
| 2610 | //TODO: can we just stuff it into "output" directly? | ||
| 2668 | //bb_error_msg("SUBST '%s' first_ch %x", arg, first_ch); | 2611 | //bb_error_msg("SUBST '%s' first_ch %x", arg, first_ch); |
| 2669 | setup_string_in_str(&input, arg); | 2612 | setup_string_in_str(&input, arg); |
| 2670 | process_command_subs(&subst_result, &input, NULL); | 2613 | process_command_subs(&subst_result, &input, NULL); |
| @@ -2672,6 +2615,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2672 | val = subst_result.data; | 2615 | val = subst_result.data; |
| 2673 | goto store_val; | 2616 | goto store_val; |
| 2674 | } | 2617 | } |
| 2618 | #endif | ||
| 2675 | default: | 2619 | default: |
| 2676 | *p = '\0'; | 2620 | *p = '\0'; |
| 2677 | arg[0] = first_ch & 0x7f; | 2621 | arg[0] = first_ch & 0x7f; |
| @@ -2696,7 +2640,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
| 2696 | o_addQstr(output, val, strlen(val)); | 2640 | o_addQstr(output, val, strlen(val)); |
| 2697 | } | 2641 | } |
| 2698 | 2642 | ||
| 2643 | #if ENABLE_HUSH_TICK | ||
| 2699 | o_free(&subst_result); | 2644 | o_free(&subst_result); |
| 2645 | #endif | ||
| 2700 | arg = ++p; | 2646 | arg = ++p; |
| 2701 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ | 2647 | } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ |
| 2702 | 2648 | ||
| @@ -2731,33 +2677,87 @@ static char **expand_variables(char **argv, char or_mask) | |||
| 2731 | 2677 | ||
| 2732 | /* output.data (malloced in one block) gets returned in "list" */ | 2678 | /* output.data (malloced in one block) gets returned in "list" */ |
| 2733 | list = o_finalize_list(&output, n); | 2679 | list = o_finalize_list(&output, n); |
| 2680 | return list; | ||
| 2681 | } | ||
| 2734 | 2682 | ||
| 2735 | #ifdef DEBUG_EXPAND | 2683 | /* Remove non-backslashed backslashes and add to "strings" vector. |
| 2736 | { | 2684 | * XXX broken if the last character is '\\', check that before calling. |
| 2737 | int m = 0; | 2685 | */ |
| 2738 | while (m <= n) { | 2686 | static char **add_unq_string_to_strings(char **strings, const char *src) |
| 2739 | debug_printf_expand("list[%d]=%p '%s'\n", m, list[m], list[m]); | 2687 | { |
| 2740 | m++; | 2688 | int cnt; |
| 2689 | const char *s; | ||
| 2690 | char *v, *dest; | ||
| 2691 | |||
| 2692 | for (cnt = 1, s = src; s && *s; s++) { | ||
| 2693 | if (*s == '\\') s++; | ||
| 2694 | cnt++; | ||
| 2695 | } | ||
| 2696 | v = dest = xmalloc(cnt); | ||
| 2697 | for (s = src; s && *s; s++, dest++) { | ||
| 2698 | if (*s == '\\') s++; | ||
| 2699 | *dest = *s; | ||
| 2700 | } | ||
| 2701 | *dest = '\0'; | ||
| 2702 | |||
| 2703 | return add_string_to_strings(strings, v); | ||
| 2704 | } | ||
| 2705 | |||
| 2706 | /* XXX broken if the last character is '\\', check that before calling */ | ||
| 2707 | static int glob_needed(const char *s) | ||
| 2708 | { | ||
| 2709 | for (; *s; s++) { | ||
| 2710 | if (*s == '\\') | ||
| 2711 | s++; | ||
| 2712 | if (strchr("*[?", *s)) | ||
| 2713 | return 1; | ||
| 2714 | } | ||
| 2715 | return 0; | ||
| 2716 | } | ||
| 2717 | |||
| 2718 | static void xglob(char ***pglob, const char *pattern) | ||
| 2719 | { | ||
| 2720 | if (glob_needed(pattern)) { | ||
| 2721 | glob_t globdata; | ||
| 2722 | int gr; | ||
| 2723 | |||
| 2724 | memset(&globdata, 0, sizeof(globdata)); | ||
| 2725 | gr = glob(pattern, 0, NULL, &globdata); | ||
| 2726 | debug_printf("glob returned %d\n", gr); | ||
| 2727 | if (gr == GLOB_NOSPACE) | ||
| 2728 | bb_error_msg_and_die("out of memory during glob"); | ||
| 2729 | if (gr == GLOB_NOMATCH) { | ||
| 2730 | globfree(&globdata); | ||
| 2731 | goto literal; | ||
| 2741 | } | 2732 | } |
| 2733 | if (gr != 0) { /* GLOB_ABORTED ? */ | ||
| 2734 | bb_error_msg("glob(3) error %d on '%s'", gr, pattern); | ||
| 2735 | //TODO: testcase for bad glob pattern behavior | ||
| 2736 | } | ||
| 2737 | if (globdata.gl_pathv && globdata.gl_pathv[0]) | ||
| 2738 | *pglob = add_strings_to_strings(1, *pglob, globdata.gl_pathv); | ||
| 2739 | globfree(&globdata); | ||
| 2740 | return; | ||
| 2742 | } | 2741 | } |
| 2743 | #endif | 2742 | |
| 2744 | return list; | 2743 | literal: |
| 2744 | /* quote removal, or more accurately, backslash removal */ | ||
| 2745 | *pglob = add_unq_string_to_strings(*pglob, pattern); | ||
| 2746 | debug_print_strings("after xglob", *pglob); | ||
| 2745 | } | 2747 | } |
| 2746 | 2748 | ||
| 2749 | //LEAK is here: callers expect result to be free()able, but we | ||
| 2750 | //actually require free_strings(). free() leaks strings. | ||
| 2747 | static char **expand_strvec_to_strvec(char **argv) | 2751 | static char **expand_strvec_to_strvec(char **argv) |
| 2748 | { | 2752 | { |
| 2749 | char **exp; | 2753 | char **exp; |
| 2750 | char **res = NULL; | 2754 | char **res = xzalloc(sizeof(res[0])); |
| 2751 | 2755 | ||
| 2752 | debug_print_strings("expand_strvec_to_strvec: pre expand", argv); | 2756 | debug_print_strings("expand_strvec_to_strvec: pre expand", argv); |
| 2753 | exp = argv = expand_variables(argv, 0); | 2757 | exp = argv = expand_variables(argv, 0); |
| 2754 | debug_print_strings("expand_strvec_to_strvec: post expand", argv); | 2758 | debug_print_strings("expand_strvec_to_strvec: post expand", argv); |
| 2755 | while (*argv) { | 2759 | while (*argv) { |
| 2756 | int r = xglob(&res, *argv); | 2760 | xglob(&res, *argv++); |
| 2757 | if (r) | ||
| 2758 | bb_error_msg("xglob returned %d on '%s'", r, *argv); | ||
| 2759 | //TODO: testcase for bad glob pattern behavior | ||
| 2760 | argv++; | ||
| 2761 | } | 2761 | } |
| 2762 | free(exp); | 2762 | free(exp); |
| 2763 | debug_print_strings("expand_strvec_to_strvec: res", res); | 2763 | debug_print_strings("expand_strvec_to_strvec: res", res); |
