1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #ifndef _WIN32
23 
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/wait.h>
27 #include <sys/types.h>
28 
29 #ifdef __APPLE__
30 #include <TargetConditionals.h>
31 #endif
32 
33 #include "uv.h"
34 #include "task.h"
35 
alloc_buffer(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)36 void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf)
37 {
38   static char buffer[1024];
39 
40   buf->base = buffer;
41   buf->len = sizeof(buffer);
42 }
43 
read_stdin(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)44 void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf)
45 {
46   if (nread < 0) {
47     uv_close((uv_handle_t*)stream, NULL);
48     return;
49   }
50 }
51 
52 /*
53  * This test is a reproduction of joyent/libuv#1419 .
54  */
TEST_IMPL(pipe_close_stdout_read_stdin)55 TEST_IMPL(pipe_close_stdout_read_stdin) {
56   int r = -1;
57   int pid;
58   int fd[2];
59   int status;
60   char buf;
61   uv_pipe_t stdin_pipe;
62 
63   r = pipe(fd);
64   ASSERT_OK(r);
65 
66 #if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
67   pid = -1;
68 #else
69   pid = fork();
70 #endif
71 
72   if (pid == 0) {
73     /*
74      * Make the read side of the pipe our stdin.
75      * The write side will be closed by the parent process.
76     */
77     close(fd[1]);
78     /* block until write end of pipe is closed */
79     r = read(fd[0], &buf, 1);
80     ASSERT(-1 <= r && r <= 1);
81     close(0);
82     r = dup(fd[0]);
83     ASSERT_NE(r, -1);
84 
85     /* Create a stream that reads from the pipe. */
86     r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
87     ASSERT_OK(r);
88 
89     r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0);
90     ASSERT_OK(r);
91 
92     r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin);
93     ASSERT_OK(r);
94 
95     /*
96      * Because the other end of the pipe was closed, there should
97      * be no event left to process after one run of the event loop.
98      * Otherwise, it means that events were not processed correctly.
99      */
100     ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_NOWAIT));
101   } else {
102     /*
103      * Close both ends of the pipe so that the child
104      * get a POLLHUP event when it tries to read from
105      * the other end.
106      */
107      close(fd[1]);
108      close(fd[0]);
109 
110     waitpid(pid, &status, 0);
111     ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
112   }
113 
114   MAKE_VALGRIND_HAPPY(uv_default_loop());
115   return 0;
116 }
117 
118 #else
119 
120 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
121 
122 #endif /* ifndef _WIN32 */
123