// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/win/startup_information.h"
#include <windows.h>
#include <stddef.h>
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/win/scoped_handle.h"
#include "base/win/scoped_process_information.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class ScopedProcessTerminator {
public:
explicit ScopedProcessTerminator(const PROCESS_INFORMATION& process_info)
: process_info_(process_info) {}
ScopedProcessTerminator(const ScopedProcessTerminator&) = delete;
ScopedProcessTerminator& operator=(const ScopedProcessTerminator&) = delete;
~ScopedProcessTerminator() {
if (process_info_.IsValid())
::TerminateProcess(process_info_.process_handle(), 0);
}
private:
base::win::ScopedProcessInformation process_info_;
};
base::win::ScopedHandle CreateInheritedHandle() {
HANDLE handle;
if (!::DuplicateHandle(::GetCurrentProcess(), ::GetCurrentProcess(),
::GetCurrentProcess(), &handle,
PROCESS_QUERY_LIMITED_INFORMATION, TRUE, 0)) {
return base::win::ScopedHandle();
}
return base::win::ScopedHandle(handle);
}
bool CheckInheritedHandle(HANDLE process, HANDLE check_handle) {
HANDLE temp_handle;
if (!::DuplicateHandle(process, check_handle, ::GetCurrentProcess(),
&temp_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
return false;
}
base::win::ScopedHandle dup_handle(temp_handle);
return ::GetProcessId(temp_handle) == ::GetCurrentProcessId();
}
} // namespace
// Verify that only the explicitly specified process handle is inherited.
TEST(StartupInformationTest, InheritStdOut) {
base::win::ScopedHandle handle_0 = CreateInheritedHandle();
ASSERT_TRUE(handle_0.is_valid());
base::win::ScopedHandle handle_1 = CreateInheritedHandle();
ASSERT_TRUE(handle_1.is_valid());
ASSERT_NE(handle_0.get(), handle_1.get());
base::win::StartupInformation startup_info;
ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1));
HANDLE inherit_process = handle_0.get();
ASSERT_TRUE(startup_info.UpdateProcThreadAttribute(
PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &inherit_process,
sizeof(inherit_process)));
base::FilePath exe_path;
ASSERT_TRUE(base::PathService::Get(base::FILE_EXE, &exe_path));
WCHAR cmd_line[] = L"dummy";
PROCESS_INFORMATION temp_process_info = {};
ASSERT_TRUE(::CreateProcess(
exe_path.value().c_str(), cmd_line, nullptr, nullptr, TRUE,
EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED, nullptr, nullptr,
startup_info.startup_info(), &temp_process_info))
<< ::GetLastError();
ScopedProcessTerminator process(temp_process_info);
EXPECT_TRUE(CheckInheritedHandle(temp_process_info.hProcess, handle_0.get()));
EXPECT_FALSE(
CheckInheritedHandle(temp_process_info.hProcess, handle_1.get()));
}