Skip to content

Commit 790be6d

Browse files
jasonbuxiaoxiang781216
authored andcommitted
nshlib/nsh_parse: use sh -c replace pthread detach when nsh background.
pthread & detach will still quit when parent task exit, cause nsh_parse clone args leak. nsh should use task instead of thread this case can reproduce the memory leak. int main(int argc, FAR char *argv[]) { printf("Hello, World!!\n"); system("sleep 1 &"); return 0; } Signed-off-by: buxiasen <[email protected]>
1 parent ec458f0 commit 790be6d

File tree

1 file changed

+52
-257
lines changed

1 file changed

+52
-257
lines changed

nshlib/nsh_parse.c

Lines changed: 52 additions & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
#include <string.h>
3131
#include <errno.h>
3232
#include <debug.h>
33-
#include <pthread.h>
3433
#include <sched.h>
3534
#include <unistd.h>
3635

@@ -126,19 +125,6 @@
126125
* Private Types
127126
****************************************************************************/
128127

129-
/* These structure describes the parsed command line */
130-
131-
#ifndef CONFIG_NSH_DISABLEBG
132-
struct cmdarg_s
133-
{
134-
FAR struct nsh_vtbl_s *vtbl; /* For front-end interaction */
135-
int fd_in; /* FD for output redirection */
136-
int fd_out; /* FD for output redirection */
137-
int argc; /* Number of arguments in argv */
138-
FAR char *argv[MAX_ARGV_ENTRIES]; /* Argument list */
139-
};
140-
#endif
141-
142128
/* This structure describes the allocation list */
143129

144130
#ifdef HAVE_MEMLIST
@@ -174,13 +160,6 @@ static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl,
174160
FAR struct nsh_alist_s *alist);
175161
#endif
176162

177-
#ifndef CONFIG_NSH_DISABLEBG
178-
static void nsh_releaseargs(struct cmdarg_s *arg);
179-
static pthread_addr_t nsh_child(pthread_addr_t arg);
180-
static struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
181-
int fd_in, int fd_out, int argc, FAR char *argv[]);
182-
#endif
183-
184163
static int nsh_saveresult(FAR struct nsh_vtbl_s *vtbl, bool result);
185164
static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
186165
int argc, FAR char *argv[], FAR const char *redirfile_in,
@@ -443,107 +422,6 @@ static void nsh_alist_free(FAR struct nsh_vtbl_s *vtbl,
443422
}
444423
#endif
445424

