summaryrefslogtreecommitdiffstats
path: root/chromium/base/process/kill_win.cc
blob: 3b85dea1cd4cd0b0008e6673987921483103043d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process/kill.h"

#include <algorithm>

#include <windows.h>
#include <io.h>
#include <stdint.h>

#include "base/logging.h"
#include "base/macros.h"
#include "base/process/memory.h"
#include "base/process/process_iterator.h"

namespace base {

TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
  DCHECK(exit_code);

  DWORD tmp_exit_code = 0;

  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
    DPLOG(FATAL) << "GetExitCodeProcess() failed";

    // This really is a random number.  We haven't received any
    // information about the exit code, presumably because this
    // process doesn't have permission to get the exit code, or
    // because of some other cause for GetExitCodeProcess to fail
    // (MSDN docs don't give the possible failure error codes for
    // this function, so it could be anything).  But we don't want
    // to leave exit_code uninitialized, since that could cause
    // random interpretations of the exit code.  So we assume it
    // terminated "normally" in this case.
    *exit_code = win::kNormalTerminationExitCode;

    // Assume the child has exited normally if we can't get the exit
    // code.
    return TERMINATION_STATUS_NORMAL_TERMINATION;
  }
  if (tmp_exit_code == STILL_ACTIVE) {
    DWORD wait_result = WaitForSingleObject(handle, 0);
    if (wait_result == WAIT_TIMEOUT) {
      *exit_code = wait_result;
      return TERMINATION_STATUS_STILL_RUNNING;
    }

    if (wait_result == WAIT_FAILED) {
      DPLOG(ERROR) << "WaitForSingleObject() failed";
    } else {
      DCHECK_EQ(WAIT_OBJECT_0, wait_result);

      // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
      NOTREACHED();
    }

    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
  }

  *exit_code = tmp_exit_code;

  // clang-format off
  switch (tmp_exit_code) {
    case win::kNormalTerminationExitCode:
      return TERMINATION_STATUS_NORMAL_TERMINATION;
    case win::kDebuggerInactiveExitCode:    // STATUS_DEBUGGER_INACTIVE.
    case win::kKeyboardInterruptExitCode:   // Control-C/end session.
    case win::kDebuggerTerminatedExitCode:  // Debugger terminated process.
    case win::kProcessKilledExitCode:       // Task manager kill.
      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
    case win::kSandboxFatalMemoryExceeded:  // Terminated process due to
                                            // exceeding the sandbox job
                                            // object memory limits.
    case win::kOomExceptionCode:            // Ran out of memory.
      return TERMINATION_STATUS_OOM;
    // This exit code means the process failed an OS integrity check.
    // This is tested in ProcessMitigationsTest.* in sandbox.
    case win::kStatusInvalidImageHashExitCode:
      return TERMINATION_STATUS_INTEGRITY_FAILURE;
    default:
      // All other exit codes indicate crashes.
      return TERMINATION_STATUS_PROCESS_CRASHED;
  }
  // clang-format on
}

bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
                            TimeDelta wait,
                            const ProcessFilter* filter) {
  bool result = true;
  DWORD start_time = GetTickCount();

  NamedProcessIterator iter(executable_name, filter);
  for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
       entry = iter.NextProcessEntry()) {
    DWORD remaining_wait = static_cast<DWORD>(
        std::max(static_cast<int64_t>(0),
                 wait.InMilliseconds() - (GetTickCount() - start_time)));
    HANDLE process = OpenProcess(SYNCHRONIZE,
                                 FALSE,
                                 entry->th32ProcessID);
    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
    CloseHandle(process);
    result &= (wait_result == WAIT_OBJECT_0);
  }

  return result;
}

bool CleanupProcesses(const FilePath::StringType& executable_name,
                      TimeDelta wait,
                      int exit_code,
                      const ProcessFilter* filter) {
  if (WaitForProcessesToExit(executable_name, wait, filter))
    return true;
  KillProcesses(executable_name, exit_code, filter);
  return false;
}

}  // namespace base