scoped_handle_unittest.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <windows.h>
  5. #include <winternl.h>
  6. #include <string>
  7. #include <utility>
  8. #include "base/base_switches.h"
  9. #include "base/command_line.h"
  10. #include "base/files/file_path.h"
  11. #include "base/scoped_native_library.h"
  12. #include "base/test/multiprocess_test.h"
  13. #include "base/test/test_timeouts.h"
  14. #include "base/win/scoped_handle.h"
  15. #include "base/win/windows_version.h"
  16. #include "build/build_config.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. #include "testing/multiprocess_func_list.h"
  19. namespace base {
  20. namespace win {
  21. namespace {
  22. std::string FailureMessage(const std::string& msg) {
  23. #if !defined(DEBUG) && defined(OFFICIAL_BUILD)
  24. // Official release builds strip all fatal messages for saving binary size,
  25. // see base/check.h.
  26. return "";
  27. #else
  28. return msg;
  29. #endif // !defined(DEBUG) && defined(OFFICIAL_BUILD)
  30. }
  31. // Death tests don't seem to work on Windows 7 32-bit native with hooks enabled.
  32. bool DoDeathTestsWork() {
  33. #if defined(ARCH_CPU_32_BITS)
  34. const auto* os_info = base::win::OSInfo::GetInstance();
  35. if (os_info->version() <= base::win::Version::WIN7 &&
  36. os_info->IsWowDisabled()) {
  37. return false;
  38. }
  39. #endif // defined(ARCH_CPU_32_BITS)
  40. return true;
  41. }
  42. } // namespace
  43. namespace testing {
  44. extern "C" bool __declspec(dllexport) RunTest();
  45. } // namespace testing
  46. using ScopedHandleTest = ::testing::Test;
  47. using ScopedHandleDeathTest = ::testing::Test;
  48. TEST_F(ScopedHandleTest, ScopedHandle) {
  49. // Any illegal error code will do. We just need to test that it is preserved
  50. // by ScopedHandle to avoid https://crbug.com/528394.
  51. const DWORD magic_error = 0x12345678;
  52. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  53. // Call SetLastError after creating the handle.
  54. ::SetLastError(magic_error);
  55. base::win::ScopedHandle handle_holder(handle);
  56. EXPECT_EQ(magic_error, ::GetLastError());
  57. // Create a new handle and then set LastError again.
  58. handle = ::CreateMutex(nullptr, false, nullptr);
  59. ::SetLastError(magic_error);
  60. handle_holder.Set(handle);
  61. EXPECT_EQ(magic_error, ::GetLastError());
  62. // Create a new handle and then set LastError again.
  63. handle = ::CreateMutex(nullptr, false, nullptr);
  64. base::win::ScopedHandle handle_source(handle);
  65. ::SetLastError(magic_error);
  66. handle_holder = std::move(handle_source);
  67. EXPECT_EQ(magic_error, ::GetLastError());
  68. }
  69. TEST_F(ScopedHandleDeathTest, HandleVerifierTrackedHasBeenClosed) {
  70. // This test is only valid if hooks are enabled.
  71. if (!DoDeathTestsWork())
  72. return;
  73. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  74. ASSERT_NE(HANDLE(nullptr), handle);
  75. using NtCloseFunc = decltype(&::NtClose);
  76. NtCloseFunc ntclose = reinterpret_cast<NtCloseFunc>(
  77. GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtClose"));
  78. ASSERT_NE(nullptr, ntclose);
  79. ASSERT_DEATH(
  80. {
  81. base::win::ScopedHandle handle_holder(handle);
  82. ntclose(handle);
  83. // Destructing a ScopedHandle with an illegally closed handle should
  84. // fail.
  85. },
  86. FailureMessage("CloseHandle failed"));
  87. }
  88. TEST_F(ScopedHandleDeathTest, HandleVerifierCloseTrackedHandle) {
  89. // This test is only valid if hooks are enabled.
  90. if (!DoDeathTestsWork())
  91. return;
  92. ASSERT_DEATH(
  93. {
  94. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  95. ASSERT_NE(HANDLE(nullptr), handle);
  96. // Start tracking the handle so that closes outside of the checker are
  97. // caught.
  98. base::win::CheckedScopedHandle handle_holder(handle);
  99. // Closing a tracked handle using ::CloseHandle should crash due to hook
  100. // noticing the illegal close.
  101. ::CloseHandle(handle);
  102. },
  103. // This test must match the CloseHandleHook causing this failure, because
  104. // if the hook doesn't crash and instead the handle is double closed by
  105. // the `handle_holder` going out of scope, then there is still a crash,
  106. // but a different crash and one we are not explicitly testing here. This
  107. // other crash is tested in HandleVerifierTrackedHasBeenClosed above.
  108. FailureMessage("CloseHandleHook validation failure"));
  109. }
  110. TEST_F(ScopedHandleDeathTest, HandleVerifierDoubleTracking) {
  111. if (!DoDeathTestsWork())
  112. return;
  113. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  114. ASSERT_NE(HANDLE(nullptr), handle);
  115. base::win::CheckedScopedHandle handle_holder(handle);
  116. ASSERT_DEATH({ base::win::CheckedScopedHandle handle_holder2(handle); },
  117. FailureMessage("Handle Already Tracked"));
  118. }
  119. TEST_F(ScopedHandleDeathTest, HandleVerifierWrongOwner) {
  120. if (!DoDeathTestsWork())
  121. return;
  122. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  123. ASSERT_NE(HANDLE(nullptr), handle);
  124. base::win::CheckedScopedHandle handle_holder(handle);
  125. ASSERT_DEATH(
  126. {
  127. base::win::CheckedScopedHandle handle_holder2;
  128. handle_holder2.handle_ = handle;
  129. },
  130. FailureMessage("Closing a handle owned by something else"));
  131. ASSERT_TRUE(handle_holder.is_valid());
  132. handle_holder.Close();
  133. }
  134. TEST_F(ScopedHandleDeathTest, HandleVerifierUntrackedHandle) {
  135. if (!DoDeathTestsWork())
  136. return;
  137. HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
  138. ASSERT_NE(HANDLE(nullptr), handle);
  139. ASSERT_DEATH(
  140. {
  141. base::win::CheckedScopedHandle handle_holder;
  142. handle_holder.handle_ = handle;
  143. },
  144. FailureMessage("Closing an untracked handle"));
  145. ASSERT_TRUE(::CloseHandle(handle));
  146. }
  147. // Under ASan, the multi-process test crashes during process shutdown for
  148. // unknown reasons. Disable it for now. http://crbug.com/685262
  149. #if defined(ADDRESS_SANITIZER)
  150. #define MAYBE_MultiProcess DISABLED_MultiProcess
  151. #else
  152. #define MAYBE_MultiProcess MultiProcess
  153. #endif
  154. TEST_F(ScopedHandleTest, MAYBE_MultiProcess) {
  155. // Initializing ICU in the child process causes a scoped handle to be created
  156. // before the test gets a chance to test the race condition, so disable ICU
  157. // for the child process here.
  158. CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine());
  159. command_line.AppendSwitch(switches::kTestDoNotInitializeIcu);
  160. base::Process test_child_process = base::SpawnMultiProcessTestChild(
  161. "HandleVerifierChildProcess", command_line, LaunchOptions());
  162. int rv = -1;
  163. ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
  164. TestTimeouts::action_timeout(), &rv));
  165. EXPECT_EQ(0, rv);
  166. }
  167. MULTIPROCESS_TEST_MAIN(HandleVerifierChildProcess) {
  168. ScopedNativeLibrary module(
  169. FilePath(FILE_PATH_LITERAL("scoped_handle_test_dll.dll")));
  170. if (!module.is_valid())
  171. return 1;
  172. auto run_test_function = reinterpret_cast<decltype(&testing::RunTest)>(
  173. module.GetFunctionPointer("RunTest"));
  174. if (!run_test_function)
  175. return 1;
  176. if (!run_test_function())
  177. return 1;
  178. return 0;
  179. }
  180. } // namespace win
  181. } // namespace base