446-
/****************************************************************************
447-
* Name: nsh_releaseargs
448-
****************************************************************************/
449-
450-
#ifndef CONFIG_NSH_DISABLEBG
451-
static void nsh_releaseargs(struct cmdarg_s *arg)
452-
{
453-
FAR struct nsh_vtbl_s *vtbl = arg->vtbl;
454-
int i;
455-
456-
/* If the output was redirected, then file descriptor should
457-
* be closed. The created task has its one, independent copy of
458-
* the file descriptor
459-
*/
460-
461-
if (vtbl->np.np_redir_out)
462-
{
463-
close(arg->fd_out);
464-
}
465-
466-
/* Same for the input */
467-
468-
if (vtbl->np.np_redir_in)
469-
{
470-
close(arg->fd_in);
471-
}
472-
473-
/* Released the cloned vtbl instance */
474-
475-
nsh_release(vtbl);
476-
477-
/* Release the cloned args */
478-
479-
for (i = 0; i < arg->argc; i++)
480-
{
481-
free(arg->argv[i]);
482-
}
483-
484-
free(arg);
485-
}
486-
#endif
487-
488-
/****************************************************************************
489-
* Name: nsh_child
490-
****************************************************************************/
491-
492-
#ifndef CONFIG_NSH_DISABLEBG
493-
static pthread_addr_t nsh_child(pthread_addr_t arg)
494-
{
495-
struct cmdarg_s *carg = (struct cmdarg_s *)arg;
496-
int ret;
497-
498-
_info("BG %s\n", carg->argv[0]);
499-
500-
/* Execute the specified command on the child thread */
501-
502-
ret = nsh_command(carg->vtbl, carg->argc, carg->argv);
503-
504-
/* Released the cloned arguments */
505-
506-
_info("BG %s complete\n", carg->argv[0]);
507-
nsh_releaseargs(carg);
508-
509-
/* Detach from the pthread since we are not going to join with it.
510-
* Otherwise, we would have a memory leak.
511-
*/
512-
513-
pthread_detach(pthread_self());
514-
return (pthread_addr_t)((uintptr_t)ret);
515-
}
516-
#endif
517-
518-
/****************************************************************************
519-
* Name: nsh_cloneargs
520-
****************************************************************************/
521-
522-
#ifndef CONFIG_NSH_DISABLEBG
523-
static struct cmdarg_s *nsh_cloneargs(FAR struct nsh_vtbl_s *vtbl,
524-
int fd_in, int fd_out, int argc,
525-
FAR char *argv[])
526-
{
527-
struct cmdarg_s *ret = (struct cmdarg_s *)zalloc(sizeof(struct cmdarg_s));
528-
int i;
529-
530-
if (ret)
531-
{
532-
ret->vtbl = vtbl;
533-
ret->fd_in = fd_in;
534-
ret->fd_out = fd_out;
535-
ret->argc = argc;
536-
537-
for (i = 0; i < argc; i++)
538-
{
539-
ret->argv[i] = strdup(argv[i]);
540-
}
541-
}
542-
543-
return ret;
544-
}
545-
#endif
546-
547425
/****************************************************************************
548426
* Name: nsh_saveresult
549427
****************************************************************************/
@@ -616,8 +494,6 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
616494
FAR const char *redirfile_in,
617495
FAR const char *redirfile_out, int oflags)
618496
{
619-
int fd_in = STDIN_FILENO;
620-
int fd_out = STDOUT_FILENO;
621497
int ret;
622498

623499
/* DO NOT CHANGE THE ORDERING OF THE FOLLOWING STEPS
@@ -713,42 +589,6 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
713589

714590
#endif
715591

716-
/* Redirected output? */
717-
718-
if (vtbl->np.np_redir_out)
719-
{
720-
/* Open the redirection file. This file will eventually
721-
* be closed by a call to either nsh_release (if the command
722-
* is executed in the background) or by nsh_undirect if the
723-
* command is executed in the foreground.
724-
*/
725-
726-
fd_out = open(redirfile_out, oflags, 0666);
727-
if (fd_out < 0)
728-
{
729-
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
730-
goto errout;
731-
}
732-
}
733-
734-
/* Redirected input? */
735-
736-
if (vtbl->np.np_redir_in)
737-
{
738-
/* Open the redirection file. This file will eventually
739-
* be closed by a call to either nsh_release (if the command
740-
* is executed in the background) or by nsh_undirect if the
741-
* command is executed in the foreground.
742-
*/
743-
744-
fd_in = open(redirfile_in, O_RDONLY, 0);
745-
if (fd_in < 0)
746-
{
747-
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
748-
goto errout;
749-
}
750-
}
751-
752592
/* Handle the case where the command is executed in background.
753593
* However is app is to be started as built-in new process will
754594
* be created anyway, so skip this step.
@@ -757,108 +597,79 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
757597
#ifndef CONFIG_NSH_DISABLEBG
758598
if (vtbl->np.np_bg)
759599
{
760-
struct sched_param param;
761-
struct nsh_vtbl_s *bkgvtbl;
762-
struct cmdarg_s *args;
763-
pthread_attr_t attr;
764-
pthread_t thread;
765-
766-
/* Get a cloned copy of the vtbl with reference count=1.
767-
* after the command has been processed, the nsh_release() call
768-
* at the end of nsh_child() will destroy the clone.
769-
*/
600+
FAR char *sh_argv[4];
601+
FAR char *sh_cmd = "sh";
602+
int i;
770603

771-
bkgvtbl = nsh_clone(vtbl);
772-
if (!bkgvtbl)
773-
{
774-
goto errout_with_redirect;
775-
}
604+
DEBUGASSERT(strncmp(argv[0], sh_cmd, 3) != 0);
776605

777-
/* Create a container for the command arguments */
778-
779-
args = nsh_cloneargs(bkgvtbl, fd_in, fd_out, argc, argv);
780-
if (!args)
606+
sh_argv[0] = sh_cmd;
607+
sh_argv[1] = "-c";
608+
for (i = 0; i < argc - 1; i++)
781609
{
782-
nsh_release(bkgvtbl);
783-
goto errout_with_redirect;
784-
}
610+
FAR char *p_arg = argv[i];
611+
size_t len = strlen(p_arg);
785612

786-
/* Handle redirection of output via a file descriptor */
613+
/* Restore from split args to concat args. */
787614

788-
if (vtbl->np.np_redir_out || vtbl->np.np_redir_in)
789-
{
790-
nsh_redirect(bkgvtbl, fd_in, fd_out, NULL);
615+
DEBUGASSERT(&p_arg[len + 1] == argv[i + 1]);
616+
p_arg[len] = ' ';
791617
}
792618

793-
/* Get the execution priority of this task */
619+
sh_argv[2] = argv[0];
620+
sh_argv[3] = NULL;
794621

795-
ret = sched_getparam(0, &param);
796-
if (ret != 0)
797-
{
798-
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "sched_getparm",
799-
NSH_ERRNO);
622+
/* np.np_bg still there, try use nsh_builtin or nsh_fileapp to
623+
* dispatch the backgroud by sh -c ""
624+
*/
800625

801-
/* NOTE: bkgvtbl is released in nsh_relaseargs() */
626+
return nsh_execute(vtbl, 4, sh_argv,
627+
redirfile_in, redirfile_out, oflags);
628+
}
629+
else
630+
#endif
631+
{
632+
uint8_t save[SAVE_SIZE];
802633

803-
nsh_releaseargs(args);
804-
goto errout;
805-
}
634+
int fd_in = STDIN_FILENO;
635+
int fd_out = STDOUT_FILENO;
806636

