|  | // Copyright (c) 2011 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 <windows.h> | 
|  | #include <winternl.h> | 
|  |  | 
|  | #include "base/base_switches.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/scoped_native_library.h" | 
|  | #include "base/test/multiprocess_test.h" | 
|  | #include "base/test/test_timeouts.h" | 
|  | #include "base/win/scoped_handle.h" | 
|  |  | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "testing/multiprocess_func_list.h" | 
|  |  | 
|  | namespace base { | 
|  | namespace win { | 
|  |  | 
|  | namespace testing { | 
|  | extern "C" bool __declspec(dllexport) RunTest(); | 
|  | }  // namespace testing | 
|  |  | 
|  | TEST(ScopedHandleTest, ScopedHandle) { | 
|  | // Any illegal error code will do. We just need to test that it is preserved | 
|  | // by ScopedHandle to avoid bug 528394. | 
|  | const DWORD magic_error = 0x12345678; | 
|  |  | 
|  | HANDLE handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | // Call SetLastError after creating the handle. | 
|  | ::SetLastError(magic_error); | 
|  | base::win::ScopedHandle handle_holder(handle); | 
|  | EXPECT_EQ(magic_error, ::GetLastError()); | 
|  |  | 
|  | // Create a new handle and then set LastError again. | 
|  | handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | ::SetLastError(magic_error); | 
|  | handle_holder.Set(handle); | 
|  | EXPECT_EQ(magic_error, ::GetLastError()); | 
|  |  | 
|  | // Create a new handle and then set LastError again. | 
|  | handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | base::win::ScopedHandle handle_source(handle); | 
|  | ::SetLastError(magic_error); | 
|  | handle_holder = std::move(handle_source); | 
|  | EXPECT_EQ(magic_error, ::GetLastError()); | 
|  | } | 
|  |  | 
|  | TEST(ScopedHandleTest, ActiveVerifierTrackedHasBeenClosed) { | 
|  | HANDLE handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | ASSERT_NE(HANDLE(nullptr), handle); | 
|  | typedef NTSTATUS(WINAPI * NtCloseFunc)(HANDLE); | 
|  | NtCloseFunc ntclose = reinterpret_cast<NtCloseFunc>( | 
|  | GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtClose")); | 
|  | ASSERT_NE(nullptr, ntclose); | 
|  |  | 
|  | ASSERT_DEATH({ | 
|  | base::win::ScopedHandle handle_holder(handle); | 
|  | ntclose(handle); | 
|  | // Destructing a ScopedHandle with an illegally closed handle should fail. | 
|  | }, ""); | 
|  | } | 
|  |  | 
|  | TEST(ScopedHandleTest, ActiveVerifierDoubleTracking) { | 
|  | HANDLE handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | ASSERT_NE(HANDLE(nullptr), handle); | 
|  |  | 
|  | base::win::ScopedHandle handle_holder(handle); | 
|  |  | 
|  | ASSERT_DEATH({ | 
|  | base::win::ScopedHandle handle_holder2(handle); | 
|  | }, ""); | 
|  | } | 
|  |  | 
|  | TEST(ScopedHandleTest, ActiveVerifierWrongOwner) { | 
|  | HANDLE handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | ASSERT_NE(HANDLE(nullptr), handle); | 
|  |  | 
|  | base::win::ScopedHandle handle_holder(handle); | 
|  | ASSERT_DEATH({ | 
|  | base::win::ScopedHandle handle_holder2; | 
|  | handle_holder2.handle_ = handle; | 
|  | }, ""); | 
|  | ASSERT_TRUE(handle_holder.IsValid()); | 
|  | handle_holder.Close(); | 
|  | } | 
|  |  | 
|  | TEST(ScopedHandleTest, ActiveVerifierUntrackedHandle) { | 
|  | HANDLE handle = ::CreateMutex(nullptr, false, nullptr); | 
|  | ASSERT_NE(HANDLE(nullptr), handle); | 
|  |  | 
|  | ASSERT_DEATH({ | 
|  | base::win::ScopedHandle handle_holder; | 
|  | handle_holder.handle_ = handle; | 
|  | }, ""); | 
|  |  | 
|  | ASSERT_TRUE(::CloseHandle(handle)); | 
|  | } | 
|  |  | 
|  | // Under ASan, the multi-process test crashes during process shutdown for | 
|  | // unknown reasons. Disable it for now. http://crbug.com/685262 | 
|  | #if defined(ADDRESS_SANITIZER) | 
|  | #define MAYBE_MultiProcess DISABLED_MultiProcess | 
|  | #else | 
|  | #define MAYBE_MultiProcess MultiProcess | 
|  | #endif | 
|  |  | 
|  | TEST(ScopedHandleTest, MAYBE_MultiProcess) { | 
|  | // Initializing ICU in the child process causes a scoped handle to be created | 
|  | // before the test gets a chance to test the race condition, so disable ICU | 
|  | // for the child process here. | 
|  | CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine()); | 
|  | command_line.AppendSwitch(switches::kTestDoNotInitializeIcu); | 
|  |  | 
|  | base::Process test_child_process = base::SpawnMultiProcessTestChild( | 
|  | "ActiveVerifierChildProcess", command_line, LaunchOptions()); | 
|  |  | 
|  | int rv = -1; | 
|  | ASSERT_TRUE(test_child_process.WaitForExitWithTimeout( | 
|  | TestTimeouts::action_timeout(), &rv)); | 
|  | EXPECT_EQ(0, rv); | 
|  | } | 
|  |  | 
|  | MULTIPROCESS_TEST_MAIN(ActiveVerifierChildProcess) { | 
|  | ScopedNativeLibrary module(FilePath(L"scoped_handle_test_dll.dll")); | 
|  |  | 
|  | if (!module.is_valid()) | 
|  | return 1; | 
|  | auto run_test_function = reinterpret_cast<decltype(&testing::RunTest)>( | 
|  | module.GetFunctionPointer("RunTest")); | 
|  | if (!run_test_function) | 
|  | return 1; | 
|  | if (!run_test_function()) | 
|  | return 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | }  // namespace win | 
|  | }  // namespace base |