1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/process/kill.h"
6
7 #include <windows.h>
8
9 #include <io.h>
10 #include <stdint.h>
11
12 #include <algorithm>
13
14 #include "base/logging.h"
15 #include "base/notreached.h"
16 #include "base/process/memory.h"
17 #include "base/process/process_iterator.h"
18
19 namespace base {
20
GetTerminationStatus(ProcessHandle handle,int * exit_code)21 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
22 DCHECK(exit_code);
23
24 DWORD tmp_exit_code = 0;
25
26 if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
27 DPLOG(FATAL) << "GetExitCodeProcess() failed";
28
29 // This really is a random number. We haven't received any
30 // information about the exit code, presumably because this
31 // process doesn't have permission to get the exit code, or
32 // because of some other cause for GetExitCodeProcess to fail
33 // (MSDN docs don't give the possible failure error codes for
34 // this function, so it could be anything). But we don't want
35 // to leave exit_code uninitialized, since that could cause
36 // random interpretations of the exit code. So we assume it
37 // terminated "normally" in this case.
38 *exit_code = win::kNormalTerminationExitCode;
39
40 // Assume the child has exited normally if we can't get the exit
41 // code.
42 return TERMINATION_STATUS_NORMAL_TERMINATION;
43 }
44 if (tmp_exit_code == STILL_ACTIVE) {
45 DWORD wait_result = WaitForSingleObject(handle, 0);
46 if (wait_result == WAIT_TIMEOUT) {
47 *exit_code = static_cast<int>(wait_result);
48 return TERMINATION_STATUS_STILL_RUNNING;
49 }
50
51 if (wait_result == WAIT_FAILED) {
52 DPLOG(ERROR) << "WaitForSingleObject() failed";
53 *exit_code = static_cast<int>(wait_result);
54 } else {
55 DCHECK_EQ(WAIT_OBJECT_0, wait_result);
56 DLOG(ERROR) << "The process used 0x103 (STILL_ACTIVE) as exit code.";
57 *exit_code = static_cast<int>(tmp_exit_code);
58 }
59
60 return TERMINATION_STATUS_ABNORMAL_TERMINATION;
61 }
62
63 *exit_code = static_cast<int>(tmp_exit_code);
64
65 // clang-format off
66 switch (tmp_exit_code) {
67 case win::kNormalTerminationExitCode:
68 return TERMINATION_STATUS_NORMAL_TERMINATION;
69 case win::kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE.
70 case win::kKeyboardInterruptExitCode: // Control-C/end session.
71 case win::kDebuggerTerminatedExitCode: // Debugger terminated process.
72 case win::kProcessKilledExitCode: // Task manager kill.
73 return TERMINATION_STATUS_PROCESS_WAS_KILLED;
74 case win::kSandboxFatalMemoryExceeded: // Terminated process due to
75 // exceeding the sandbox job
76 // object memory limits.
77 case win::kOomExceptionCode: // Ran out of memory.
78 return TERMINATION_STATUS_OOM;
79 // This exit code means the process failed an OS integrity check.
80 // This is tested in ProcessMitigationsTest.* in sandbox.
81 case win::kStatusInvalidImageHashExitCode:
82 return TERMINATION_STATUS_INTEGRITY_FAILURE;
83 default:
84 // All other exit codes indicate crashes.
85 return TERMINATION_STATUS_PROCESS_CRASHED;
86 }
87 // clang-format on
88 }
89
WaitForProcessesToExit(const FilePath::StringType & executable_name,TimeDelta wait,const ProcessFilter * filter)90 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
91 TimeDelta wait,
92 const ProcessFilter* filter) {
93 bool result = true;
94 DWORD start_time = GetTickCount();
95
96 NamedProcessIterator iter(executable_name, filter);
97 for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
98 entry = iter.NextProcessEntry()) {
99 DWORD remaining_wait = static_cast<DWORD>(
100 std::max(static_cast<int64_t>(0),
101 wait.InMilliseconds() - (GetTickCount() - start_time)));
102 HANDLE process = OpenProcess(SYNCHRONIZE,
103 FALSE,
104 entry->th32ProcessID);
105 DWORD wait_result = WaitForSingleObject(process, remaining_wait);
106 CloseHandle(process);
107 result &= (wait_result == WAIT_OBJECT_0);
108 }
109
110 return result;
111 }
112
CleanupProcesses(const FilePath::StringType & executable_name,TimeDelta wait,int exit_code,const ProcessFilter * filter)113 bool CleanupProcesses(const FilePath::StringType& executable_name,
114 TimeDelta wait,
115 int exit_code,
116 const ProcessFilter* filter) {
117 if (WaitForProcessesToExit(executable_name, wait, filter))
118 return true;
119 KillProcesses(executable_name, exit_code, filter);
120 return false;
121 }
122
123 } // namespace base
124