xref: /aosp_15_r20/external/cronet/base/win/scoped_handle_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/win/scoped_handle.h"
6 
7 #include <windows.h>
8 
9 #include <winternl.h>
10 
11 #include <string>
12 #include <utility>
13 
14 #include "base/command_line.h"
15 #include "base/files/file_path.h"
16 #include "base/scoped_native_library.h"
17 #include "base/test/multiprocess_test.h"
18 #include "base/test/test_timeouts.h"
19 #include "build/build_config.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/multiprocess_func_list.h"
22 
23 namespace base {
24 namespace win {
25 
26 namespace {
27 
FailureMessage(const std::string & msg)28 std::string FailureMessage(const std::string& msg) {
29 #if defined(NDEBUG) && defined(OFFICIAL_BUILD)
30   // Official release builds strip all fatal messages for saving binary size,
31   // see base/check.h.
32   return "";
33 #else
34   return msg;
35 #endif  // defined(NDEBUG) && defined(OFFICIAL_BUILD)
36 }
37 
38 }  // namespace
39 
40 namespace testing {
41 extern "C" bool __declspec(dllexport) RunTest();
42 }  // namespace testing
43 
44 using ScopedHandleTest = ::testing::Test;
45 using ScopedHandleDeathTest = ::testing::Test;
46 
TEST_F(ScopedHandleTest,ScopedHandle)47 TEST_F(ScopedHandleTest, ScopedHandle) {
48   // Any illegal error code will do. We just need to test that it is preserved
49   // by ScopedHandle to avoid https://crbug.com/528394.
50   const DWORD magic_error = 0x12345678;
51 
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 
58   // Create a new handle and then set LastError again.
59   handle = ::CreateMutex(nullptr, false, nullptr);
60   ::SetLastError(magic_error);
61   handle_holder.Set(handle);
62   EXPECT_EQ(magic_error, ::GetLastError());
63 
64   // Create a new handle and then set LastError again.
65   handle = ::CreateMutex(nullptr, false, nullptr);
66   base::win::ScopedHandle handle_source(handle);
67   ::SetLastError(magic_error);
68   handle_holder = std::move(handle_source);
69   EXPECT_EQ(magic_error, ::GetLastError());
70 }
71 
TEST_F(ScopedHandleDeathTest,HandleVerifierTrackedHasBeenClosed)72 TEST_F(ScopedHandleDeathTest, HandleVerifierTrackedHasBeenClosed) {
73   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
74   ASSERT_NE(HANDLE(nullptr), handle);
75 
76   ASSERT_DEATH(
77       {
78         base::win::ScopedHandle handle_holder(handle);
79         ::NtClose(handle);
80         // Destructing a ScopedHandle with an illegally closed handle should
81         // fail.
82       },
83       FailureMessage("CloseHandle failed"));
84 }
85 
TEST_F(ScopedHandleDeathTest,HandleVerifierCloseTrackedHandle)86 TEST_F(ScopedHandleDeathTest, HandleVerifierCloseTrackedHandle) {
87   ASSERT_DEATH(
88       {
89         HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
90         ASSERT_NE(HANDLE(nullptr), handle);
91 
92         // Start tracking the handle so that closes outside of the checker are
93         // caught.
94         base::win::CheckedScopedHandle handle_holder(handle);
95 
96         // Closing a tracked handle using ::CloseHandle should crash due to hook
97         // noticing the illegal close.
98         ::CloseHandle(handle);
99       },
100       // This test must match the CloseHandleHook causing this failure, because
101       // if the hook doesn't crash and instead the handle is double closed by
102       // the `handle_holder` going out of scope, then there is still a crash,
103       // but a different crash and one we are not explicitly testing here. This
104       // other crash is tested in HandleVerifierTrackedHasBeenClosed above.
105       FailureMessage("CloseHandleHook validation failure"));
106 }
107 
TEST_F(ScopedHandleDeathTest,HandleVerifierDoubleTracking)108 TEST_F(ScopedHandleDeathTest, HandleVerifierDoubleTracking) {
109   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
110   ASSERT_NE(HANDLE(nullptr), handle);
111 
112   base::win::CheckedScopedHandle handle_holder(handle);
113 
114   ASSERT_DEATH({ base::win::CheckedScopedHandle handle_holder2(handle); },
115                FailureMessage("Handle Already Tracked"));
116 }
117 
TEST_F(ScopedHandleDeathTest,HandleVerifierWrongOwner)118 TEST_F(ScopedHandleDeathTest, HandleVerifierWrongOwner) {
119   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
120   ASSERT_NE(HANDLE(nullptr), handle);
121 
122   base::win::CheckedScopedHandle handle_holder(handle);
123   ASSERT_DEATH(
124       {
125         base::win::CheckedScopedHandle handle_holder2;
126         handle_holder2.handle_ = handle;
127       },
128       FailureMessage("Closing a handle owned by something else"));
129   ASSERT_TRUE(handle_holder.is_valid());
130   handle_holder.Close();
131 }
132 
TEST_F(ScopedHandleDeathTest,HandleVerifierUntrackedHandle)133 TEST_F(ScopedHandleDeathTest, HandleVerifierUntrackedHandle) {
134   HANDLE handle = ::CreateMutex(nullptr, false, nullptr);
135   ASSERT_NE(HANDLE(nullptr), handle);
136 
137   ASSERT_DEATH(
138       {
139         base::win::CheckedScopedHandle handle_holder;
140         handle_holder.handle_ = handle;
141       },
142       FailureMessage("Closing an untracked handle"));
143 
144   ASSERT_TRUE(::CloseHandle(handle));
145 }
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 TEST_F(ScopedHandleTest, MAYBE_MultiProcess) {
156   CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine());
157 
158   base::Process test_child_process = base::SpawnMultiProcessTestChild(
159       "HandleVerifierChildProcess", command_line, LaunchOptions());
160 
161   int rv = -1;
162   ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
163       TestTimeouts::action_timeout(), &rv));
164   EXPECT_EQ(0, rv);
165 }
166 
MULTIPROCESS_TEST_MAIN(HandleVerifierChildProcess)167 MULTIPROCESS_TEST_MAIN(HandleVerifierChildProcess) {
168   ScopedNativeLibrary module(
169       FilePath(FILE_PATH_LITERAL("scoped_handle_test_dll.dll")));
170 
171   if (!module.is_valid())
172     return 1;
173   auto run_test_function = reinterpret_cast<decltype(&testing::RunTest)>(
174       module.GetFunctionPointer("RunTest"));
175   if (!run_test_function)
176     return 1;
177   if (!run_test_function())
178     return 1;
179 
180   return 0;
181 }
182 
183 }  // namespace win
184 }  // namespace base
185