Attachment "dup-2.patch" to
ticket [2827015fff]
added by
lars_h
2009-07-29 21:25:21.
Index: tests/exec.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/exec.test,v
retrieving revision 1.33
diff -u -r1.33 exec.test
--- tests/exec.test 8 May 2009 08:13:31 -0000 1.33
+++ tests/exec.test 29 Jul 2009 13:59:12 -0000
@@ -605,6 +605,26 @@
exec [interpreter] "$path(sh)" -c "\"$path(echo)\" foo bar 1>&2" 2>@1
} {foo bar}
+test exec-15.8 {Bug 2827015: swapping standard error and standard out}\
+ -constraints {exec stdio} -setup {
+ set path(script) [makeFile {
+ puts stdout OUT1
+ puts stderr ERR1
+ puts stdout OUT2
+ puts stderr ERR2
+ } script]
+ set path(script2) [makeFile {
+ exec [info nameofexecutable] [lindex $argv 0] >@stderr 2>@stdout
+ puts separator
+ } script2]
+} -body {
+ exec [interpreter] $path(script2) $path(script)
+} -returnCodes error -result "ERR1\nERR2\nseparator\nOUT1\nOUT2" -cleanup {
+ removeFile $path(script)
+ removeFile $path(script2)
+}
+
+
test exec-16.1 {flush output before exec} {exec} {
set f [open $path(gorp.file) w]
puts $f "First line"
Index: unix/tclUnixPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPipe.c,v
retrieving revision 1.48
diff -u -r1.48 tclUnixPipe.c
--- unix/tclUnixPipe.c 9 Jan 2009 11:21:46 -0000 1.48
+++ unix/tclUnixPipe.c 29 Jul 2009 13:59:13 -0000
@@ -451,31 +451,67 @@
pid = fork();
if (pid == 0) {
int joinThisError = errorFile && (errorFile == outputFile);
+ int fd0,fd1,fd2;
+ int closeOut=0,closeErr=0;
fd = GetFd(errPipeOut);
/*
* Set up stdio file handles for the child process.
*/
-
- if (!SetupStdFile(inputFile, TCL_STDIN)
- || !SetupStdFile(outputFile, TCL_STDOUT)
- || (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
- || (joinThisError &&
- ((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
- sprintf(errSpace,
- "%dforked process couldn't set up input/output: ", errno);
- (void)write(fd, errSpace, (size_t) strlen(errSpace));
- _exit(1);
- }
+ fd0 = GetFd(inputFile);
+ fd1 = GetFd(outputFile);
+ fd2 = GetFd(errorFile);
+
+ if (fd1 == 0) {
+ outputFile = MakeFile(dup(0));
+ closeOut = 1;
+ }
+ if (fd2 == 0) {
+ errorFile = MakeFile(dup(0));
+ closeErr = 1;
+ }
+ if (!SetupStdFile(inputFile, TCL_STDIN)) {
+ sprintf(errSpace,
+ "%dforked process couldn't set up input: ", errno);
+ goto child_error;
+ }
+
+
+ if (fd2 == 1) {
+ errorFile = MakeFile(dup(1));
+ closeErr = 1;
+ }
+ if (!SetupStdFile(outputFile, TCL_STDOUT)) {
+ sprintf(errSpace,
+ "%dforked process couldn't set up output: ", errno);
+ goto child_error;
+ }
+
+ if ( !joinThisError ? !SetupStdFile(errorFile, TCL_STDERR)
+ : (dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)
+ ) {
+ sprintf(errSpace,
+ "%dforked process couldn't set up stderr: ", errno);
+ goto child_error;
+ }
+
+ if (closeOut) close(GetFd(outputFile));
+ if (closeErr) close(GetFd(errorFile));
/*
+ * Anyone know what this comment means:
* Close the input side of the error pipe.
*/
RestoreSignals();
execvp(newArgv[0], newArgv); /* INTL: Native. */
+
+ /*
+ * If we get here, then execvp failed.
+ */
sprintf(errSpace, "%dcouldn't execute \"%.150s\": ", errno, argv[0]);
+ child_error:
(void)write(fd, errSpace, (size_t) strlen(errSpace));
_exit(1);
}