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