diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-10 16:19:39 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-06-10 16:19:39 +0000 |
| commit | 76d50418b37e59c4b474137ffa2eba4d3f7dbbb8 (patch) | |
| tree | 111c924c34b6b81669ef8fc609584ea6506dcb67 /shell | |
| parent | 3fe4f986a055d0bc942dcda0c2fea3ef68e341d7 (diff) | |
| download | busybox-w32-76d50418b37e59c4b474137ffa2eba4d3f7dbbb8.tar.gz busybox-w32-76d50418b37e59c4b474137ffa2eba4d3f7dbbb8.tar.bz2 busybox-w32-76d50418b37e59c4b474137ffa2eba4d3f7dbbb8.zip | |
hush: fix a memory leak in NOMMU case
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/shell/hush.c b/shell/hush.c index b80468f58..d7b9c39ec 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -516,8 +516,12 @@ static int free_pipe(struct pipe *pi, int indent); | |||
| 516 | /* really run the final data structures: */ | 516 | /* really run the final data structures: */ |
| 517 | static int setup_redirects(struct child_prog *prog, int squirrel[]); | 517 | static int setup_redirects(struct child_prog *prog, int squirrel[]); |
| 518 | static int run_list(struct pipe *pi); | 518 | static int run_list(struct pipe *pi); |
| 519 | static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; | 519 | #if BB_MMU |
| 520 | static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; | 520 | #define pseudo_exec_argv(ptrs2free, argv) pseudo_exec_argv(argv) |
| 521 | #define pseudo_exec(ptrs2free, child) pseudo_exec(child) | ||
| 522 | #endif | ||
| 523 | static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN; | ||
| 524 | static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN; | ||
| 521 | static int run_pipe(struct pipe *pi); | 525 | static int run_pipe(struct pipe *pi); |
| 522 | /* extended glob support: */ | 526 | /* extended glob support: */ |
| 523 | static char **globhack(const char *src, char **strings); | 527 | static char **globhack(const char *src, char **strings); |
| @@ -619,6 +623,18 @@ static void free_strings(char **strings) | |||
| 619 | } | 623 | } |
| 620 | 624 | ||
| 621 | 625 | ||
| 626 | #if !BB_MMU | ||
| 627 | #define EXTRA_PTRS 5 /* 1 for NULL, 1 for args, 3 for paranoid reasons */ | ||
| 628 | static char **alloc_ptrs(char **argv) | ||
| 629 | { | ||
| 630 | char **v = argv; | ||
| 631 | while (*v) | ||
| 632 | v++; | ||
| 633 | return xzalloc((v - argv + EXTRA_PTRS) * sizeof(v[0])); | ||
| 634 | } | ||
| 635 | #endif | ||
| 636 | |||
| 637 | |||
| 622 | /* Function prototypes for builtins */ | 638 | /* Function prototypes for builtins */ |
| 623 | static int builtin_cd(char **argv); | 639 | static int builtin_cd(char **argv); |
| 624 | static int builtin_echo(char **argv); | 640 | static int builtin_echo(char **argv); |
| @@ -891,9 +907,14 @@ static int builtin_exec(char **argv) | |||
| 891 | { | 907 | { |
| 892 | if (argv[1] == NULL) | 908 | if (argv[1] == NULL) |
| 893 | return EXIT_SUCCESS; /* bash does this */ | 909 | return EXIT_SUCCESS; /* bash does this */ |
| 910 | { | ||
| 911 | #if !BB_MMU | ||
| 912 | char **ptrs2free = alloc_ptrs(argv); | ||
| 913 | #endif | ||
| 894 | // FIXME: if exec fails, bash does NOT exit! We do... | 914 | // FIXME: if exec fails, bash does NOT exit! We do... |
| 895 | pseudo_exec_argv(argv + 1); | 915 | pseudo_exec_argv(ptrs2free, argv + 1); |
| 896 | /* never returns */ | 916 | /* never returns */ |
| 917 | } | ||
| 897 | } | 918 | } |
| 898 | 919 | ||
| 899 | /* built-in 'exit' handler */ | 920 | /* built-in 'exit' handler */ |
| @@ -1421,7 +1442,7 @@ static void restore_redirects(int squirrel[]) | |||
| 1421 | * XXX no exit() here. If you don't exec, use _exit instead. | 1442 | * XXX no exit() here. If you don't exec, use _exit instead. |
| 1422 | * The at_exit handlers apparently confuse the calling process, | 1443 | * The at_exit handlers apparently confuse the calling process, |
| 1423 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ | 1444 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ |
| 1424 | static void pseudo_exec_argv(char **argv) | 1445 | static void pseudo_exec_argv(char **ptrs2free, char **argv) |
| 1425 | { | 1446 | { |
| 1426 | int i, rcode; | 1447 | int i, rcode; |
| 1427 | char *p; | 1448 | char *p; |
| @@ -1430,8 +1451,10 @@ static void pseudo_exec_argv(char **argv) | |||
| 1430 | for (i = 0; is_assignment(argv[i]); i++) { | 1451 | for (i = 0; is_assignment(argv[i]); i++) { |
| 1431 | debug_printf_exec("pid %d environment modification: %s\n", | 1452 | debug_printf_exec("pid %d environment modification: %s\n", |
| 1432 | getpid(), argv[i]); | 1453 | getpid(), argv[i]); |
| 1433 | // FIXME: vfork case?? | ||
| 1434 | p = expand_string_to_string(argv[i]); | 1454 | p = expand_string_to_string(argv[i]); |
| 1455 | #if !BB_MMU | ||
| 1456 | *ptrs2free++ = p; | ||
| 1457 | #endif | ||
| 1435 | putenv(p); | 1458 | putenv(p); |
| 1436 | } | 1459 | } |
| 1437 | argv += i; | 1460 | argv += i; |
| @@ -1442,6 +1465,9 @@ static void pseudo_exec_argv(char **argv) | |||
| 1442 | _exit(EXIT_SUCCESS); | 1465 | _exit(EXIT_SUCCESS); |
| 1443 | 1466 | ||
| 1444 | argv = expand_strvec_to_strvec(argv); | 1467 | argv = expand_strvec_to_strvec(argv); |
| 1468 | #if !BB_MMU | ||
| 1469 | *ptrs2free++ = (char*) argv; | ||
| 1470 | #endif | ||
| 1445 | 1471 | ||
| 1446 | /* | 1472 | /* |
| 1447 | * Check if the command matches any of the builtins. | 1473 | * Check if the command matches any of the builtins. |
| @@ -1485,13 +1511,13 @@ static void pseudo_exec_argv(char **argv) | |||
| 1485 | 1511 | ||
| 1486 | /* Called after [v]fork() in run_pipe() | 1512 | /* Called after [v]fork() in run_pipe() |
| 1487 | */ | 1513 | */ |
| 1488 | static void pseudo_exec(struct child_prog *child) | 1514 | static void pseudo_exec(char **ptrs2free, struct child_prog *child) |
| 1489 | { | 1515 | { |
| 1490 | // FIXME: buggy wrt NOMMU! Must not modify any global data | 1516 | // FIXME: buggy wrt NOMMU! Must not modify any global data |
| 1491 | // until it does exec/_exit, but currently it does | 1517 | // until it does exec/_exit, but currently it does |
| 1492 | // (puts malloc'ed stuff into environment) | 1518 | // (puts malloc'ed stuff into environment) |
| 1493 | if (child->argv) | 1519 | if (child->argv) |
| 1494 | pseudo_exec_argv(child->argv); | 1520 | pseudo_exec_argv(ptrs2free, child->argv); |
| 1495 | 1521 | ||
| 1496 | if (child->group) { | 1522 | if (child->group) { |
| 1497 | #if !BB_MMU | 1523 | #if !BB_MMU |
| @@ -1880,10 +1906,16 @@ static int run_pipe(struct pipe *pi) | |||
| 1880 | nextin = 0; | 1906 | nextin = 0; |
| 1881 | 1907 | ||
| 1882 | for (i = 0; i < pi->num_progs; i++) { | 1908 | for (i = 0; i < pi->num_progs; i++) { |
| 1909 | #if !BB_MMU | ||
| 1910 | char **ptrs2free = NULL; | ||
| 1911 | #endif | ||
| 1883 | child = &(pi->progs[i]); | 1912 | child = &(pi->progs[i]); |
| 1884 | if (child->argv) | 1913 | if (child->argv) { |
| 1885 | debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); | 1914 | debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); |
| 1886 | else | 1915 | #if !BB_MMU |
| 1916 | ptrs2free = alloc_ptrs(child->argv); | ||
| 1917 | #endif | ||
| 1918 | } else | ||
| 1887 | debug_printf_exec(": pipe member with no argv\n"); | 1919 | debug_printf_exec(": pipe member with no argv\n"); |
| 1888 | 1920 | ||
| 1889 | /* pipes are inserted between pairs of commands */ | 1921 | /* pipes are inserted between pairs of commands */ |
| @@ -1925,9 +1957,11 @@ static int run_pipe(struct pipe *pi) | |||
| 1925 | set_jobctrl_sighandler(SIG_DFL); | 1957 | set_jobctrl_sighandler(SIG_DFL); |
| 1926 | set_misc_sighandler(SIG_DFL); | 1958 | set_misc_sighandler(SIG_DFL); |
| 1927 | signal(SIGCHLD, SIG_DFL); | 1959 | signal(SIGCHLD, SIG_DFL); |
| 1928 | pseudo_exec(child); /* does not return */ | 1960 | pseudo_exec(ptrs2free, child); /* does not return */ |
| 1929 | } | 1961 | } |
| 1930 | 1962 | #if !BB_MMU | |
| 1963 | free_strings(ptrs2free); | ||
| 1964 | #endif | ||
| 1931 | if (child->pid < 0) { /* [v]fork failed */ | 1965 | if (child->pid < 0) { /* [v]fork failed */ |
| 1932 | /* Clearly indicate, was it fork or vfork */ | 1966 | /* Clearly indicate, was it fork or vfork */ |
| 1933 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); | 1967 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); |
