blob: 8f6def9c2c1f15c499ecf92128139db023797295 [file] [log] [blame]
levin@chromium.org5c528682011-03-28 10:54:15 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
5#define _CRT_SECURE_NO_WARNINGS
6
vandebo@chromium.orga7a30982009-11-19 06:10:57 +09007#include <limits>
8
phajdan.jr@chromium.org80fcf7d2009-04-17 18:57:52 +09009#include "base/command_line.h"
agl@chromium.orgd263ad72009-05-02 06:37:31 +090010#include "base/eintr_wrapper.h"
jcampan@chromium.org5c270332009-04-22 06:44:12 +090011#include "base/file_path.h"
erg@google.comcb8b2cb2010-08-31 05:15:25 +090012#include "base/logging.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090013#include "base/memory/scoped_ptr.h"
jcampan@chromium.org5c270332009-04-22 06:44:12 +090014#include "base/path_service.h"
initial.commit3f4a7322008-07-27 06:49:38 +090015#include "base/process_util.h"
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +090016#include "base/test/multiprocess_test.h"
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090017#include "base/test/test_timeouts.h"
bradchen@google.com2df7cdc2011-07-19 10:09:14 +090018#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
brettw@chromium.org61391822011-01-01 05:02:16 +090019#include "base/threading/platform_thread.h"
brettw@chromium.orgd85babb2010-08-03 23:35:22 +090020#include "base/utf_string_conversions.h"
estade@chromium.org92ac1542008-10-22 10:15:47 +090021#include "testing/gtest/include/gtest/gtest.h"
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +090022#include "testing/multiprocess_func_list.h"
initial.commit3f4a7322008-07-27 06:49:38 +090023
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +090024#if defined(OS_LINUX)
vandebo@chromium.orgb2a3f932009-11-25 06:34:53 +090025#include <errno.h>
vandebo@chromium.orga7a30982009-11-19 06:10:57 +090026#include <malloc.h>
agl@chromium.org37ec6ec2010-01-09 06:28:27 +090027#include <glib.h>
bradchen@google.com8486c472011-07-16 08:55:21 +090028#include <sched.h>
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +090029#endif
30#if defined(OS_POSIX)
avi@chromium.org0cc39242010-05-20 05:23:46 +090031#include <dlfcn.h>
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +090032#include <fcntl.h>
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090033#include <signal.h>
evan@chromium.org875bb6e2009-12-29 09:32:52 +090034#include <sys/resource.h>
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +090035#include <sys/socket.h>
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +090036#include <sys/wait.h>
37#endif
estade@chromium.org92ac1542008-10-22 10:15:47 +090038#if defined(OS_WIN)
39#include <windows.h>
estade@chromium.org92ac1542008-10-22 10:15:47 +090040#endif
avi@chromium.org4b9545a2010-03-20 03:42:41 +090041#if defined(OS_MACOSX)
avi@chromium.org41d92e82010-07-02 05:11:43 +090042#include <malloc/malloc.h>
avi@chromium.org4b9545a2010-03-20 03:42:41 +090043#include "base/process_util_unittest_mac.h"
44#endif
estade@chromium.org92ac1542008-10-22 10:15:47 +090045
maruel@chromium.org9cf11e82010-04-30 02:44:42 +090046namespace {
47
48#if defined(OS_WIN)
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090049const wchar_t kProcessName[] = L"base_unittests.exe";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +090050#else
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090051const wchar_t kProcessName[] = L"base_unittests";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +090052#endif // defined(OS_WIN)
53
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +090054#if defined(OS_ANDROID)
55const char kShellPath[] = "/system/bin/sh";
56const char kPosixShell[] = "sh";
57#else
58const char kShellPath[] = "/bin/sh";
59const char kPosixShell[] = "bash";
60#endif
61
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090062const char kSignalFileSlow[] = "SlowChildProcess.die";
63const char kSignalFileCrash[] = "CrashingChildProcess.die";
64const char kSignalFileKill[] = "KilledChildProcess.die";
65
66#if defined(OS_WIN)
67const int kExpectedStillRunningExitCode = 0x102;
68const int kExpectedKilledExitCode = 1;
69#else
70const int kExpectedStillRunningExitCode = 0;
71#endif
72
maruel@chromium.org77fa1502010-06-12 04:10:30 +090073// Sleeps until file filename is created.
74void WaitToDie(const char* filename) {
75 FILE *fp;
76 do {
brettw@chromium.org61391822011-01-01 05:02:16 +090077 base::PlatformThread::Sleep(10);
maruel@chromium.org77fa1502010-06-12 04:10:30 +090078 fp = fopen(filename, "r");
79 } while (!fp);
80 fclose(fp);
81}
82
83// Signals children they should die now.
84void SignalChildren(const char* filename) {
85 FILE *fp = fopen(filename, "w");
86 fclose(fp);
87}
88
gspencer@chromium.org587d4f02010-12-14 09:42:23 +090089// Using a pipe to the child to wait for an event was considered, but
90// there were cases in the past where pipes caused problems (other
91// libraries closing the fds, child deadlocking). This is a simple
92// case, so it's not worth the risk. Using wait loops is discouraged
93// in most instances.
94base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
95 int* exit_code) {
96 // Now we wait until the result is something other than STILL_RUNNING.
97 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
98 const int kIntervalMs = 20;
99 int waited = 0;
100 do {
101 status = base::GetTerminationStatus(handle, exit_code);
brettw@chromium.org61391822011-01-01 05:02:16 +0900102 base::PlatformThread::Sleep(kIntervalMs);
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900103 waited += kIntervalMs;
104 } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
phajdan.jr@chromium.org59bceeb2011-06-10 03:53:13 +0900105 waited < TestTimeouts::action_max_timeout_ms());
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900106
107 return status;
108}
109
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900110} // namespace
brettw@google.comc60d9892008-11-14 12:25:15 +0900111
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +0900112class ProcessUtilTest : public base::MultiProcessTest {
evan@chromium.org048a2222009-08-25 10:50:52 +0900113#if defined(OS_POSIX)
114 public:
115 // Spawn a child process that counts how many file descriptors are open.
116 int CountOpenFDsInChild();
117#endif
estade@chromium.org92ac1542008-10-22 10:15:47 +0900118};
estade@chromium.org92ac1542008-10-22 10:15:47 +0900119
jeremy@chromium.org012e9992008-10-30 05:46:04 +0900120MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
estade@chromium.org92ac1542008-10-22 10:15:47 +0900121 return 0;
122}
123
124TEST_F(ProcessUtilTest, SpawnChild) {
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +0900125 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
phajdan.jr@chromium.orgef0e9432009-10-13 22:43:42 +0900126 ASSERT_NE(base::kNullProcessHandle, handle);
phajdan.jr@chromium.org59bceeb2011-06-10 03:53:13 +0900127 EXPECT_TRUE(base::WaitForSingleProcess(
128 handle, TestTimeouts::action_max_timeout_ms()));
stoyan@chromium.org3067a4d2009-02-10 04:28:41 +0900129 base::CloseProcessHandle(handle);
estade@chromium.org92ac1542008-10-22 10:15:47 +0900130}
131
dkegel@google.com902a9712008-11-01 05:19:43 +0900132MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900133 WaitToDie(kSignalFileSlow);
dkegel@google.com902a9712008-11-01 05:19:43 +0900134 return 0;
135}
136
dkegel@google.com6f2e2d82008-11-01 05:58:55 +0900137TEST_F(ProcessUtilTest, KillSlowChild) {
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900138 remove(kSignalFileSlow);
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +0900139 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
phajdan.jr@chromium.orgef0e9432009-10-13 22:43:42 +0900140 ASSERT_NE(base::kNullProcessHandle, handle);
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900141 SignalChildren(kSignalFileSlow);
phajdan.jr@chromium.org59bceeb2011-06-10 03:53:13 +0900142 EXPECT_TRUE(base::WaitForSingleProcess(
143 handle, TestTimeouts::action_max_timeout_ms()));
stoyan@chromium.org3067a4d2009-02-10 04:28:41 +0900144 base::CloseProcessHandle(handle);
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900145 remove(kSignalFileSlow);
dkegel@google.com902a9712008-11-01 05:19:43 +0900146}
147
thakis@chromium.orge2865b22011-09-20 02:43:00 +0900148// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058
149#if defined(OS_LINUX) || defined(OS_WIN)
dyu@chromium.org2b47e612011-09-02 02:45:52 +0900150#define MAYBE_GetTerminationStatusExit DISABLED_GetTerminationStatusExit
151#else
mad@chromium.orgfd9caa32011-09-15 00:16:19 +0900152#define MAYBE_GetTerminationStatusExit FLAKY_GetTerminationStatusExit
dyu@chromium.org2b47e612011-09-02 02:45:52 +0900153#endif
154
155TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusExit) {
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900156 remove(kSignalFileSlow);
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +0900157 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
phajdan.jr@chromium.org6c941222010-04-06 22:03:47 +0900158 ASSERT_NE(base::kNullProcessHandle, handle);
159
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900160 int exit_code = 42;
161 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
162 base::GetTerminationStatus(handle, &exit_code));
163 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
phajdan.jr@chromium.org6c941222010-04-06 22:03:47 +0900164
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900165 SignalChildren(kSignalFileSlow);
166 exit_code = 42;
167 base::TerminationStatus status =
168 WaitForChildTermination(handle, &exit_code);
169 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
170 EXPECT_EQ(0, exit_code);
phajdan.jr@chromium.org6c941222010-04-06 22:03:47 +0900171 base::CloseProcessHandle(handle);
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900172 remove(kSignalFileSlow);
173}
174
175#if !defined(OS_MACOSX)
176// This test is disabled on Mac, since it's flaky due to ReportCrash
177// taking a variable amount of time to parse and load the debug and
178// symbol data for this unit test's executable before firing the
179// signal handler.
180//
181// TODO(gspencer): turn this test process into a very small program
182// with no symbols (instead of using the multiprocess testing
183// framework) to reduce the ReportCrash overhead.
184
185MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
186 WaitToDie(kSignalFileCrash);
187#if defined(OS_POSIX)
188 // Have to disable to signal handler for segv so we can get a crash
189 // instead of an abnormal termination through the crash dump handler.
190 ::signal(SIGSEGV, SIG_DFL);
191#endif
192 // Make this process have a segmentation fault.
hans@chromium.org9221ced2011-10-12 03:53:36 +0900193 volatile int* oops = NULL;
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900194 *oops = 0xDEAD;
195 return 1;
196}
197
glider@chromium.org3b393cb2011-09-21 06:39:13 +0900198// This test intentionally crashes, so we don't need to run it under
199// AddressSanitizer.
200#if defined(ADDRESS_SANITIZER)
201#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash
202#else
203#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash
204#endif
205TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
gspencer@chromium.org587d4f02010-12-14 09:42:23 +0900206 remove(kSignalFileCrash);
207 base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
208 false);
209 ASSERT_NE(base::kNullProcessHandle, handle);
210
211 int exit_code = 42;
212 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
213 base::GetTerminationStatus(handle, &exit_code));
214 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
215
216 SignalChildren(kSignalFileCrash);
217 exit_code = 42;
218 base::TerminationStatus status =
219 WaitForChildTermination(handle, &exit_code);
220 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
221
222#if defined(OS_WIN)
223 EXPECT_EQ(0xc0000005, exit_code);
224#elif defined(OS_POSIX)
225 int signaled = WIFSIGNALED(exit_code);
226 EXPECT_NE(0, signaled);
227 int signal = WTERMSIG(exit_code);
228 EXPECT_EQ(SIGSEGV, signal);
229#endif
230 base::CloseProcessHandle(handle);
231
232 // Reset signal handlers back to "normal".
233 base::EnableInProcessStackDumping();
234 remove(kSignalFileCrash);
235}
236#endif // !defined(OS_MACOSX)
237
238MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
239 WaitToDie(kSignalFileKill);
240#if defined(OS_WIN)
241 // Kill ourselves.
242 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
243 ::TerminateProcess(handle, kExpectedKilledExitCode);
244#elif defined(OS_POSIX)
245 // Send a SIGKILL to this process, just like the OOM killer would.
246 ::kill(getpid(), SIGKILL);
247#endif
248 return 1;
249}
250
251TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
252 remove(kSignalFileKill);
253 base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
254 false);
255 ASSERT_NE(base::kNullProcessHandle, handle);
256
257 int exit_code = 42;
258 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
259 base::GetTerminationStatus(handle, &exit_code));
260 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
261
262 SignalChildren(kSignalFileKill);
263 exit_code = 42;
264 base::TerminationStatus status =
265 WaitForChildTermination(handle, &exit_code);
266 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
267#if defined(OS_WIN)
268 EXPECT_EQ(kExpectedKilledExitCode, exit_code);
269#elif defined(OS_POSIX)
270 int signaled = WIFSIGNALED(exit_code);
271 EXPECT_NE(0, signaled);
272 int signal = WTERMSIG(exit_code);
273 EXPECT_EQ(SIGKILL, signal);
274#endif
275 base::CloseProcessHandle(handle);
276 remove(kSignalFileKill);
phajdan.jr@chromium.org6c941222010-04-06 22:03:47 +0900277}
278
davemoore@chromium.orgad59fcb2009-10-30 02:43:44 +0900279// Ensure that the priority of a process is restored correctly after
280// backgrounding and restoring.
281// Note: a platform may not be willing or able to lower the priority of
282// a process. The calls to SetProcessBackground should be noops then.
283TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
brettw@chromium.org1c8c3be2010-08-18 04:40:11 +0900284 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900285 base::Process process(handle);
davemoore@chromium.orgad59fcb2009-10-30 02:43:44 +0900286 int old_priority = process.GetPriority();
cpu@chromium.orga540d362011-04-29 09:41:36 +0900287#if defined(OS_WIN)
cpu@chromium.org2c6bbaf2011-04-29 10:22:31 +0900288 EXPECT_TRUE(process.SetProcessBackgrounded(true));
289 EXPECT_TRUE(process.IsProcessBackgrounded());
290 EXPECT_TRUE(process.SetProcessBackgrounded(false));
291 EXPECT_FALSE(process.IsProcessBackgrounded());
292#else
293 process.SetProcessBackgrounded(true);
294 process.SetProcessBackgrounded(false);
cpu@chromium.orga540d362011-04-29 09:41:36 +0900295#endif
cpu@chromium.orgc4a8beb2011-04-29 08:51:53 +0900296 int new_priority = process.GetPriority();
297 EXPECT_EQ(old_priority, new_priority);
298}
299
300// Same as SetProcessBackgrounded but to this very process. It uses
301// a different code path at least for Windows.
302TEST_F(ProcessUtilTest, SetProcessBackgroundedSelf) {
303 base::Process process(base::Process::Current().handle());
304 int old_priority = process.GetPriority();
cpu@chromium.orga540d362011-04-29 09:41:36 +0900305#if defined(OS_WIN)
cpu@chromium.org2c6bbaf2011-04-29 10:22:31 +0900306 EXPECT_TRUE(process.SetProcessBackgrounded(true));
307 EXPECT_TRUE(process.IsProcessBackgrounded());
308 EXPECT_TRUE(process.SetProcessBackgrounded(false));
309 EXPECT_FALSE(process.IsProcessBackgrounded());
310#else
311 process.SetProcessBackgrounded(true);
312 process.SetProcessBackgrounded(false);
cpu@chromium.orga540d362011-04-29 09:41:36 +0900313#endif
davemoore@chromium.orgad59fcb2009-10-30 02:43:44 +0900314 int new_priority = process.GetPriority();
315 EXPECT_EQ(old_priority, new_priority);
316}
317
estade@chromium.org92ac1542008-10-22 10:15:47 +0900318// TODO(estade): if possible, port these 2 tests.
319#if defined(OS_WIN)
320TEST_F(ProcessUtilTest, EnableLFH) {
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900321 ASSERT_TRUE(base::EnableLowFragmentationHeap());
initial.commit3f4a7322008-07-27 06:49:38 +0900322 if (IsDebuggerPresent()) {
323 // Under these conditions, LFH can't be enabled. There's no point to test
324 // anything.
325 const char* no_debug_env = getenv("_NO_DEBUG_HEAP");
326 if (!no_debug_env || strcmp(no_debug_env, "1"))
327 return;
328 }
329 HANDLE heaps[1024] = { 0 };
330 unsigned number_heaps = GetProcessHeaps(1024, heaps);
331 EXPECT_GT(number_heaps, 0u);
332 for (unsigned i = 0; i < number_heaps; ++i) {
333 ULONG flag = 0;
334 SIZE_T length;
335 ASSERT_NE(0, HeapQueryInformation(heaps[i],
336 HeapCompatibilityInformation,
337 &flag,
338 sizeof(flag),
339 &length));
340 // If flag is 0, the heap is a standard heap that does not support
341 // look-asides. If flag is 1, the heap supports look-asides. If flag is 2,
342 // the heap is a low-fragmentation heap (LFH). Note that look-asides are not
343 // supported on the LFH.
344
345 // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag.
346 EXPECT_LE(flag, 2u);
347 EXPECT_NE(flag, 1u);
348 }
349}
350
estade@chromium.org92ac1542008-10-22 10:15:47 +0900351TEST_F(ProcessUtilTest, CalcFreeMemory) {
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900352 scoped_ptr<base::ProcessMetrics> metrics(
353 base::ProcessMetrics::CreateProcessMetrics(::GetCurrentProcess()));
354 ASSERT_TRUE(NULL != metrics.get());
initial.commit3f4a7322008-07-27 06:49:38 +0900355
356 // Typical values here is ~1900 for total and ~1000 for largest. Obviously
357 // it depends in what other tests have done to this process.
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900358 base::FreeMBytes free_mem1 = {0};
initial.commit3f4a7322008-07-27 06:49:38 +0900359 EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem1));
360 EXPECT_LT(10u, free_mem1.total);
361 EXPECT_LT(10u, free_mem1.largest);
362 EXPECT_GT(2048u, free_mem1.total);
363 EXPECT_GT(2048u, free_mem1.largest);
364 EXPECT_GE(free_mem1.total, free_mem1.largest);
365 EXPECT_TRUE(NULL != free_mem1.largest_ptr);
366
367 // Allocate 20M and check again. It should have gone down.
368 const int kAllocMB = 20;
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900369 scoped_array<char> alloc(new char[kAllocMB * 1024 * 1024]);
initial.commit3f4a7322008-07-27 06:49:38 +0900370 size_t expected_total = free_mem1.total - kAllocMB;
371 size_t expected_largest = free_mem1.largest;
372
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900373 base::FreeMBytes free_mem2 = {0};
initial.commit3f4a7322008-07-27 06:49:38 +0900374 EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem2));
375 EXPECT_GE(free_mem2.total, free_mem2.largest);
376 EXPECT_GE(expected_total, free_mem2.total);
377 EXPECT_GE(expected_largest, free_mem2.largest);
378 EXPECT_TRUE(NULL != free_mem2.largest_ptr);
initial.commit3f4a7322008-07-27 06:49:38 +0900379}
jcampan@chromium.org5c270332009-04-22 06:44:12 +0900380
381TEST_F(ProcessUtilTest, GetAppOutput) {
382 // Let's create a decently long message.
383 std::string message;
384 for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte
385 // boundary.
386 message += "Hello!";
387 }
388
389 FilePath python_runtime;
390 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime));
391 python_runtime = python_runtime.Append(FILE_PATH_LITERAL("third_party"))
bradnelson@google.combf2587b2010-11-23 12:18:19 +0900392 .Append(FILE_PATH_LITERAL("python_26"))
jcampan@chromium.org5c270332009-04-22 06:44:12 +0900393 .Append(FILE_PATH_LITERAL("python.exe"));
394
evan@chromium.orgc4fee2c2009-10-27 07:39:33 +0900395 CommandLine cmd_line(python_runtime);
evan@chromium.org580ab7f2010-08-14 07:10:30 +0900396 cmd_line.AppendArg("-c");
397 cmd_line.AppendArg("import sys; sys.stdout.write('" + message + "');");
jcampan@chromium.org5c270332009-04-22 06:44:12 +0900398 std::string output;
399 ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
400 EXPECT_EQ(message, output);
401
402 // Let's make sure stderr is ignored.
evan@chromium.orgc4fee2c2009-10-27 07:39:33 +0900403 CommandLine other_cmd_line(python_runtime);
evan@chromium.org580ab7f2010-08-14 07:10:30 +0900404 other_cmd_line.AppendArg("-c");
405 other_cmd_line.AppendArg("import sys; sys.stderr.write('Hello!');");
jcampan@chromium.org5c270332009-04-22 06:44:12 +0900406 output.clear();
jcampan@chromium.org56389002009-06-05 05:30:15 +0900407 ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output));
jcampan@chromium.org5c270332009-04-22 06:44:12 +0900408 EXPECT_EQ("", output);
409}
cpu@chromium.org40dea2f2010-02-01 12:28:47 +0900410
411TEST_F(ProcessUtilTest, LaunchAsUser) {
412 base::UserTokenHandle token;
413 ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
414 std::wstring cmdline =
msw@chromium.orgc57622c2011-07-20 13:54:52 +0900415 this->MakeCmdLine("SimpleChildProcess", false).GetCommandLineString();
evan@chromium.org23210262011-07-20 01:30:27 +0900416 base::LaunchOptions options;
417 options.as_user = token;
418 EXPECT_TRUE(base::LaunchProcess(cmdline, options, NULL));
cpu@chromium.org40dea2f2010-02-01 12:28:47 +0900419}
420
estade@chromium.org92ac1542008-10-22 10:15:47 +0900421#endif // defined(OS_WIN)
license.botf003cfe2008-08-24 09:55:55 +0900422
rsesek@chromium.org3b26fdb2011-08-19 05:23:04 +0900423#if defined(OS_MACOSX)
424
425TEST_F(ProcessUtilTest, MacTerminateOnHeapCorruption) {
426 // Note that base::EnableTerminationOnHeapCorruption() is called as part of
427 // test suite setup and does not need to be done again, else mach_override
428 // will fail.
429
430 char buf[3];
431 ASSERT_DEATH(free(buf), "being freed.*"
432 "\\*\\*\\* set a breakpoint in malloc_error_break to debug.*"
433 "Terminating process due to a potential for future heap corruption");
434}
435
436#endif // defined(OS_MACOSX)
437
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900438#if defined(OS_POSIX)
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900439
440namespace {
441
jeremy@chromium.org3113a772009-01-30 02:51:51 +0900442// Returns the maximum number of files that a process can have open.
443// Returns 0 on error.
444int GetMaxFilesOpenInProcess() {
445 struct rlimit rlim;
446 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
447 return 0;
448 }
449
450 // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
451 // which are all 32 bits on the supported platforms.
452 rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
453 if (rlim.rlim_cur > max_int) {
454 return max_int;
455 }
456
457 return rlim.rlim_cur;
458}
459
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900460const int kChildPipe = 20; // FD # for write end of pipe in child process.
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900461
462} // namespace
463
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900464MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
465 // This child process counts the number of open FDs, it then writes that
466 // number out to a pipe connected to the parent.
467 int num_open_files = 0;
468 int write_pipe = kChildPipe;
469 int max_files = GetMaxFilesOpenInProcess();
470 for (int i = STDERR_FILENO + 1; i < max_files; i++) {
471 if (i != kChildPipe) {
dkegel@google.com62718722009-10-21 05:50:24 +0900472 int fd;
473 if ((fd = HANDLE_EINTR(dup(i))) != -1) {
474 close(fd);
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900475 num_open_files += 1;
476 }
477 }
478 }
479
agl@chromium.orgd263ad72009-05-02 06:37:31 +0900480 int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
481 sizeof(num_open_files)));
hbono@chromium.org16ba7392009-02-23 16:14:49 +0900482 DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
evan@chromium.org36699862010-02-02 11:28:16 +0900483 int ret = HANDLE_EINTR(close(write_pipe));
484 DPCHECK(ret == 0);
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900485
486 return 0;
487}
488
evan@chromium.org048a2222009-08-25 10:50:52 +0900489int ProcessUtilTest::CountOpenFDsInChild() {
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900490 int fds[2];
evan@chromium.org08599b42009-02-23 13:07:56 +0900491 if (pipe(fds) < 0)
492 NOTREACHED();
evan@chromium.org048a2222009-08-25 10:50:52 +0900493
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900494 base::file_handle_mapping_vector fd_mapping_vec;
thestig@chromium.orgc491b202010-02-26 09:31:08 +0900495 fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900496 base::ProcessHandle handle = this->SpawnChild(
evan@chromium.org3f985142010-07-30 11:14:22 +0900497 "ProcessUtilsLeakFDChildProcess", fd_mapping_vec, false);
evan@chromium.org048a2222009-08-25 10:50:52 +0900498 CHECK(handle);
evan@chromium.org36699862010-02-02 11:28:16 +0900499 int ret = HANDLE_EINTR(close(fds[1]));
500 DPCHECK(ret == 0);
evan@chromium.org048a2222009-08-25 10:50:52 +0900501
502 // Read number of open files in client process from pipe;
503 int num_open_files = -1;
504 ssize_t bytes_read =
505 HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files)));
willchan@chromium.orge5ec8202010-03-02 09:41:12 +0900506 CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
evan@chromium.org048a2222009-08-25 10:50:52 +0900507
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900508 CHECK(base::WaitForSingleProcess(handle, 1000));
evan@chromium.org048a2222009-08-25 10:50:52 +0900509 base::CloseProcessHandle(handle);
evan@chromium.org36699862010-02-02 11:28:16 +0900510 ret = HANDLE_EINTR(close(fds[0]));
511 DPCHECK(ret == 0);
evan@chromium.org048a2222009-08-25 10:50:52 +0900512
513 return num_open_files;
514}
515
516TEST_F(ProcessUtilTest, FDRemapping) {
517 int fds_before = CountOpenFDsInChild();
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900518
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900519 // open some dummy fds to make sure they don't propagate over to the
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900520 // child process.
521 int dev_null = open("/dev/null", O_RDONLY);
522 int sockets[2];
523 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
524
evan@chromium.org048a2222009-08-25 10:50:52 +0900525 int fds_after = CountOpenFDsInChild();
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900526
evan@chromium.org048a2222009-08-25 10:50:52 +0900527 ASSERT_EQ(fds_after, fds_before);
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900528
evan@chromium.org36699862010-02-02 11:28:16 +0900529 int ret;
530 ret = HANDLE_EINTR(close(sockets[0]));
531 DPCHECK(ret == 0);
532 ret = HANDLE_EINTR(close(sockets[1]));
533 DPCHECK(ret == 0);
534 ret = HANDLE_EINTR(close(dev_null));
535 DPCHECK(ret == 0);
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900536}
537
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900538namespace {
539
bradchen@google.com8486c472011-07-16 08:55:21 +0900540std::string TestLaunchProcess(const base::environment_vector& env_changes,
541 const int clone_flags) {
agl@chromium.org4300a312010-03-12 00:25:54 +0900542 std::vector<std::string> args;
543 base::file_handle_mapping_vector fds_to_remap;
agl@chromium.org4300a312010-03-12 00:25:54 +0900544
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900545 args.push_back(kPosixShell);
agl@chromium.org4300a312010-03-12 00:25:54 +0900546 args.push_back("-c");
547 args.push_back("echo $BASE_TEST");
548
549 int fds[2];
550 PCHECK(pipe(fds) == 0);
551
552 fds_to_remap.push_back(std::make_pair(fds[1], 1));
evan@chromium.orgfa395722011-07-13 03:09:46 +0900553 base::LaunchOptions options;
554 options.wait = true;
555 options.environ = &env_changes;
556 options.fds_to_remap = &fds_to_remap;
mark@chromium.orgcb1af062011-09-02 06:44:24 +0900557#if defined(OS_LINUX)
bradchen@google.com8486c472011-07-16 08:55:21 +0900558 options.clone_flags = clone_flags;
mark@chromium.orgcb1af062011-09-02 06:44:24 +0900559#else
560 CHECK_EQ(0, clone_flags);
561#endif // OS_LINUX
evan@chromium.org81cdadb2011-07-16 01:47:02 +0900562 EXPECT_TRUE(base::LaunchProcess(args, options, NULL));
mark@chromium.orgc3997312011-01-11 02:09:45 +0900563 PCHECK(HANDLE_EINTR(close(fds[1])) == 0);
agl@chromium.org4300a312010-03-12 00:25:54 +0900564
565 char buf[512];
566 const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
567 PCHECK(n > 0);
mark@chromium.orgc3997312011-01-11 02:09:45 +0900568
569 PCHECK(HANDLE_EINTR(close(fds[0])) == 0);
570
agl@chromium.org4300a312010-03-12 00:25:54 +0900571 return std::string(buf, n);
572}
573
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900574const char kLargeString[] =
agl@chromium.org4300a312010-03-12 00:25:54 +0900575 "0123456789012345678901234567890123456789012345678901234567890123456789"
576 "0123456789012345678901234567890123456789012345678901234567890123456789"
577 "0123456789012345678901234567890123456789012345678901234567890123456789"
578 "0123456789012345678901234567890123456789012345678901234567890123456789"
579 "0123456789012345678901234567890123456789012345678901234567890123456789"
580 "0123456789012345678901234567890123456789012345678901234567890123456789"
581 "0123456789012345678901234567890123456789012345678901234567890123456789";
582
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900583} // namespace
584
evan@chromium.orgfa395722011-07-13 03:09:46 +0900585TEST_F(ProcessUtilTest, LaunchProcess) {
agl@chromium.org4300a312010-03-12 00:25:54 +0900586 base::environment_vector env_changes;
bradchen@google.com8486c472011-07-16 08:55:21 +0900587 const int no_clone_flags = 0;
agl@chromium.org4300a312010-03-12 00:25:54 +0900588
589 env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
590 std::string("bar")));
bradchen@google.com8486c472011-07-16 08:55:21 +0900591 EXPECT_EQ("bar\n", TestLaunchProcess(env_changes, no_clone_flags));
agl@chromium.org4300a312010-03-12 00:25:54 +0900592 env_changes.clear();
593
594 EXPECT_EQ(0, setenv("BASE_TEST", "testing", 1 /* override */));
bradchen@google.com8486c472011-07-16 08:55:21 +0900595 EXPECT_EQ("testing\n", TestLaunchProcess(env_changes, no_clone_flags));
agl@chromium.org4300a312010-03-12 00:25:54 +0900596
597 env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
598 std::string("")));
bradchen@google.com8486c472011-07-16 08:55:21 +0900599 EXPECT_EQ("\n", TestLaunchProcess(env_changes, no_clone_flags));
agl@chromium.org4300a312010-03-12 00:25:54 +0900600
601 env_changes[0].second = "foo";
bradchen@google.com8486c472011-07-16 08:55:21 +0900602 EXPECT_EQ("foo\n", TestLaunchProcess(env_changes, no_clone_flags));
agl@chromium.org4300a312010-03-12 00:25:54 +0900603
604 env_changes.clear();
605 EXPECT_EQ(0, setenv("BASE_TEST", kLargeString, 1 /* override */));
bradchen@google.com8486c472011-07-16 08:55:21 +0900606 EXPECT_EQ(std::string(kLargeString) + "\n",
607 TestLaunchProcess(env_changes, no_clone_flags));
agl@chromium.org4300a312010-03-12 00:25:54 +0900608
609 env_changes.push_back(std::make_pair(std::string("BASE_TEST"),
610 std::string("wibble")));
bradchen@google.com8486c472011-07-16 08:55:21 +0900611 EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, no_clone_flags));
612
613#if defined(OS_LINUX)
bradchen@google.com2df7cdc2011-07-19 10:09:14 +0900614 // Test a non-trival value for clone_flags.
615 // Don't test on Valgrind as it has limited support for clone().
616 if (!RunningOnValgrind()) {
617 EXPECT_EQ("wibble\n", TestLaunchProcess(env_changes, CLONE_FS | SIGCHLD));
618 }
bradchen@google.com8486c472011-07-16 08:55:21 +0900619#endif
agl@chromium.org4300a312010-03-12 00:25:54 +0900620}
621
622TEST_F(ProcessUtilTest, AlterEnvironment) {
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900623 const char* const empty[] = { NULL };
624 const char* const a2[] = { "A=2", NULL };
agl@chromium.org4300a312010-03-12 00:25:54 +0900625 base::environment_vector changes;
626 char** e;
627
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900628 e = base::AlterEnvironment(changes, empty);
agl@chromium.org4300a312010-03-12 00:25:54 +0900629 EXPECT_TRUE(e[0] == NULL);
630 delete[] e;
631
632 changes.push_back(std::make_pair(std::string("A"), std::string("1")));
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900633 e = base::AlterEnvironment(changes, empty);
agl@chromium.org4300a312010-03-12 00:25:54 +0900634 EXPECT_EQ(std::string("A=1"), e[0]);
635 EXPECT_TRUE(e[1] == NULL);
636 delete[] e;
637
638 changes.clear();
639 changes.push_back(std::make_pair(std::string("A"), std::string("")));
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900640 e = base::AlterEnvironment(changes, empty);
agl@chromium.org4300a312010-03-12 00:25:54 +0900641 EXPECT_TRUE(e[0] == NULL);
642 delete[] e;
643
644 changes.clear();
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900645 e = base::AlterEnvironment(changes, a2);
agl@chromium.org4300a312010-03-12 00:25:54 +0900646 EXPECT_EQ(std::string("A=2"), e[0]);
647 EXPECT_TRUE(e[1] == NULL);
648 delete[] e;
649
650 changes.clear();
651 changes.push_back(std::make_pair(std::string("A"), std::string("1")));
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900652 e = base::AlterEnvironment(changes, a2);
agl@chromium.org4300a312010-03-12 00:25:54 +0900653 EXPECT_EQ(std::string("A=1"), e[0]);
654 EXPECT_TRUE(e[1] == NULL);
655 delete[] e;
656
657 changes.clear();
658 changes.push_back(std::make_pair(std::string("A"), std::string("")));
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900659 e = base::AlterEnvironment(changes, a2);
agl@chromium.org4300a312010-03-12 00:25:54 +0900660 EXPECT_TRUE(e[0] == NULL);
661 delete[] e;
662}
663
viettrungluu@chromium.org2090aa92010-07-28 13:02:34 +0900664TEST_F(ProcessUtilTest, GetAppOutput) {
phajdan.jr@chromium.org80fcf7d2009-04-17 18:57:52 +0900665 std::string output;
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900666
667#if defined(OS_ANDROID)
668 std::vector<std::string> argv;
669 argv.push_back("sh"); // Instead of /bin/sh, force path search to find it.
670 argv.push_back("-c");
671
672 argv.push_back("exit 0");
673 EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
674 EXPECT_STREQ("", output.c_str());
675
676 argv[2] = "exit 1";
677 EXPECT_FALSE(base::GetAppOutput(CommandLine(argv), &output));
678 EXPECT_STREQ("", output.c_str());
679
680 argv[2] = "echo foobar42";
681 EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
682 EXPECT_STREQ("foobar42\n", output.c_str());
683#else
viettrungluu@chromium.org2090aa92010-07-28 13:02:34 +0900684 EXPECT_TRUE(base::GetAppOutput(CommandLine(FilePath("true")), &output));
phajdan.jr@chromium.org80fcf7d2009-04-17 18:57:52 +0900685 EXPECT_STREQ("", output.c_str());
686
viettrungluu@chromium.org2090aa92010-07-28 13:02:34 +0900687 EXPECT_FALSE(base::GetAppOutput(CommandLine(FilePath("false")), &output));
phajdan.jr@chromium.org80fcf7d2009-04-17 18:57:52 +0900688
689 std::vector<std::string> argv;
viettrungluu@chromium.org2090aa92010-07-28 13:02:34 +0900690 argv.push_back("/bin/echo");
691 argv.push_back("-n");
692 argv.push_back("foobar42");
693 EXPECT_TRUE(base::GetAppOutput(CommandLine(argv), &output));
694 EXPECT_STREQ("foobar42", output.c_str());
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900695#endif // defined(OS_ANDROID)
phajdan.jr@chromium.org80fcf7d2009-04-17 18:57:52 +0900696}
697
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900698TEST_F(ProcessUtilTest, GetAppOutputRestricted) {
699 // Unfortunately, since we can't rely on the path, we need to know where
700 // everything is. So let's use /bin/sh, which is on every POSIX system, and
701 // its built-ins.
702 std::vector<std::string> argv;
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900703 argv.push_back(std::string(kShellPath)); // argv[0]
704 argv.push_back("-c"); // argv[1]
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900705
706 // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of
707 // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we
708 // need absolute paths).
709 argv.push_back("exit 0"); // argv[2]; equivalent to "true"
710 std::string output = "abc";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900711 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900712 EXPECT_STREQ("", output.c_str());
713
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900714 argv[2] = "exit 1"; // equivalent to "false"
maruel@chromium.orga14b6ae2010-06-11 03:26:33 +0900715 output = "before";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900716 EXPECT_FALSE(base::GetAppOutputRestricted(CommandLine(argv),
maruel@chromium.orga14b6ae2010-06-11 03:26:33 +0900717 &output, 100));
718 EXPECT_STREQ("", output.c_str());
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900719
720 // Amount of output exactly equal to space allowed.
721 argv[2] = "echo 123456789"; // (the sh built-in doesn't take "-n")
722 output.clear();
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900723 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900724 EXPECT_STREQ("123456789\n", output.c_str());
725
726 // Amount of output greater than space allowed.
727 output.clear();
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900728 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 5));
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900729 EXPECT_STREQ("12345", output.c_str());
730
731 // Amount of output less than space allowed.
732 output.clear();
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900733 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 15));
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900734 EXPECT_STREQ("123456789\n", output.c_str());
735
736 // Zero space allowed.
737 output = "abc";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900738 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 0));
viettrungluu@chromium.orga7860722009-11-06 08:37:40 +0900739 EXPECT_STREQ("", output.c_str());
740}
741
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900742#if !(OS_MACOSX)
743// TODO(benwells): GetAppOutputRestricted should terminate applications
744// with SIGPIPE when we have enough output. http://crbug.com/88502
745TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) {
746 std::vector<std::string> argv;
747 std::string output;
748
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900749 argv.push_back(std::string(kShellPath)); // argv[0]
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900750 argv.push_back("-c");
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900751#if defined(OS_ANDROID)
752 argv.push_back("while echo 12345678901234567890; do :; done");
753 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
754 EXPECT_STREQ("1234567890", output.c_str());
755#else
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900756 argv.push_back("yes");
757 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
758 EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str());
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900759#endif
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900760}
761#endif
762
viettrungluu@chromium.orga85fb332010-01-05 01:17:13 +0900763TEST_F(ProcessUtilTest, GetAppOutputRestrictedNoZombies) {
764 std::vector<std::string> argv;
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900765
766 argv.push_back(std::string(kShellPath)); // argv[0]
767 argv.push_back("-c"); // argv[1]
viettrungluu@chromium.orga85fb332010-01-05 01:17:13 +0900768 argv.push_back("echo 123456789012345678901234567890"); // argv[2]
769
770 // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS
771 // 10.5) times with an output buffer big enough to capture all output.
772 for (int i = 0; i < 300; i++) {
773 std::string output;
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900774 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 100));
viettrungluu@chromium.orga85fb332010-01-05 01:17:13 +0900775 EXPECT_STREQ("123456789012345678901234567890\n", output.c_str());
776 }
777
778 // Ditto, but with an output buffer too small to capture all output.
779 for (int i = 0; i < 300; i++) {
780 std::string output;
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900781 EXPECT_TRUE(base::GetAppOutputRestricted(CommandLine(argv), &output, 10));
viettrungluu@chromium.orga85fb332010-01-05 01:17:13 +0900782 EXPECT_STREQ("1234567890", output.c_str());
783 }
784}
785
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900786TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
787 // Test getting output from a successful application.
788 std::vector<std::string> argv;
789 std::string output;
790 int exit_code;
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900791 argv.push_back(std::string(kShellPath)); // argv[0]
792 argv.push_back("-c"); // argv[1]
793 argv.push_back("echo foo"); // argv[2];
benwells@chromium.orge99fd2b2011-07-06 15:14:48 +0900794 EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
795 &exit_code));
796 EXPECT_STREQ("foo\n", output.c_str());
797 EXPECT_EQ(exit_code, 0);
798
799 // Test getting output from an application which fails with a specific exit
800 // code.
801 output.clear();
802 argv[2] = "echo foo; exit 2";
803 EXPECT_TRUE(base::GetAppOutputWithExitCode(CommandLine(argv), &output,
804 &exit_code));
805 EXPECT_STREQ("foo\n", output.c_str());
806 EXPECT_EQ(exit_code, 2);
807}
808
dkegel@google.com43c36742009-06-09 08:29:11 +0900809TEST_F(ProcessUtilTest, GetParentProcessId) {
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900810 base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
dkegel@google.com43c36742009-06-09 08:29:11 +0900811 EXPECT_EQ(ppid, getppid());
812}
evan@chromium.orgbcbd9402009-09-19 10:57:39 +0900813
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900814#if defined(OS_LINUX) || defined(OS_ANDROID)
evan@chromium.orgbcbd9402009-09-19 10:57:39 +0900815TEST_F(ProcessUtilTest, ParseProcStatCPU) {
816 // /proc/self/stat for a process running "top".
817 const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
818 "4202496 471 0 0 0 "
819 "12 16 0 0 " // <- These are the goods.
820 "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
821 "4246868 140733983044336 18446744073709551615 140244213071219 "
822 "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900823 EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat));
evan@chromium.orgbcbd9402009-09-19 10:57:39 +0900824
825 // cat /proc/self/stat on a random other machine I have.
826 const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
827 "0 142 0 0 0 "
828 "0 0 0 0 " // <- No CPU, apparently.
829 "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
830 "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
831
maruel@chromium.org9cf11e82010-04-30 02:44:42 +0900832 EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
evan@chromium.orgbcbd9402009-09-19 10:57:39 +0900833}
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900834#endif // defined(OS_LINUX) || defined(OS_ANDROID)
dkegel@google.com43c36742009-06-09 08:29:11 +0900835
jeremy@chromium.orgc5506fa2008-12-18 07:41:50 +0900836#endif // defined(OS_POSIX)
837
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900838// TODO(vandebo) make this work on Windows too.
839#if !defined(OS_WIN)
willchan@chromium.orgddcc5a42009-11-25 09:17:53 +0900840
thestig@chromium.orgc491b202010-02-26 09:31:08 +0900841#if defined(USE_TCMALLOC)
willchan@chromium.orgddcc5a42009-11-25 09:17:53 +0900842extern "C" {
843int tc_set_new_mode(int mode);
844}
thestig@chromium.orgc491b202010-02-26 09:31:08 +0900845#endif // defined(USE_TCMALLOC)
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900846
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900847// Android doesn't implement set_new_handler, so we can't use the
848// OutOfMemoryTest cases.
mark@chromium.org495e1ba2011-10-19 02:41:07 +0900849// OpenBSD does not support these tests either.
850#if !defined(OS_ANDROID) && !defined(OS_OPENBSD)
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900851class OutOfMemoryDeathTest : public testing::Test {
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900852 public:
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900853 OutOfMemoryDeathTest()
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900854 : value_(NULL),
855 // Make test size as large as possible minus a few pages so
856 // that alignment or other rounding doesn't make it wrap.
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900857 test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024),
858 signed_test_size_(std::numeric_limits<ssize_t>::max()) {
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900859 }
860
861 virtual void SetUp() {
thestig@chromium.orgc491b202010-02-26 09:31:08 +0900862#if defined(USE_TCMALLOC)
willchan@chromium.orgddcc5a42009-11-25 09:17:53 +0900863 tc_set_new_mode(1);
864 }
865
866 virtual void TearDown() {
867 tc_set_new_mode(0);
thestig@chromium.orgc491b202010-02-26 09:31:08 +0900868#endif // defined(USE_TCMALLOC)
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900869 }
870
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900871 void SetUpInDeathAssert() {
872 // Must call EnableTerminationOnOutOfMemory() because that is called from
873 // chrome's main function and therefore hasn't been called yet.
874 // Since this call may result in another thread being created and death
875 // tests shouldn't be started in a multithread environment, this call
876 // should be done inside of the ASSERT_DEATH.
877 base::EnableTerminationOnOutOfMemory();
878 }
879
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900880 void* value_;
881 size_t test_size_;
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900882 ssize_t signed_test_size_;
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900883};
884
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900885TEST_F(OutOfMemoryDeathTest, New) {
886 ASSERT_DEATH({
887 SetUpInDeathAssert();
888 value_ = operator new(test_size_);
889 }, "");
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900890}
891
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900892TEST_F(OutOfMemoryDeathTest, NewArray) {
893 ASSERT_DEATH({
894 SetUpInDeathAssert();
895 value_ = new char[test_size_];
896 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900897}
898
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900899TEST_F(OutOfMemoryDeathTest, Malloc) {
900 ASSERT_DEATH({
901 SetUpInDeathAssert();
902 value_ = malloc(test_size_);
903 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900904}
905
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900906TEST_F(OutOfMemoryDeathTest, Realloc) {
907 ASSERT_DEATH({
908 SetUpInDeathAssert();
909 value_ = realloc(NULL, test_size_);
910 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900911}
912
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900913TEST_F(OutOfMemoryDeathTest, Calloc) {
914 ASSERT_DEATH({
915 SetUpInDeathAssert();
916 value_ = calloc(1024, test_size_ / 1024L);
917 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900918}
919
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900920TEST_F(OutOfMemoryDeathTest, Valloc) {
921 ASSERT_DEATH({
922 SetUpInDeathAssert();
923 value_ = valloc(test_size_);
924 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900925}
926
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900927#if defined(OS_LINUX)
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900928TEST_F(OutOfMemoryDeathTest, Pvalloc) {
929 ASSERT_DEATH({
930 SetUpInDeathAssert();
931 value_ = pvalloc(test_size_);
932 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900933}
934
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900935TEST_F(OutOfMemoryDeathTest, Memalign) {
936 ASSERT_DEATH({
937 SetUpInDeathAssert();
938 value_ = memalign(4, test_size_);
939 }, "");
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900940}
941
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900942TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
agl@chromium.org37ec6ec2010-01-09 06:28:27 +0900943 // g_try_malloc is documented to return NULL on failure. (g_malloc is the
944 // 'safe' default that crashes if allocation fails). However, since we have
945 // hopefully overridden malloc, even g_try_malloc should fail. This tests
946 // that the run-time symbol resolution is overriding malloc for shared
947 // libraries as well as for our code.
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900948 ASSERT_DEATH({
949 SetUpInDeathAssert();
950 value_ = g_try_malloc(test_size_);
951 }, "");
agl@chromium.org37ec6ec2010-01-09 06:28:27 +0900952}
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900953#endif // OS_LINUX
vandebo@chromium.orga7a30982009-11-19 06:10:57 +0900954
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900955// Android doesn't implement posix_memalign().
956#if defined(OS_POSIX) && !defined(OS_ANDROID)
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900957TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
avi@chromium.org0cc39242010-05-20 05:23:46 +0900958 typedef int (*memalign_t)(void **, size_t, size_t);
959#if defined(OS_MACOSX)
960 // posix_memalign only exists on >= 10.6. Use dlsym to grab it at runtime
961 // because it may not be present in the SDK used for compilation.
962 memalign_t memalign =
963 reinterpret_cast<memalign_t>(dlsym(RTLD_DEFAULT, "posix_memalign"));
964#else
965 memalign_t memalign = posix_memalign;
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900966#endif // defined(OS_MACOSX)
avi@chromium.org0cc39242010-05-20 05:23:46 +0900967 if (memalign) {
968 // Grab the return value of posix_memalign to silence a compiler warning
969 // about unused return values. We don't actually care about the return
970 // value, since we're asserting death.
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900971 ASSERT_DEATH({
972 SetUpInDeathAssert();
973 EXPECT_EQ(ENOMEM, memalign(&value_, 8, test_size_));
974 }, "");
avi@chromium.org0cc39242010-05-20 05:23:46 +0900975 }
976}
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +0900977#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
avi@chromium.org0cc39242010-05-20 05:23:46 +0900978
avi@chromium.org4b9545a2010-03-20 03:42:41 +0900979#if defined(OS_MACOSX)
980
avi@chromium.org41d92e82010-07-02 05:11:43 +0900981// Purgeable zone tests (if it exists)
982
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900983TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
avi@chromium.org41d92e82010-07-02 05:11:43 +0900984 malloc_zone_t* zone = base::GetPurgeableZone();
985 if (zone)
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900986 ASSERT_DEATH({
987 SetUpInDeathAssert();
988 value_ = malloc_zone_malloc(zone, test_size_);
989 }, "");
avi@chromium.org41d92e82010-07-02 05:11:43 +0900990}
991
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900992TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
avi@chromium.org41d92e82010-07-02 05:11:43 +0900993 malloc_zone_t* zone = base::GetPurgeableZone();
994 if (zone)
levin@chromium.orgd18fb522010-08-24 07:44:01 +0900995 ASSERT_DEATH({
996 SetUpInDeathAssert();
997 value_ = malloc_zone_realloc(zone, NULL, test_size_);
998 }, "");
avi@chromium.org41d92e82010-07-02 05:11:43 +0900999}
1000
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001001TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
avi@chromium.org41d92e82010-07-02 05:11:43 +09001002 malloc_zone_t* zone = base::GetPurgeableZone();
1003 if (zone)
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001004 ASSERT_DEATH({
1005 SetUpInDeathAssert();
1006 value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
1007 }, "");
avi@chromium.org41d92e82010-07-02 05:11:43 +09001008}
1009
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001010TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
avi@chromium.org41d92e82010-07-02 05:11:43 +09001011 malloc_zone_t* zone = base::GetPurgeableZone();
1012 if (zone)
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001013 ASSERT_DEATH({
1014 SetUpInDeathAssert();
1015 value_ = malloc_zone_valloc(zone, test_size_);
1016 }, "");
avi@chromium.org41d92e82010-07-02 05:11:43 +09001017}
1018
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001019TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
avi@chromium.org41d92e82010-07-02 05:11:43 +09001020 malloc_zone_t* zone = base::GetPurgeableZone();
1021
1022 typedef void* (*zone_memalign_t)(malloc_zone_t*, size_t, size_t);
1023 // malloc_zone_memalign only exists on >= 10.6. Use dlsym to grab it at
1024 // runtime because it may not be present in the SDK used for compilation.
1025 zone_memalign_t zone_memalign =
1026 reinterpret_cast<zone_memalign_t>(
1027 dlsym(RTLD_DEFAULT, "malloc_zone_memalign"));
1028
1029 if (zone && zone_memalign) {
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001030 ASSERT_DEATH({
1031 SetUpInDeathAssert();
1032 value_ = zone_memalign(zone, 8, test_size_);
1033 }, "");
avi@chromium.org41d92e82010-07-02 05:11:43 +09001034 }
1035}
1036
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001037// Since these allocation functions take a signed size, it's possible that
mark@chromium.orgda40e1d2010-05-15 00:43:00 +09001038// calling them just once won't be enough to exhaust memory. In the 32-bit
1039// environment, it's likely that these allocation attempts will fail because
1040// not enough contiguous address space is availble. In the 64-bit environment,
1041// it's likely that they'll fail because they would require a preposterous
1042// amount of (virtual) memory.
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001043
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001044TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
1045 ASSERT_DEATH({
1046 SetUpInDeathAssert();
1047 while ((value_ =
1048 base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
1049 }, "");
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001050}
1051
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001052TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
1053 ASSERT_DEATH({
1054 SetUpInDeathAssert();
1055 while ((value_ =
1056 base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
1057 }, "");
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001058}
1059
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001060TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
1061 ASSERT_DEATH({
1062 SetUpInDeathAssert();
1063 while ((value_ =
1064 base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
1065 }, "");
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001066}
1067
mark@chromium.orgda40e1d2010-05-15 00:43:00 +09001068#if !defined(ARCH_CPU_64_BITS)
1069
1070// See process_util_unittest_mac.mm for an explanation of why this test isn't
1071// run in the 64-bit environment.
1072
levin@chromium.orgd18fb522010-08-24 07:44:01 +09001073TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
1074 ASSERT_DEATH({
1075 SetUpInDeathAssert();
1076 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
1077 }, "");
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001078}
1079
mark@chromium.orgda40e1d2010-05-15 00:43:00 +09001080#endif // !ARCH_CPU_64_BITS
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001081#endif // OS_MACOSX
1082
jingzhao@chromium.org1b42c242011-09-29 13:43:54 +09001083#endif // !defined(OS_ANDROID)
1084
avi@chromium.org4b9545a2010-03-20 03:42:41 +09001085#endif // !defined(OS_WIN)