807-
/* Determine the priority to execute the command */
637+
/* Redirected output? */
808638

809-
if (vtbl->np.np_nice != 0)
639+
if (vtbl->np.np_redir_out)
810640
{
811-
int priority = param.sched_priority - vtbl->np.np_nice;
812-
if (vtbl->np.np_nice < 0)
813-
{
814-
int max_priority = sched_get_priority_max(SCHED_NSH);
815-
if (priority > max_priority)
816-
{
817-
priority = max_priority;
818-
}
819-
}
820-
else
641+
/* Open the redirection file. This file will eventually
642+
* be closed by a call to either nsh_release (if the command
643+
* is executed in the background) or by nsh_undirect if the
644+
* command is executed in the foreground.
645+
*/
646+
647+
fd_out = open(redirfile_out, oflags, 0666);
648+
if (fd_out < 0)
821649
{
822-
int min_priority = sched_get_priority_min(SCHED_NSH);
823-
if (priority < min_priority)
824-
{
825-
priority = min_priority;
826-
}
650+
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
651+
return nsh_saveresult(vtbl, true);
827652
}
828-
829-
param.sched_priority = priority;
830653
}
831654

832-
/* Set up the thread attributes */
655+
/* Redirected input? */
833656

834-
pthread_attr_init(&attr);
835-
pthread_attr_setschedpolicy(&attr, SCHED_NSH);
836-
pthread_attr_setschedparam(&attr, &param);
837-
838-
/* Execute the command as a separate thread at the appropriate
839-
* priority.
840-
*/
841-
842-
ret = pthread_create(&thread, &attr, nsh_child, (pthread_addr_t)args);
843-
if (ret != 0)
657+
if (vtbl->np.np_redir_in)
844658
{
845-
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "pthread_create",
846-
NSH_ERRNO_OF(ret));
847-
848-
/* NOTE: bkgvtbl is released in nsh_relaseargs() */
659+
/* Open the redirection file. This file will eventually
660+
* be closed by a call to either nsh_release (if the command
661+
* is executed in the background) or by nsh_undirect if the
662+
* command is executed in the foreground.
663+
*/
849664

850-
nsh_releaseargs(args);
851-
goto errout;
665+
fd_in = open(redirfile_in, O_RDONLY, 0);
666+
if (fd_in < 0)
667+
{
668+
nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
669+
return nsh_saveresult(vtbl, true);
670+
}
852671
}
853672

854-
nsh_output(vtbl, "%s [%d:%d]\n", argv[0], thread,
855-
param.sched_priority);
856-
}
857-
else
858-
#endif
859-
{
860-
uint8_t save[SAVE_SIZE];
861-
862673
/* Handle redirection of stdin/stdout file descriptor */
863674

864675
if (vtbl->np.np_redir_out || vtbl->np.np_redir_in)
@@ -890,7 +701,7 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
890701

891702
if (ret < 0)
892703
{
893-
goto errout;
704+
return nsh_saveresult(vtbl, true);
894705
}
895706
}
896707

@@ -899,22 +710,6 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl,
899710
*/
900711

901712
return nsh_saveresult(vtbl, false);
902-
903-
#ifndef CONFIG_NSH_DISABLEBG
904-
errout_with_redirect:
905-
if (vtbl->np.np_redir_out)
906-
{
907-
close(fd_out);
908-
}
909-
910-
if (vtbl->np.np_redir_in)
911-
{
912-
close(fd_in);
913-
}
914-
#endif
915-
916-
errout:
917-
return nsh_saveresult(vtbl, true);
918713
}
919714

920715
/****************************************************************************

0 commit comments

Comments
 (0)