1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #define _CRT_SECURE_NO_WARNINGS 6 7 #include <limits> 8 9 #include "base/command_line.h" 10 #include "base/eintr_wrapper.h" 11 #include "base/file_path.h" 12 #include "base/multiprocess_test.h" 13 #include "base/path_service.h" 14 #include "base/platform_thread.h" 15 #include "base/process_util.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 #if defined(OS_LINUX) 19 #include <dlfcn.h> 20 #include <errno.h> 21 #include <malloc.h> 22 #include <glib.h> 23 #endif 24 #if defined(OS_POSIX) 25 #include <fcntl.h> 26 #include <sys/resource.h> 27 #include <sys/socket.h> 28 #endif 29 #if defined(OS_WIN) 30 #include <windows.h> 31 #endif 32 33 namespace base { 34 35 class ProcessUtilTest : public MultiProcessTest { 36 #if defined(OS_POSIX) 37 public: 38 // Spawn a child process that counts how many file descriptors are open. 39 int CountOpenFDsInChild(); 40 #endif 41 }; 42 43 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { 44 return 0; 45 } 46 47 TEST_F(ProcessUtilTest, SpawnChild) { 48 ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess"); 49 50 ASSERT_NE(base::kNullProcessHandle, handle); 51 EXPECT_TRUE(WaitForSingleProcess(handle, 5000)); 52 base::CloseProcessHandle(handle); 53 } 54 55 MULTIPROCESS_TEST_MAIN(SlowChildProcess) { 56 // Sleep until file "SlowChildProcess.die" is created. 57 FILE *fp; 58 do { 59 PlatformThread::Sleep(100); 60 fp = fopen("SlowChildProcess.die", "r"); 61 } while (!fp); 62 fclose(fp); 63 remove("SlowChildProcess.die"); 64 exit(0); 65 return 0; 66 } 67 68 TEST_F(ProcessUtilTest, KillSlowChild) { 69 remove("SlowChildProcess.die"); 70 ProcessHandle handle = this->SpawnChild(L"SlowChildProcess"); 71 ASSERT_NE(base::kNullProcessHandle, handle); 72 FILE *fp = fopen("SlowChildProcess.die", "w"); 73 fclose(fp); 74 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 75 base::CloseProcessHandle(handle); 76 } 77 78 // Ensure that the priority of a process is restored correctly after 79 // backgrounding and restoring. 80 // Note: a platform may not be willing or able to lower the priority of 81 // a process. The calls to SetProcessBackground should be noops then. 82 TEST_F(ProcessUtilTest, SetProcessBackgrounded) { 83 ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess"); 84 Process process(handle); 85 int old_priority = process.GetPriority(); 86 process.SetProcessBackgrounded(true); 87 process.SetProcessBackgrounded(false); 88 int new_priority = process.GetPriority(); 89 EXPECT_EQ(old_priority, new_priority); 90 } 91 92 // TODO(estade): if possible, port these 2 tests. 93 #if defined(OS_WIN) 94 TEST_F(ProcessUtilTest, EnableLFH) { 95 ASSERT_TRUE(EnableLowFragmentationHeap()); 96 if (IsDebuggerPresent()) { 97 // Under these conditions, LFH can't be enabled. There's no point to test 98 // anything. 99 const char* no_debug_env = getenv("_NO_DEBUG_HEAP"); 100 if (!no_debug_env || strcmp(no_debug_env, "1")) 101 return; 102 } 103 HANDLE heaps[1024] = { 0 }; 104 unsigned number_heaps = GetProcessHeaps(1024, heaps); 105 EXPECT_GT(number_heaps, 0u); 106 for (unsigned i = 0; i < number_heaps; ++i) { 107 ULONG flag = 0; 108 SIZE_T length; 109 ASSERT_NE(0, HeapQueryInformation(heaps[i], 110 HeapCompatibilityInformation, 111 &flag, 112 sizeof(flag), 113 &length)); 114 // If flag is 0, the heap is a standard heap that does not support 115 // look-asides. If flag is 1, the heap supports look-asides. If flag is 2, 116 // the heap is a low-fragmentation heap (LFH). Note that look-asides are not 117 // supported on the LFH. 118 119 // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag. 120 EXPECT_LE(flag, 2u); 121 EXPECT_NE(flag, 1u); 122 } 123 } 124 125 TEST_F(ProcessUtilTest, CalcFreeMemory) { 126 ProcessMetrics* metrics = 127 ProcessMetrics::CreateProcessMetrics(::GetCurrentProcess()); 128 ASSERT_TRUE(NULL != metrics); 129 130 // Typical values here is ~1900 for total and ~1000 for largest. Obviously 131 // it depends in what other tests have done to this process. 132 FreeMBytes free_mem1 = {0}; 133 EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem1)); 134 EXPECT_LT(10u, free_mem1.total); 135 EXPECT_LT(10u, free_mem1.largest); 136 EXPECT_GT(2048u, free_mem1.total); 137 EXPECT_GT(2048u, free_mem1.largest); 138 EXPECT_GE(free_mem1.total, free_mem1.largest); 139 EXPECT_TRUE(NULL != free_mem1.largest_ptr); 140 141 // Allocate 20M and check again. It should have gone down. 142 const int kAllocMB = 20; 143 char* alloc = new char[kAllocMB * 1024 * 1024]; 144 EXPECT_TRUE(NULL != alloc); 145 146 size_t expected_total = free_mem1.total - kAllocMB; 147 size_t expected_largest = free_mem1.largest; 148 149 FreeMBytes free_mem2 = {0}; 150 EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem2)); 151 EXPECT_GE(free_mem2.total, free_mem2.largest); 152 EXPECT_GE(expected_total, free_mem2.total); 153 EXPECT_GE(expected_largest, free_mem2.largest); 154 EXPECT_TRUE(NULL != free_mem2.largest_ptr); 155 156 delete[] alloc; 157 delete metrics; 158 } 159 160 TEST_F(ProcessUtilTest, GetAppOutput) { 161 // Let's create a decently long message. 162 std::string message; 163 for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte 164 // boundary. 165 message += "Hello!"; 166 } 167 168 FilePath python_runtime; 169 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime)); 170 python_runtime = python_runtime.Append(FILE_PATH_LITERAL("third_party")) 171 .Append(FILE_PATH_LITERAL("python_24")) 172 .Append(FILE_PATH_LITERAL("python.exe")); 173 174 CommandLine cmd_line(python_runtime); 175 cmd_line.AppendLooseValue(L"-c"); 176 cmd_line.AppendLooseValue(L"\"import sys; sys.stdout.write('" + 177 ASCIIToWide(message) + L"');\""); 178 std::string output; 179 ASSERT_TRUE(base::GetAppOutput(cmd_line, &output)); 180 EXPECT_EQ(message, output); 181 182 // Let's make sure stderr is ignored. 183 CommandLine other_cmd_line(python_runtime); 184 other_cmd_line.AppendLooseValue(L"-c"); 185 other_cmd_line.AppendLooseValue( 186 L"\"import sys; sys.stderr.write('Hello!');\""); 187 output.clear(); 188 ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output)); 189 EXPECT_EQ("", output); 190 } 191 192 TEST_F(ProcessUtilTest, LaunchAsUser) { 193 base::UserTokenHandle token; 194 ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); 195 std::wstring cmdline = 196 this->MakeCmdLine(L"SimpleChildProcess", false).command_line_string(); 197 EXPECT_TRUE(base::LaunchAppAsUser(token, cmdline, false, NULL)); 198 } 199 200 #endif // defined(OS_WIN) 201 202 #if defined(OS_POSIX) 203 // Returns the maximum number of files that a process can have open. 204 // Returns 0 on error. 205 int GetMaxFilesOpenInProcess() { 206 struct rlimit rlim; 207 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { 208 return 0; 209 } 210 211 // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints 212 // which are all 32 bits on the supported platforms. 213 rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max()); 214 if (rlim.rlim_cur > max_int) { 215 return max_int; 216 } 217 218 return rlim.rlim_cur; 219 } 220 221 const int kChildPipe = 20; // FD # for write end of pipe in child process. 222 MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) { 223 // This child process counts the number of open FDs, it then writes that 224 // number out to a pipe connected to the parent. 225 int num_open_files = 0; 226 int write_pipe = kChildPipe; 227 int max_files = GetMaxFilesOpenInProcess(); 228 for (int i = STDERR_FILENO + 1; i < max_files; i++) { 229 if (i != kChildPipe) { 230 int fd; 231 if ((fd = HANDLE_EINTR(dup(i))) != -1) { 232 close(fd); 233 num_open_files += 1; 234 } 235 } 236 } 237 238 int written = HANDLE_EINTR(write(write_pipe, &num_open_files, 239 sizeof(num_open_files))); 240 DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files)); 241 int ret = HANDLE_EINTR(close(write_pipe)); 242 DPCHECK(ret == 0); 243 244 return 0; 245 } 246 247 int ProcessUtilTest::CountOpenFDsInChild() { 248 int fds[2]; 249 if (pipe(fds) < 0) 250 NOTREACHED(); 251 252 file_handle_mapping_vector fd_mapping_vec; 253 fd_mapping_vec.push_back(std::pair<int,int>(fds[1], kChildPipe)); 254 ProcessHandle handle = this->SpawnChild(L"ProcessUtilsLeakFDChildProcess", 255 fd_mapping_vec, 256 false); 257 CHECK(handle); 258 int ret = HANDLE_EINTR(close(fds[1])); 259 DPCHECK(ret == 0); 260 261 // Read number of open files in client process from pipe; 262 int num_open_files = -1; 263 ssize_t bytes_read = 264 HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files))); 265 CHECK(bytes_read == static_cast<ssize_t>(sizeof(num_open_files))); 266 267 CHECK(WaitForSingleProcess(handle, 1000)); 268 base::CloseProcessHandle(handle); 269 ret = HANDLE_EINTR(close(fds[0])); 270 DPCHECK(ret == 0); 271 272 return num_open_files; 273 } 274 275 TEST_F(ProcessUtilTest, FDRemapping) { 276 int fds_before = CountOpenFDsInChild(); 277 278 // open some dummy fds to make sure they don't propogate over to the 279 // child process. 280 int dev_null = open("/dev/null", O_RDONLY); 281 int sockets[2]; 282 socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); 283 284 int fds_after = CountOpenFDsInChild(); 285 286 ASSERT_EQ(fds_after, fds_before); 287 288 int ret; 289 ret = HANDLE_EINTR(close(sockets[0])); 290 DPCHECK(ret == 0); 291 ret = HANDLE_EINTR(close(sockets[1])); 292 DPCHECK(ret == 0); 293 ret = HANDLE_EINTR(close(dev_null)); 294 DPCHECK(ret == 0); 295 } 296 297 TEST_F(ProcessUtilTest, GetAppOutput) { 298 std::string output; 299 EXPECT_TRUE(GetAppOutput(CommandLine(FilePath("true")), &output)); 300 EXPECT_STREQ("", output.c_str()); 301 302 EXPECT_FALSE(GetAppOutput(CommandLine(FilePath("false")), &output)); 303 304 std::vector<std::string> argv; 305 argv.push_back("/bin/echo"); 306 argv.push_back("-n"); 307 argv.push_back("foobar42"); 308 EXPECT_TRUE(GetAppOutput(CommandLine(argv), &output)); 309 EXPECT_STREQ("foobar42", output.c_str()); 310 } 311 312 TEST_F(ProcessUtilTest, GetAppOutputRestricted) { 313 // Unfortunately, since we can't rely on the path, we need to know where 314 // everything is. So let's use /bin/sh, which is on every POSIX system, and 315 // its built-ins. 316 std::vector<std::string> argv; 317 argv.push_back("/bin/sh"); // argv[0] 318 argv.push_back("-c"); // argv[1] 319 320 // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of 321 // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we 322 // need absolute paths). 323 argv.push_back("exit 0"); // argv[2]; equivalent to "true" 324 std::string output = "abc"; 325 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 100)); 326 EXPECT_STREQ("", output.c_str()); 327 328 // On failure, should not touch |output|. As above, but for |false|. 329 argv[2] = "exit 1"; // equivalent to "false" 330 output = "abc"; 331 EXPECT_FALSE(GetAppOutputRestricted(CommandLine(argv), 332 &output, 100)); 333 EXPECT_STREQ("abc", output.c_str()); 334 335 // Amount of output exactly equal to space allowed. 336 argv[2] = "echo 123456789"; // (the sh built-in doesn't take "-n") 337 output.clear(); 338 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 10)); 339 EXPECT_STREQ("123456789\n", output.c_str()); 340 341 // Amount of output greater than space allowed. 342 output.clear(); 343 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 5)); 344 EXPECT_STREQ("12345", output.c_str()); 345 346 // Amount of output less than space allowed. 347 output.clear(); 348 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 15)); 349 EXPECT_STREQ("123456789\n", output.c_str()); 350 351 // Zero space allowed. 352 output = "abc"; 353 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 0)); 354 EXPECT_STREQ("", output.c_str()); 355 } 356 357 TEST_F(ProcessUtilTest, GetAppOutputRestrictedNoZombies) { 358 std::vector<std::string> argv; 359 argv.push_back("/bin/sh"); // argv[0] 360 argv.push_back("-c"); // argv[1] 361 argv.push_back("echo 123456789012345678901234567890"); // argv[2] 362 363 // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS 364 // 10.5) times with an output buffer big enough to capture all output. 365 for (int i = 0; i < 300; i++) { 366 std::string output; 367 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 100)); 368 EXPECT_STREQ("123456789012345678901234567890\n", output.c_str()); 369 } 370 371 // Ditto, but with an output buffer too small to capture all output. 372 for (int i = 0; i < 300; i++) { 373 std::string output; 374 EXPECT_TRUE(GetAppOutputRestricted(CommandLine(argv), &output, 10)); 375 EXPECT_STREQ("1234567890", output.c_str()); 376 } 377 } 378 379 #if defined(OS_LINUX) 380 TEST_F(ProcessUtilTest, GetParentProcessId) { 381 base::ProcessId ppid = GetParentProcessId(GetCurrentProcId()); 382 EXPECT_EQ(ppid, getppid()); 383 } 384 385 TEST_F(ProcessUtilTest, ParseProcStatCPU) { 386 // /proc/self/stat for a process running "top". 387 const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 " 388 "4202496 471 0 0 0 " 389 "12 16 0 0 " // <- These are the goods. 390 "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 " 391 "4246868 140733983044336 18446744073709551615 140244213071219 " 392 "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0"; 393 EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat)); 394 395 // cat /proc/self/stat on a random other machine I have. 396 const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 " 397 "0 142 0 0 0 " 398 "0 0 0 0 " // <- No CPU, apparently. 399 "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 " 400 "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0"; 401 402 EXPECT_EQ(0, ParseProcStatCPU(kSelfStat)); 403 } 404 #endif 405 406 #endif // defined(OS_POSIX) 407 408 // TODO(vandebo) make this work on Windows and Mac too. 409 #if defined(OS_LINUX) 410 411 #if defined(LINUX_USE_TCMALLOC) 412 extern "C" { 413 int tc_set_new_mode(int mode); 414 } 415 #endif // defined(LINUX_USE_TCMALLOC) 416 417 class OutOfMemoryTest : public testing::Test { 418 public: 419 OutOfMemoryTest() 420 : value_(NULL), 421 // Make test size as large as possible minus a few pages so 422 // that alignment or other rounding doesn't make it wrap. 423 test_size_(std::numeric_limits<std::size_t>::max() - 8192) { 424 } 425 426 virtual void SetUp() { 427 // Must call EnableTerminationOnOutOfMemory() because that is called from 428 // chrome's main function and therefore hasn't been called yet. 429 EnableTerminationOnOutOfMemory(); 430 #if defined(LINUX_USE_TCMALLOC) 431 tc_set_new_mode(1); 432 } 433 434 virtual void TearDown() { 435 tc_set_new_mode(0); 436 #endif // defined(LINUX_USE_TCMALLOC) 437 } 438 439 void* value_; 440 size_t test_size_; 441 }; 442 443 TEST_F(OutOfMemoryTest, New) { 444 ASSERT_DEATH(value_ = new char[test_size_], ""); 445 } 446 447 TEST_F(OutOfMemoryTest, Malloc) { 448 ASSERT_DEATH(value_ = malloc(test_size_), ""); 449 } 450 451 TEST_F(OutOfMemoryTest, Realloc) { 452 ASSERT_DEATH(value_ = realloc(NULL, test_size_), ""); 453 } 454 455 TEST_F(OutOfMemoryTest, Calloc) { 456 ASSERT_DEATH(value_ = calloc(1024, test_size_ / 1024L), ""); 457 } 458 459 TEST_F(OutOfMemoryTest, Valloc) { 460 ASSERT_DEATH(value_ = valloc(test_size_), ""); 461 } 462 463 TEST_F(OutOfMemoryTest, Pvalloc) { 464 ASSERT_DEATH(value_ = pvalloc(test_size_), ""); 465 } 466 467 TEST_F(OutOfMemoryTest, Memalign) { 468 ASSERT_DEATH(value_ = memalign(4, test_size_), ""); 469 } 470 471 TEST_F(OutOfMemoryTest, ViaSharedLibraries) { 472 // g_try_malloc is documented to return NULL on failure. (g_malloc is the 473 // 'safe' default that crashes if allocation fails). However, since we have 474 // hopefully overridden malloc, even g_try_malloc should fail. This tests 475 // that the run-time symbol resolution is overriding malloc for shared 476 // libraries as well as for our code. 477 ASSERT_DEATH(value_ = g_try_malloc(test_size_), ""); 478 } 479 480 481 TEST_F(OutOfMemoryTest, Posix_memalign) { 482 // Grab the return value of posix_memalign to silence a compiler warning 483 // about unused return values. We don't actually care about the return 484 // value, since we're asserting death. 485 ASSERT_DEATH(EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_)), ""); 486 } 487 488 #endif // defined(OS_LINUX) 489 490 } // namespace base 491