// Copyright 2016 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/win/base_win_buildflags.h" #include "base/win/current_module.h" #include "base/win/scoped_handle.h" #include "base/win/scoped_handle_verifier.h" namespace base { namespace win { namespace testing { extern "C" bool __declspec(dllexport) RunTest(); namespace { struct ThreadParams { HANDLE ready_event; HANDLE start_event; }; // Note, this must use all native functions to avoid instantiating the // HandleVerifier. e.g. can't use base::Thread or even base::PlatformThread. DWORD __stdcall ThreadFunc(void* params) { ThreadParams* thread_params = reinterpret_cast(params); HANDLE handle = ::CreateMutex(nullptr, false, nullptr); ::SetEvent(thread_params->ready_event); ::WaitForSingleObject(thread_params->start_event, INFINITE); CheckedScopedHandle handle_holder(handle); return 0; } bool InternalRunThreadTest() { std::vector threads_; // From manual testing, the bug fixed by crrev.com/678736a starts reliably // causing handle verifier asserts to trigger at around 100 threads, so make // it 200 to be sure to detect any future regressions. const size_t kNumThreads = 200; // bManualReset is set to true to allow signalling multiple threads. HANDLE start_event = ::CreateEvent(nullptr, true, false, nullptr); if (!start_event) return false; HANDLE ready_event = CreateEvent(nullptr, false, false, nullptr); if (!ready_event) return false; ThreadParams thread_params = {ready_event, start_event}; for (size_t i = 0; i < kNumThreads; i++) { HANDLE thread_handle = ::CreateThread(nullptr, 0, ThreadFunc, reinterpret_cast(&thread_params), 0, nullptr); if (!thread_handle) break; ::WaitForSingleObject(ready_event, INFINITE); threads_.push_back(thread_handle); } ::CloseHandle(ready_event); if (threads_.size() != kNumThreads) { for (auto* thread : threads_) ::CloseHandle(thread); ::CloseHandle(start_event); return false; } ::SetEvent(start_event); ::CloseHandle(start_event); for (auto* thread : threads_) { ::WaitForSingleObject(thread, INFINITE); ::CloseHandle(thread); } return true; } bool InternalRunLocationTest() { // Create a new handle and then set LastError again. HANDLE handle = ::CreateMutex(nullptr, false, nullptr); if (!handle) return false; CheckedScopedHandle handle_holder(handle); HMODULE verifier_module = base::win::internal::GetHandleVerifierModuleForTesting(); if (!verifier_module) return false; // Get my module HMODULE my_module = CURRENT_MODULE(); if (!my_module) return false; HMODULE main_module = ::GetModuleHandle(nullptr); #if BUILDFLAG(SINGLE_MODULE_MODE_HANDLE_VERIFIER) // In a component build HandleVerifier will always be created inside base.dll // as the code always lives there. if (verifier_module == my_module || verifier_module == main_module) return false; #else // In a non-component build, HandleVerifier should always be created in the // version of base linked with the main executable. if (verifier_module == my_module || verifier_module != main_module) return false; #endif return true; } } // namespace bool RunTest() { return InternalRunThreadTest() && InternalRunLocationTest(); } } // namespace testing } // namespace win } // namespace base