Jim Tcl
Check-in [fc4c80e31e]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:exec: Better adhere to possible vfork restrictions

Avoid modification of any variables on the parents stack. Avoid use of stdio in the event that execve fails.

Signed-off-by: Steve Bennett <steveb@workware.net.au>

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fc4c80e31e877da19bff296657f7f47796a582cb
User & Date: steveb@workware.net.au 2018-07-08 11:48:03
Original User & Date: steveb@workware.net.au 2018-07-08 11:48:04
Context
2018-07-08
11:48
foreach: Avoid memory leak in case of error

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 569b3d59ce user: steveb@workware.net.au tags: trunk

11:48
exec: Better adhere to possible vfork restrictions

Avoid modification of any variables on the parents stack. Avoid use of stdio in the event that execve fails.

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: fc4c80e31e user: steveb@workware.net.au tags: trunk

11:47
remove some unused variable assignments

Signed-off-by: Steve Bennett <steveb@workware.net.au> check-in: 6220fc5fc0 user: steveb@workware.net.au tags: trunk

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to jim-exec.c.

720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
...
839
840
841
842
843
844
845

846
847
848
849
850
851
852
....
1005
1006
1007
1008
1009
1010
1011

1012
1013
1014
1015
1016
1017
1018
....
1019
1020
1021
1022
1023
1024
1025


1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045


1046



1047





1048

1049
1050








1051



1052
1053
1054
1055
1056
1057
1058

1059



1060
1061
1062
1063
1064
1065
1066
                                 * -1 means use stdout. */
    int pipeIds[2];           /* File ids for pipe that's being created. */
    int firstArg, lastArg;      /* Indexes of first and last arguments in
                                 * current command. */
    int lastBar;
    int i;
    pidtype pid;
    char **save_environ;
    struct WaitInfoTable *table = Jim_CmdPrivData(interp);

    /* Holds the args which will be used to exec */
    char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
    int arg_count = 0;

    if (inPipePtr != NULL) {
................................................................................
badargs:
        Jim_Free(arg_array);
        return -1;
    }

    /* Must do this before vfork(), so do it now */
    save_environ = JimSaveEnv(JimBuildEnv(interp));


    /*
     * Set up the redirected input source for the pipeline, if
     * so requested.
     */
    if (input != NULL) {
        if (inputFile == FILE_TEXT) {
................................................................................
            goto error;
        }

        /* Replace | with NULL for execv() */
        arg_array[lastArg] = NULL;
        if (lastArg == arg_count) {
            outputId = lastOutputId;

        }
        else {
            if (pipe(pipeIds) != 0) {
                Jim_SetResultErrno(interp, "couldn't create pipe");
                goto error;
            }
            outputId = pipeIds[1];
................................................................................
        }

        /* Need to do this before vfork() */
        if (pipe_dup_err) {
            errorId = outputId;
        }



        /* Now fork the child */

#ifdef __MINGW32__
        pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
        if (pid == JIM_BAD_PID) {
            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
            goto error;
        }
#else
        /*
         * Make a new process and enter it into the table if the fork
         * is successful.
         */
        pid = vfork();
        if (pid < 0) {
            Jim_SetResultErrno(interp, "couldn't fork child process");
            goto error;
        }
        if (pid == 0) {
            /* Child */


            if (inputId != -1) dup2(inputId, fileno(stdin));



            if (outputId != -1) dup2(outputId, fileno(stdout));





            if (errorId != -1) dup2(errorId, fileno(stderr));


            for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {








                close(i);



            }

            /* Restore SIGPIPE behaviour */
            (void)signal(SIGPIPE, SIG_DFL);

            execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron());


            fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]);



#ifdef JIM_MAINTAINER
            {
                /* Keep valgrind happy */
                static char *const false_argv[2] = {"false", NULL};
                execvp(false_argv[0],false_argv);
            }
#endif







|







 







>







 







>







 







>
>



|






|









>
>
|
>
>
>
|
>
>
>
>
>
|
>
|
<
>
>
>
>
>
>
>
>
|
>
>
>





|

>
|
>
>
>







720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
....
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
....
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064

1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
                                 * -1 means use stdout. */
    int pipeIds[2];           /* File ids for pipe that's being created. */
    int firstArg, lastArg;      /* Indexes of first and last arguments in
                                 * current command. */
    int lastBar;
    int i;
    pidtype pid;
    char **save_environ, **child_environ;
    struct WaitInfoTable *table = Jim_CmdPrivData(interp);

    /* Holds the args which will be used to exec */
    char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
    int arg_count = 0;

    if (inPipePtr != NULL) {
................................................................................
badargs:
        Jim_Free(arg_array);
        return -1;
    }

    /* Must do this before vfork(), so do it now */
    save_environ = JimSaveEnv(JimBuildEnv(interp));
    child_environ = Jim_GetEnviron();

    /*
     * Set up the redirected input source for the pipeline, if
     * so requested.
     */
    if (input != NULL) {
        if (inputFile == FILE_TEXT) {
................................................................................
            goto error;
        }

        /* Replace | with NULL for execv() */
        arg_array[lastArg] = NULL;
        if (lastArg == arg_count) {
            outputId = lastOutputId;
            lastOutputId = -1;
        }
        else {
            if (pipe(pipeIds) != 0) {
                Jim_SetResultErrno(interp, "couldn't create pipe");
                goto error;
            }
            outputId = pipeIds[1];
................................................................................
        }

        /* Need to do this before vfork() */
        if (pipe_dup_err) {
            errorId = outputId;
        }

        i = strlen(arg_array[firstArg]);

        /* Now fork the child */

#ifdef __MINGW32__
        pid = JimStartWinProcess(interp, &arg_array[firstArg], child_environ, inputId, outputId, errorId);
        if (pid == JIM_BAD_PID) {
            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
            goto error;
        }
#else
        /*
         * Make a new process and enter it into the table if the vfork
         * is successful.
         */
        pid = vfork();
        if (pid < 0) {
            Jim_SetResultErrno(interp, "couldn't fork child process");
            goto error;
        }
        if (pid == 0) {
            /* Child */
            /* Set up stdin, stdout, stderr */
            if (inputId != -1) {
                dup2(inputId, fileno(stdin));
                close(inputId);
            }
            if (outputId != -1) {
                dup2(outputId, fileno(stdout));
                if (outputId != errorId) {
                    close(outputId);
                }
            }
            if (errorId != -1) {
                dup2(errorId, fileno(stderr));
                close(errorId);
            }

            /* Close parent-only file descriptors */
            if (outPipePtr) {
                close(*outPipePtr);
            }
            if (errFilePtr) {
                close(*errFilePtr);
            }
            if (pipeIds[0] != -1) {
                close(pipeIds[0]);
            }
            if (lastOutputId != -1) {
                close(lastOutputId);
            }

            /* Restore SIGPIPE behaviour */
            (void)signal(SIGPIPE, SIG_DFL);

            execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);

            if (write(fileno(stderr), "couldn't exec \"", 15) &&
                write(fileno(stderr), arg_array[firstArg], i) &&
                write(fileno(stderr), "\"\n", 2)) {
                /* nothing */
            }
#ifdef JIM_MAINTAINER
            {
                /* Keep valgrind happy */
                static char *const false_argv[2] = {"false", NULL};
                execvp(false_argv[0],false_argv);
            }
#endif