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); |