Protect WebURLLoaderImpl::Context while receiving responses.
[chromium-blink-merge.git] / base / process_util_win.cc
blob7119004d7ef61ca1de114b97c03aca0ed9204192
1 // Copyright (c) 2012 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.
5 #include "base/process_util.h"
7 #include <fcntl.h>
8 #include <io.h>
9 #include <windows.h>
10 #include <userenv.h>
11 #include <psapi.h>
13 #include <ios>
15 #include "base/bind.h"
16 #include "base/bind_helpers.h"
17 #include "base/command_line.h"
18 #include "base/debug/stack_trace.h"
19 #include "base/logging.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "base/message_loop.h"
22 #include "base/metrics/histogram.h"
23 #include "base/sys_info.h"
24 #include "base/win/object_watcher.h"
25 #include "base/win/scoped_handle.h"
26 #include "base/win/scoped_process_information.h"
27 #include "base/win/windows_version.h"
29 // userenv.dll is required for CreateEnvironmentBlock().
30 #pragma comment(lib, "userenv.lib")
32 namespace base {
34 namespace {
36 // Exit codes with special meanings on Windows.
37 const DWORD kNormalTerminationExitCode = 0;
38 const DWORD kDebuggerInactiveExitCode = 0xC0000354;
39 const DWORD kKeyboardInterruptExitCode = 0xC000013A;
40 const DWORD kDebuggerTerminatedExitCode = 0x40010004;
42 // Maximum amount of time (in milliseconds) to wait for the process to exit.
43 static const int kWaitInterval = 2000;
45 // This exit code is used by the Windows task manager when it kills a
46 // process. It's value is obviously not that unique, and it's
47 // surprising to me that the task manager uses this value, but it
48 // seems to be common practice on Windows to test for it as an
49 // indication that the task manager has killed something if the
50 // process goes away.
51 const DWORD kProcessKilledExitCode = 1;
53 // HeapSetInformation function pointer.
54 typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
56 void OnNoMemory() {
57 // Kill the process. This is important for security, since WebKit doesn't
58 // NULL-check many memory allocations. If a malloc fails, returns NULL, and
59 // the buffer is then used, it provides a handy mapping of memory starting at
60 // address 0 for an attacker to utilize.
61 __debugbreak();
62 _exit(1);
65 class TimerExpiredTask : public win::ObjectWatcher::Delegate {
66 public:
67 explicit TimerExpiredTask(ProcessHandle process);
68 ~TimerExpiredTask();
70 void TimedOut();
72 // MessageLoop::Watcher -----------------------------------------------------
73 virtual void OnObjectSignaled(HANDLE object);
75 private:
76 void KillProcess();
78 // The process that we are watching.
79 ProcessHandle process_;
81 win::ObjectWatcher watcher_;
83 DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
86 TimerExpiredTask::TimerExpiredTask(ProcessHandle process) : process_(process) {
87 watcher_.StartWatching(process_, this);
90 TimerExpiredTask::~TimerExpiredTask() {
91 TimedOut();
92 DCHECK(!process_) << "Make sure to close the handle.";
95 void TimerExpiredTask::TimedOut() {
96 if (process_)
97 KillProcess();
100 void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
101 CloseHandle(process_);
102 process_ = NULL;
105 void TimerExpiredTask::KillProcess() {
106 // Stop watching the process handle since we're killing it.
107 watcher_.StopWatching();
109 // OK, time to get frisky. We don't actually care when the process
110 // terminates. We just care that it eventually terminates, and that's what
111 // TerminateProcess should do for us. Don't check for the result code since
112 // it fails quite often. This should be investigated eventually.
113 base::KillProcess(process_, kProcessKilledExitCode, false);
115 // Now, just cleanup as if the process exited normally.
116 OnObjectSignaled(process_);
119 } // namespace
121 void RouteStdioToConsole() {
122 // Don't change anything if stdout or stderr already point to a
123 // valid stream.
125 // If we are running under Buildbot or under Cygwin's default
126 // terminal (mintty), stderr and stderr will be pipe handles. In
127 // that case, we don't want to open CONOUT$, because its output
128 // likely does not go anywhere.
130 // We don't use GetStdHandle() to check stdout/stderr here because
131 // it can return dangling IDs of handles that were never inherited
132 // by this process. These IDs could have been reused by the time
133 // this function is called. The CRT checks the validity of
134 // stdout/stderr on startup (before the handle IDs can be reused).
135 // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was
136 // invalid.
137 if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0)
138 return;
140 if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
141 unsigned int result = GetLastError();
142 // Was probably already attached.
143 if (result == ERROR_ACCESS_DENIED)
144 return;
145 // Don't bother creating a new console for each child process if the
146 // parent process is invalid (eg: crashed).
147 if (result == ERROR_GEN_FAILURE)
148 return;
149 // Make a new console if attaching to parent fails with any other error.
150 // It should be ERROR_INVALID_HANDLE at this point, which means the browser
151 // was likely not started from a console.
152 AllocConsole();
155 // Arbitrary byte count to use when buffering output lines. More
156 // means potential waste, less means more risk of interleaved
157 // log-lines in output.
158 enum { kOutputBufferSize = 64 * 1024 };
160 if (freopen("CONOUT$", "w", stdout)) {
161 setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize);
162 // Overwrite FD 1 for the benefit of any code that uses this FD
163 // directly. This is safe because the CRT allocates FDs 0, 1 and
164 // 2 at startup even if they don't have valid underlying Windows
165 // handles. This means we won't be overwriting an FD created by
166 // _open() after startup.
167 _dup2(_fileno(stdout), 1);
169 if (freopen("CONOUT$", "w", stderr)) {
170 setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize);
171 _dup2(_fileno(stderr), 2);
174 // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
175 std::ios::sync_with_stdio();
178 ProcessId GetCurrentProcId() {
179 return ::GetCurrentProcessId();
182 ProcessHandle GetCurrentProcessHandle() {
183 return ::GetCurrentProcess();
186 HMODULE GetModuleFromAddress(void* address) {
187 HMODULE instance = NULL;
188 if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
189 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
190 static_cast<char*>(address),
191 &instance)) {
192 NOTREACHED();
194 return instance;
197 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
198 // We try to limit privileges granted to the handle. If you need this
199 // for test code, consider using OpenPrivilegedProcessHandle instead of
200 // adding more privileges here.
201 ProcessHandle result = OpenProcess(PROCESS_TERMINATE |
202 PROCESS_QUERY_INFORMATION |
203 SYNCHRONIZE,
204 FALSE, pid);
206 if (result == NULL)
207 return false;
209 *handle = result;
210 return true;
213 bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
214 ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
215 PROCESS_TERMINATE |
216 PROCESS_QUERY_INFORMATION |
217 PROCESS_VM_READ |
218 SYNCHRONIZE,
219 FALSE, pid);
221 if (result == NULL)
222 return false;
224 *handle = result;
225 return true;
228 bool OpenProcessHandleWithAccess(ProcessId pid,
229 uint32 access_flags,
230 ProcessHandle* handle) {
231 ProcessHandle result = OpenProcess(access_flags, FALSE, pid);
233 if (result == NULL)
234 return false;
236 *handle = result;
237 return true;
240 void CloseProcessHandle(ProcessHandle process) {
241 CloseHandle(process);
244 ProcessId GetProcId(ProcessHandle process) {
245 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
246 HANDLE current_process = GetCurrentProcess();
247 HANDLE process_with_query_rights;
248 if (DuplicateHandle(current_process, process, current_process,
249 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
250 false, 0)) {
251 DWORD id = GetProcessId(process_with_query_rights);
252 CloseHandle(process_with_query_rights);
253 return id;
256 // We're screwed.
257 NOTREACHED();
258 return 0;
261 bool GetProcessIntegrityLevel(ProcessHandle process, IntegrityLevel *level) {
262 if (!level)
263 return false;
265 if (win::GetVersion() < base::win::VERSION_VISTA)
266 return false;
268 HANDLE process_token;
269 if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE,
270 &process_token))
271 return false;
273 win::ScopedHandle scoped_process_token(process_token);
275 DWORD token_info_length = 0;
276 if (GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
277 &token_info_length) ||
278 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
279 return false;
281 scoped_ptr<char[]> token_label_bytes(new char[token_info_length]);
282 if (!token_label_bytes.get())
283 return false;
285 TOKEN_MANDATORY_LABEL* token_label =
286 reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
287 if (!token_label)
288 return false;
290 if (!GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
291 token_info_length, &token_info_length))
292 return false;
294 DWORD integrity_level = *GetSidSubAuthority(token_label->Label.Sid,
295 (DWORD)(UCHAR)(*GetSidSubAuthorityCount(token_label->Label.Sid)-1));
297 if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
298 *level = LOW_INTEGRITY;
299 } else if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
300 integrity_level < SECURITY_MANDATORY_HIGH_RID) {
301 *level = MEDIUM_INTEGRITY;
302 } else if (integrity_level >= SECURITY_MANDATORY_HIGH_RID) {
303 *level = HIGH_INTEGRITY;
304 } else {
305 NOTREACHED();
306 return false;
309 return true;
312 bool LaunchProcess(const string16& cmdline,
313 const LaunchOptions& options,
314 ProcessHandle* process_handle) {
315 STARTUPINFO startup_info = {};
316 startup_info.cb = sizeof(startup_info);
317 if (options.empty_desktop_name)
318 startup_info.lpDesktop = L"";
319 startup_info.dwFlags = STARTF_USESHOWWINDOW;
320 startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
322 if (options.stdin_handle || options.stdout_handle || options.stderr_handle) {
323 DCHECK(options.inherit_handles);
324 DCHECK(options.stdin_handle);
325 DCHECK(options.stdout_handle);
326 DCHECK(options.stderr_handle);
327 startup_info.dwFlags |= STARTF_USESTDHANDLES;
328 startup_info.hStdInput = options.stdin_handle;
329 startup_info.hStdOutput = options.stdout_handle;
330 startup_info.hStdError = options.stderr_handle;
333 DWORD flags = 0;
335 if (options.job_handle) {
336 flags |= CREATE_SUSPENDED;
338 // If this code is run under a debugger, the launched process is
339 // automatically associated with a job object created by the debugger.
340 // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
341 flags |= CREATE_BREAKAWAY_FROM_JOB;
344 if (options.force_breakaway_from_job_)
345 flags |= CREATE_BREAKAWAY_FROM_JOB;
347 base::win::ScopedProcessInformation process_info;
349 if (options.as_user) {
350 flags |= CREATE_UNICODE_ENVIRONMENT;
351 void* enviroment_block = NULL;
353 if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) {
354 DPLOG(ERROR);
355 return false;
358 BOOL launched =
359 CreateProcessAsUser(options.as_user, NULL,
360 const_cast<wchar_t*>(cmdline.c_str()),
361 NULL, NULL, options.inherit_handles, flags,
362 enviroment_block, NULL, &startup_info,
363 process_info.Receive());
364 DestroyEnvironmentBlock(enviroment_block);
365 if (!launched) {
366 DPLOG(ERROR);
367 return false;
369 } else {
370 if (!CreateProcess(NULL,
371 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
372 options.inherit_handles, flags, NULL, NULL,
373 &startup_info, process_info.Receive())) {
374 DPLOG(ERROR);
375 return false;
379 if (options.job_handle) {
380 if (0 == AssignProcessToJobObject(options.job_handle,
381 process_info.process_handle())) {
382 DLOG(ERROR) << "Could not AssignProcessToObject.";
383 KillProcess(process_info.process_handle(), kProcessKilledExitCode, true);
384 return false;
387 ResumeThread(process_info.thread_handle());
390 if (options.wait)
391 WaitForSingleObject(process_info.process_handle(), INFINITE);
393 // If the caller wants the process handle, we won't close it.
394 if (process_handle)
395 *process_handle = process_info.TakeProcessHandle();
397 return true;
400 bool LaunchProcess(const CommandLine& cmdline,
401 const LaunchOptions& options,
402 ProcessHandle* process_handle) {
403 return LaunchProcess(cmdline.GetCommandLineString(), options, process_handle);
406 bool SetJobObjectAsKillOnJobClose(HANDLE job_object) {
407 JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
408 limit_info.BasicLimitInformation.LimitFlags =
409 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
410 return 0 != SetInformationJobObject(
411 job_object,
412 JobObjectExtendedLimitInformation,
413 &limit_info,
414 sizeof(limit_info));
417 // Attempts to kill the process identified by the given process
418 // entry structure, giving it the specified exit code.
419 // Returns true if this is successful, false otherwise.
420 bool KillProcessById(ProcessId process_id, int exit_code, bool wait) {
421 HANDLE process = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE,
422 FALSE, // Don't inherit handle
423 process_id);
424 if (!process) {
425 DLOG_GETLASTERROR(ERROR) << "Unable to open process " << process_id;
426 return false;
428 bool ret = KillProcess(process, exit_code, wait);
429 CloseHandle(process);
430 return ret;
433 bool GetAppOutput(const CommandLine& cl, std::string* output) {
434 HANDLE out_read = NULL;
435 HANDLE out_write = NULL;
437 SECURITY_ATTRIBUTES sa_attr;
438 // Set the bInheritHandle flag so pipe handles are inherited.
439 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
440 sa_attr.bInheritHandle = TRUE;
441 sa_attr.lpSecurityDescriptor = NULL;
443 // Create the pipe for the child process's STDOUT.
444 if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
445 NOTREACHED() << "Failed to create pipe";
446 return false;
449 // Ensure we don't leak the handles.
450 win::ScopedHandle scoped_out_read(out_read);
451 win::ScopedHandle scoped_out_write(out_write);
453 // Ensure the read handle to the pipe for STDOUT is not inherited.
454 if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
455 NOTREACHED() << "Failed to disabled pipe inheritance";
456 return false;
459 FilePath::StringType writable_command_line_string(cl.GetCommandLineString());
461 base::win::ScopedProcessInformation proc_info;
462 STARTUPINFO start_info = { 0 };
464 start_info.cb = sizeof(STARTUPINFO);
465 start_info.hStdOutput = out_write;
466 // Keep the normal stdin and stderr.
467 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
468 start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
469 start_info.dwFlags |= STARTF_USESTDHANDLES;
471 // Create the child process.
472 if (!CreateProcess(NULL,
473 &writable_command_line_string[0],
474 NULL, NULL,
475 TRUE, // Handles are inherited.
476 0, NULL, NULL, &start_info, proc_info.Receive())) {
477 NOTREACHED() << "Failed to start process";
478 return false;
481 // Close our writing end of pipe now. Otherwise later read would not be able
482 // to detect end of child's output.
483 scoped_out_write.Close();
485 // Read output from the child process's pipe for STDOUT
486 const int kBufferSize = 1024;
487 char buffer[kBufferSize];
489 for (;;) {
490 DWORD bytes_read = 0;
491 BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
492 if (!success || bytes_read == 0)
493 break;
494 output->append(buffer, bytes_read);
497 // Let's wait for the process to finish.
498 WaitForSingleObject(proc_info.process_handle(), INFINITE);
500 return true;
503 bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
504 bool result = (TerminateProcess(process, exit_code) != FALSE);
505 if (result && wait) {
506 // The process may not end immediately due to pending I/O
507 if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
508 DLOG_GETLASTERROR(ERROR) << "Error waiting for process exit";
509 } else if (!result) {
510 DLOG_GETLASTERROR(ERROR) << "Unable to terminate process";
512 return result;
515 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
516 DWORD tmp_exit_code = 0;
518 if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
519 DLOG_GETLASTERROR(FATAL) << "GetExitCodeProcess() failed";
520 if (exit_code) {
521 // This really is a random number. We haven't received any
522 // information about the exit code, presumably because this
523 // process doesn't have permission to get the exit code, or
524 // because of some other cause for GetExitCodeProcess to fail
525 // (MSDN docs don't give the possible failure error codes for
526 // this function, so it could be anything). But we don't want
527 // to leave exit_code uninitialized, since that could cause
528 // random interpretations of the exit code. So we assume it
529 // terminated "normally" in this case.
530 *exit_code = kNormalTerminationExitCode;
532 // Assume the child has exited normally if we can't get the exit
533 // code.
534 return TERMINATION_STATUS_NORMAL_TERMINATION;
536 if (tmp_exit_code == STILL_ACTIVE) {
537 DWORD wait_result = WaitForSingleObject(handle, 0);
538 if (wait_result == WAIT_TIMEOUT) {
539 if (exit_code)
540 *exit_code = wait_result;
541 return TERMINATION_STATUS_STILL_RUNNING;
544 if (wait_result == WAIT_FAILED) {
545 DLOG_GETLASTERROR(ERROR) << "WaitForSingleObject() failed";
546 } else {
547 DCHECK_EQ(WAIT_OBJECT_0, wait_result);
549 // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
550 NOTREACHED();
553 return TERMINATION_STATUS_ABNORMAL_TERMINATION;
556 if (exit_code)
557 *exit_code = tmp_exit_code;
559 switch (tmp_exit_code) {
560 case kNormalTerminationExitCode:
561 return TERMINATION_STATUS_NORMAL_TERMINATION;
562 case kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE.
563 case kKeyboardInterruptExitCode: // Control-C/end session.
564 case kDebuggerTerminatedExitCode: // Debugger terminated process.
565 case kProcessKilledExitCode: // Task manager kill.
566 return TERMINATION_STATUS_PROCESS_WAS_KILLED;
567 default:
568 // All other exit codes indicate crashes.
569 return TERMINATION_STATUS_PROCESS_CRASHED;
573 bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
574 bool success = WaitForExitCodeWithTimeout(
575 handle, exit_code, base::TimeDelta::FromMilliseconds(INFINITE));
576 CloseProcessHandle(handle);
577 return success;
580 bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code,
581 base::TimeDelta timeout) {
582 if (::WaitForSingleObject(handle, timeout.InMilliseconds()) != WAIT_OBJECT_0)
583 return false;
584 DWORD temp_code; // Don't clobber out-parameters in case of failure.
585 if (!::GetExitCodeProcess(handle, &temp_code))
586 return false;
588 *exit_code = temp_code;
589 return true;
592 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
593 base::TimeDelta wait,
594 const ProcessFilter* filter) {
595 const ProcessEntry* entry;
596 bool result = true;
597 DWORD start_time = GetTickCount();
599 NamedProcessIterator iter(executable_name, filter);
600 while ((entry = iter.NextProcessEntry())) {
601 DWORD remaining_wait = std::max<int64>(
602 0, wait.InMilliseconds() - (GetTickCount() - start_time));
603 HANDLE process = OpenProcess(SYNCHRONIZE,
604 FALSE,
605 entry->th32ProcessID);
606 DWORD wait_result = WaitForSingleObject(process, remaining_wait);
607 CloseHandle(process);
608 result = result && (wait_result == WAIT_OBJECT_0);
611 return result;
614 bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
615 int exit_code;
616 if (!WaitForExitCodeWithTimeout(handle, &exit_code, wait))
617 return false;
618 return exit_code == 0;
621 bool CleanupProcesses(const FilePath::StringType& executable_name,
622 base::TimeDelta wait,
623 int exit_code,
624 const ProcessFilter* filter) {
625 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
626 if (!exited_cleanly)
627 KillProcesses(executable_name, exit_code, filter);
628 return exited_cleanly;
631 void EnsureProcessTerminated(ProcessHandle process) {
632 DCHECK(process != GetCurrentProcess());
634 // If already signaled, then we are done!
635 if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
636 CloseHandle(process);
637 return;
640 MessageLoop::current()->PostDelayedTask(
641 FROM_HERE,
642 base::Bind(&TimerExpiredTask::TimedOut,
643 base::Owned(new TimerExpiredTask(process))),
644 base::TimeDelta::FromMilliseconds(kWaitInterval));
647 bool EnableLowFragmentationHeap() {
648 HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
649 HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
650 kernel32,
651 "HeapSetInformation"));
653 // On Windows 2000, the function is not exported. This is not a reason to
654 // fail.
655 if (!heap_set)
656 return true;
658 unsigned number_heaps = GetProcessHeaps(0, NULL);
659 if (!number_heaps)
660 return false;
662 // Gives us some extra space in the array in case a thread is creating heaps
663 // at the same time we're querying them.
664 static const int MARGIN = 8;
665 scoped_ptr<HANDLE[]> heaps(new HANDLE[number_heaps + MARGIN]);
666 number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
667 if (!number_heaps)
668 return false;
670 for (unsigned i = 0; i < number_heaps; ++i) {
671 ULONG lfh_flag = 2;
672 // Don't bother with the result code. It may fails on heaps that have the
673 // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
674 heap_set(heaps[i],
675 HeapCompatibilityInformation,
676 &lfh_flag,
677 sizeof(lfh_flag));
679 return true;
682 void EnableTerminationOnHeapCorruption() {
683 // Ignore the result code. Supported on XP SP3 and Vista.
684 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
687 void EnableTerminationOnOutOfMemory() {
688 std::set_new_handler(&OnNoMemory);
691 void RaiseProcessToHighPriority() {
692 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
695 } // namespace base