Home | History | Annotate | Download | only in base
      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