// 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 #include #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( 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)); } TEST(ScopedHandleTest, 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( module.GetFunctionPointer("RunTest")); if (!run_test_function) return 1; if (!run_test_function()) return 1; return 0; } } // namespace win } // namespace base