• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/base/subprocess.h"
18 
19 #include <thread>
20 
21 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
22 #include <Windows.h>
23 #else
24 #include <signal.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #endif
28 
29 #include "perfetto/base/time.h"
30 #include "perfetto/ext/base/file_utils.h"
31 #include "perfetto/ext/base/pipe.h"
32 #include "perfetto/ext/base/temp_file.h"
33 #include "test/gtest_and_gmock.h"
34 
35 namespace perfetto {
36 namespace base {
37 namespace {
38 
GetOutput(const Subprocess & p)39 std::string GetOutput(const Subprocess& p) {
40   std::string output = p.output();
41 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42   size_t pos = 0;
43   while ((pos = output.find("\r\n", pos)) != std::string::npos)
44     output.erase(pos, 1);
45 #endif
46   return output;
47 }
48 
GenLargeString()49 std::string GenLargeString() {
50   std::string contents;
51   for (int i = 0; i < 4096; i++) {
52     contents += "very long text " + std::to_string(i) + "\n";
53   }
54   // Make sure that |contents| is > the default pipe buffer on Linux (4 pages).
55   PERFETTO_DCHECK(contents.size() > 4096 * 4);
56   return contents;
57 }
58 
TEST(SubprocessTest,InvalidPath)59 TEST(SubprocessTest, InvalidPath) {
60   Subprocess p({"/usr/bin/invalid_1337"});
61   EXPECT_FALSE(p.Call());
62   EXPECT_EQ(p.status(), Subprocess::kTerminated);
63 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
64   EXPECT_EQ(p.returncode(), ERROR_FILE_NOT_FOUND);
65 #else
66   EXPECT_EQ(p.returncode(), 128);
67   EXPECT_EQ(GetOutput(p), "execve() failed\n");
68 #endif
69 }
70 
TEST(SubprocessTest,StdoutOnly)71 TEST(SubprocessTest, StdoutOnly) {
72 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
73   Subprocess p({"cmd", "/c", "(echo skip_err 1>&2) && echo out_only"});
74 #else
75   Subprocess p({"sh", "-c", "(echo skip_err >&2); echo out_only"});
76 #endif
77   p.args.stdout_mode = Subprocess::kBuffer;
78   p.args.stderr_mode = Subprocess::kDevNull;
79 
80   EXPECT_TRUE(p.Call());
81   EXPECT_EQ(p.status(), Subprocess::kTerminated);
82   EXPECT_EQ(GetOutput(p), "out_only\n");
83 }
84 
TEST(SubprocessTest,StderrOnly)85 TEST(SubprocessTest, StderrOnly) {
86 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
87   Subprocess p({"cmd", "/c", "(echo err_only>&2) && echo skip_out"});
88 #else
89   Subprocess p({"sh", "-c", "(echo err_only >&2); echo skip_out"});
90 #endif
91   p.args.stdout_mode = Subprocess::kDevNull;
92   p.args.stderr_mode = Subprocess::kBuffer;
93   EXPECT_TRUE(p.Call());
94   EXPECT_EQ(GetOutput(p), "err_only\n");
95 }
96 
TEST(SubprocessTest,BothStdoutAndStderr)97 TEST(SubprocessTest, BothStdoutAndStderr) {
98 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
99   Subprocess p({"cmd", "/c", "echo out&&(echo err>&2)&&echo out2"});
100 #else
101   Subprocess p({"sh", "-c", "echo out; (echo err >&2); echo out2"});
102 #endif
103   p.args.stdout_mode = Subprocess::kBuffer;
104   p.args.stderr_mode = Subprocess::kBuffer;
105   EXPECT_TRUE(p.Call());
106   EXPECT_EQ(GetOutput(p), "out\nerr\nout2\n");
107 }
108 
TEST(SubprocessTest,BinTrue)109 TEST(SubprocessTest, BinTrue) {
110 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
111   Subprocess p({"cmd", "/c", "(exit 0)"});
112 #else
113   Subprocess p({"true"});
114 #endif
115   EXPECT_TRUE(p.Call());
116   EXPECT_EQ(p.status(), Subprocess::kTerminated);
117   EXPECT_EQ(p.returncode(), 0);
118 }
119 
TEST(SubprocessTest,BinFalse)120 TEST(SubprocessTest, BinFalse) {
121 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
122   Subprocess p({"cmd", "/c", "(exit 1)"});
123 #else
124   Subprocess p({"false"});
125 #endif
126   EXPECT_FALSE(p.Call());
127   EXPECT_EQ(p.status(), Subprocess::kTerminated);
128   EXPECT_EQ(p.returncode(), 1);
129 }
130 
TEST(SubprocessTest,Echo)131 TEST(SubprocessTest, Echo) {
132 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
133   Subprocess p({"cmd", "/c", "echo|set /p ignored_var=foobar"});
134 #else
135   Subprocess p({"echo", "-n", "foobar"});
136 #endif
137   p.args.stdout_mode = Subprocess::kBuffer;
138   EXPECT_TRUE(p.Call());
139   EXPECT_EQ(p.status(), Subprocess::kTerminated);
140   EXPECT_EQ(p.returncode(), 0);
141   EXPECT_EQ(GetOutput(p), "foobar");
142 }
143 
TEST(SubprocessTest,FeedbackLongInput)144 TEST(SubprocessTest, FeedbackLongInput) {
145   std::string contents = GenLargeString();
146 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
147   Subprocess p({"cmd", "/C", "findstr ."});
148 #else
149   Subprocess p({"cat", "-"});
150 #endif
151   p.args.stdout_mode = Subprocess::kBuffer;
152   p.args.input = contents;
153   EXPECT_TRUE(p.Call());
154   EXPECT_EQ(p.status(), Subprocess::kTerminated);
155   EXPECT_EQ(p.returncode(), 0);
156   EXPECT_EQ(GetOutput(p), contents);
157 }
158 
TEST(SubprocessTest,CatLargeFile)159 TEST(SubprocessTest, CatLargeFile) {
160   std::string contents = GenLargeString();
161   TempFile tf = TempFile::Create();
162   WriteAll(tf.fd(), contents.data(), contents.size());
163   FlushFile(tf.fd());
164 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
165   Subprocess p({"cmd", "/c", ("type \"" + tf.path() + "\"").c_str()});
166 #else
167   Subprocess p({"cat", tf.path().c_str()});
168 #endif
169   p.args.stdout_mode = Subprocess::kBuffer;
170   EXPECT_TRUE(p.Call());
171   EXPECT_EQ(GetOutput(p), contents);
172 }
173 
TEST(SubprocessTest,Timeout)174 TEST(SubprocessTest, Timeout) {
175 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
176   Subprocess p({"ping", "127.0.0.1", "-n", "60"});
177   p.args.stdout_mode = Subprocess::kDevNull;
178 #else
179   Subprocess p({"sleep", "60"});
180 #endif
181 
182   EXPECT_FALSE(p.Call(/*timeout_ms=*/1));
183   EXPECT_EQ(p.status(), Subprocess::kTerminated);
184   EXPECT_TRUE(p.timed_out());
185 }
186 
TEST(SubprocessTest,TimeoutNotHit)187 TEST(SubprocessTest, TimeoutNotHit) {
188 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
189   Subprocess p({"ping", "127.0.0.1", "-n", "1"});
190   p.args.stdout_mode = Subprocess::kDevNull;
191 #else
192   Subprocess p({"sleep", "0.01"});
193 #endif
194   EXPECT_TRUE(p.Call(/*timeout_ms=*/100000));
195   EXPECT_EQ(p.status(), Subprocess::kTerminated);
196 }
197 
TEST(SubprocessTest,TimeoutStopOutput)198 TEST(SubprocessTest, TimeoutStopOutput) {
199 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
200   Subprocess p({"cmd", "/c", "FOR /L %N IN () DO @echo stuff>NUL"});
201 #else
202   Subprocess p({"sh", "-c", "while true; do echo stuff; done"});
203 #endif
204   p.args.stdout_mode = Subprocess::kDevNull;
205   EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
206   EXPECT_EQ(p.status(), Subprocess::kTerminated);
207   EXPECT_TRUE(p.timed_out());
208 }
209 
TEST(SubprocessTest,ExitBeforeReadingStdin)210 TEST(SubprocessTest, ExitBeforeReadingStdin) {
211 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
212   Subprocess p({"ping", "127.0.0.1", "-n", "1"});
213 #else
214   // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
215   Subprocess p({"sh", "-c", "sleep 0.01"});
216 #endif
217   p.args.stdout_mode = Subprocess::kDevNull;
218   p.args.stderr_mode = Subprocess::kDevNull;
219   p.args.input = GenLargeString();
220   EXPECT_TRUE(p.Call());
221   EXPECT_EQ(p.status(), Subprocess::kTerminated);
222   EXPECT_EQ(p.returncode(), 0);
223 }
224 
TEST(SubprocessTest,StdinWriteStall)225 TEST(SubprocessTest, StdinWriteStall) {
226 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
227   Subprocess p({"ping", "127.0.0.1", "-n", "10"});
228 #else
229   // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
230   // This causes a situation where the write on the stdin will stall because
231   // nobody reads it and the pipe buffer fills up. In this situation we should
232   // still handle the timeout properly.
233   Subprocess p({"sh", "-c", "sleep 10"});
234 #endif
235   p.args.stdout_mode = Subprocess::kDevNull;
236   p.args.stderr_mode = Subprocess::kDevNull;
237   p.args.input = GenLargeString();
238   EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
239   EXPECT_EQ(p.status(), Subprocess::kTerminated);
240   EXPECT_TRUE(p.timed_out());
241 }
242 
TEST(SubprocessTest,StartAndWait)243 TEST(SubprocessTest, StartAndWait) {
244 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
245   Subprocess p({"ping", "127.0.0.1", "-n", "1000"});
246 #else
247   Subprocess p({"sleep", "1000"});
248 #endif
249   p.args.stdout_mode = Subprocess::kDevNull;
250   p.Start();
251   EXPECT_EQ(p.Poll(), Subprocess::kRunning);
252   p.KillAndWaitForTermination();
253 
254   EXPECT_EQ(p.status(), Subprocess::kTerminated);
255   EXPECT_EQ(p.Poll(), Subprocess::kTerminated);
256 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
257   EXPECT_EQ(p.returncode(), static_cast<int>(STATUS_CONTROL_C_EXIT));
258 #else
259   EXPECT_EQ(p.returncode(), static_cast<int>(128 + SIGKILL));
260 #endif
261 }
262 
TEST(SubprocessTest,PollBehavesProperly)263 TEST(SubprocessTest, PollBehavesProperly) {
264   Pipe pipe = Pipe::Create();
265 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
266   Subprocess p({"cmd", "/c", "(exit 0)"});
267 #else
268   Subprocess p({"true"});
269 #endif
270   p.args.stdout_mode = Subprocess::kFd;
271   p.args.out_fd = std::move(pipe.wr);
272   p.Start();
273 
274   // Wait for EOF (which really means the child process has terminated).
275   std::string ignored;
276   ReadPlatformHandle(*pipe.rd, &ignored);
277 
278   // The kernel takes some time to detect the termination of the process. The
279   // best thing we can do here is check that we detect the termination within
280   // some reasonable time.
281   auto start_ms = GetWallTimeMs();
282   while (p.Poll() != Subprocess::kTerminated) {
283     auto elapsed_ms = GetWallTimeMs() - start_ms;
284     ASSERT_LT(elapsed_ms, TimeMillis(10000));
285     std::this_thread::sleep_for(TimeMillis(5));
286   }
287 
288   // At this point Poll() must detect the termination.
289   EXPECT_EQ(p.Poll(), Subprocess::kTerminated);
290   EXPECT_EQ(p.returncode(), 0);
291 }
292 
TEST(SubprocessTest,Wait)293 TEST(SubprocessTest, Wait) {
294 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
295   Subprocess p({"cmd", "/c", "echo exec_done && FOR /L %N IN () DO @echo>NUL"});
296 #else
297   Subprocess p({"sh", "-c", "echo exec_done; while true; do true; done"});
298 #endif
299   p.args.stdout_mode = Subprocess::kBuffer;
300   p.Start();
301 
302   // Wait for the fork()+exec() to complete.
303   while (p.output().find("exec_done") == std::string::npos) {
304     EXPECT_FALSE(p.Wait(1 /*ms*/));
305     EXPECT_EQ(p.status(), Subprocess::kRunning);
306   }
307 
308 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
309   ScopedPlatformHandle proc_handle(::OpenProcess(
310       PROCESS_TERMINATE, /*inherit=*/false, static_cast<DWORD>(p.pid())));
311   ASSERT_TRUE(proc_handle);
312   ASSERT_TRUE(::TerminateProcess(*proc_handle, DBG_CONTROL_BREAK));
313 #else
314   kill(p.pid(), SIGBUS);
315 #endif
316   EXPECT_TRUE(p.Wait(30000 /*ms*/));  // We shouldn't hit this.
317   EXPECT_TRUE(p.Wait());              // Should be a no-op.
318   EXPECT_EQ(p.status(), Subprocess::kTerminated);
319 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
320   EXPECT_EQ(p.returncode(), static_cast<int>(DBG_CONTROL_BREAK));
321 #else
322   EXPECT_EQ(p.returncode(), 128 + SIGBUS);
323 #endif
324 }
325 
TEST(SubprocessTest,KillOnDtor)326 TEST(SubprocessTest, KillOnDtor) {
327   auto is_process_alive = [](PlatformProcessId pid) {
328 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
329     DWORD ignored = 0;
330     return ProcessIdToSessionId(static_cast<DWORD>(pid), &ignored);
331 #else
332     // We use kill(SIGWINCH) as a way to tell if the process is still alive by
333     // looking at the kill(2) return value. SIGWINCH is one of the few signals
334     // that has default ignore disposition.
335     return kill(pid, SIGWINCH) == 0;
336 #endif
337   };
338 
339   PlatformProcessId pid;
340   {
341 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
342     Subprocess p({"ping", "127.0.0.1", "-n", "1000"});
343 #else
344     Subprocess p({"sleep", "1000"});
345 #endif
346     p.Start();
347     pid = p.pid();
348     EXPECT_TRUE(is_process_alive(pid));
349   }
350 
351   // Both on Windows and Linux, kill can take some time to free up the pid.
352   bool alive = true;
353   for (int attempt = 0; attempt < 1000 && alive; attempt++) {
354     alive = is_process_alive(pid);
355     std::this_thread::sleep_for(TimeMillis(5));
356   }
357   EXPECT_FALSE(alive);
358 }
359 
360 // Regression test for b/162505491.
TEST(SubprocessTest,MoveOperators)361 TEST(SubprocessTest, MoveOperators) {
362   {
363 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
364     Subprocess initial({"ping", "127.0.0.1", "-n", "100"});
365 #else
366     Subprocess initial = Subprocess({"sleep", "10000"});
367 #endif
368     initial.args.stdout_mode = Subprocess::kDevNull;
369     initial.Start();
370     Subprocess moved(std::move(initial));
371     EXPECT_EQ(moved.Poll(), Subprocess::kRunning);
372     EXPECT_EQ(initial.Poll(), Subprocess::kNotStarted);
373 
374     // Check that reuse works
375 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
376     initial = Subprocess({"cmd", "/c", "echo|set /p ignored_var=hello"});
377 #else
378     initial = Subprocess({"echo", "-n", "hello"});
379 #endif
380     initial.args.stdout_mode = Subprocess::OutputMode::kBuffer;
381     initial.Start();
382     initial.Wait(/*timeout=*/5000);
383     EXPECT_EQ(initial.status(), Subprocess::kTerminated);
384     EXPECT_EQ(initial.returncode(), 0);
385     EXPECT_EQ(initial.output(), "hello");
386   }
387 
388   std::vector<Subprocess> v;
389   for (int i = 0; i < 10; i++) {
390 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
391     v.emplace_back(Subprocess({"ping", "127.0.0.1", "-n", "10"}));
392 #else
393     v.emplace_back(Subprocess({"sleep", "10"}));
394 #endif
395     v.back().args.stdout_mode = Subprocess::OutputMode::kDevNull;
396     v.back().Start();
397   }
398   for (auto& p : v)
399     EXPECT_EQ(p.Poll(), Subprocess::kRunning);
400 }
401 
402 // posix_entrypoint_for_testing is not supported on Windows.
403 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
404 
405 // Test the case of passing a lambda in |entrypoint| but no cmd.c
TEST(SubprocessTest,Entrypoint)406 TEST(SubprocessTest, Entrypoint) {
407   Subprocess p;
408   p.args.input = "ping\n";
409   p.args.stdout_mode = Subprocess::kBuffer;
410   p.args.posix_entrypoint_for_testing = [] {
411     char buf[32]{};
412     PERFETTO_CHECK(fgets(buf, sizeof(buf), stdin));
413     PERFETTO_CHECK(strcmp(buf, "ping\n") == 0);
414     printf("pong\n");
415     fflush(stdout);
416     _exit(42);
417   };
418   EXPECT_FALSE(p.Call());
419   EXPECT_EQ(p.returncode(), 42);
420   EXPECT_EQ(GetOutput(p), "pong\n");
421 }
422 
423 // Test the case of passing both a lambda entrypoint and a process to exec.
TEST(SubprocessTest,EntrypointAndExec)424 TEST(SubprocessTest, EntrypointAndExec) {
425   base::Pipe pipe1 = base::Pipe::Create();
426   base::Pipe pipe2 = base::Pipe::Create();
427   int pipe1_wr = *pipe1.wr;
428   int pipe2_wr = *pipe2.wr;
429 
430   Subprocess p({"echo", "123"});
431   p.args.stdout_mode = Subprocess::kBuffer;
432   p.args.preserve_fds.push_back(pipe2_wr);
433   p.args.posix_entrypoint_for_testing = [pipe1_wr, pipe2_wr] {
434     base::ignore_result(write(pipe1_wr, "fail", 4));
435     base::ignore_result(write(pipe2_wr, "pass", 4));
436   };
437 
438   p.Start();
439   pipe1.wr.reset();
440   pipe2.wr.reset();
441 
442   char buf[8];
443   EXPECT_LE(read(*pipe1.rd, buf, sizeof(buf)), 0);
444   EXPECT_EQ(read(*pipe2.rd, buf, sizeof(buf)), 4);
445   buf[4] = '\0';
446   EXPECT_STREQ(buf, "pass");
447   EXPECT_TRUE(p.Wait());
448   EXPECT_EQ(p.status(), Subprocess::kTerminated);
449   EXPECT_EQ(GetOutput(p), "123\n");
450 }
451 
452 #endif
453 
454 }  // namespace
455 }  // namespace base
456 }  // namespace perfetto
457