blob: ca6fb451a876e3e249ae8526f083bcc7ce0f0ec3 [file] [log] [blame]
// 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