diff options
author | Cronet Mainline Eng <cronet-mainline-eng+copybara@google.com> | 2023-08-14 17:15:38 +0000 |
---|---|---|
committer | Mohannad Farrag <aymanm@google.com> | 2023-08-14 17:22:36 +0000 |
commit | ec3a8e8db24bb3ce4b078106b358ca1c4389c14f (patch) | |
tree | 823f64849ad509483bfebb2252199a5fe79b8e43 /base/win | |
parent | d12afe756882b2521faa0b33cbd4813fcea04c22 (diff) | |
download | cronet-ec3a8e8db24bb3ce4b078106b358ca1c4389c14f.tar.gz |
Import Cronet version 117.0.5938.0
Project import generated by Copybara.
FolderOrigin-RevId: /tmp/copybara-origin/src
Change-Id: Ib7683d0ed240e11ed9068152600c8092afba4571
Diffstat (limited to 'base/win')
-rw-r--r-- | base/win/com_init_util.cc | 12 | ||||
-rw-r--r-- | base/win/message_window_unittest.cc | 5 | ||||
-rw-r--r-- | base/win/nt_status.cc | 14 | ||||
-rw-r--r-- | base/win/registry.cc | 572 | ||||
-rw-r--r-- | base/win/registry.h | 102 | ||||
-rw-r--r-- | base/win/registry_unittest.cc | 244 | ||||
-rw-r--r-- | base/win/scoped_handle_unittest.cc | 5 | ||||
-rw-r--r-- | base/win/scoped_safearray.h | 5 |
8 files changed, 229 insertions, 730 deletions
diff --git a/base/win/com_init_util.cc b/base/win/com_init_util.cc index b7b973c95..9867c1540 100644 --- a/base/win/com_init_util.cc +++ b/base/win/com_init_util.cc @@ -4,11 +4,11 @@ #include "base/win/com_init_util.h" +#include <stdint.h> #include <windows.h> - #include <winternl.h> + #include "base/logging.h" -#include "base/memory/raw_ptr_exclusion.h" #include "base/notreached.h" namespace base { @@ -28,12 +28,8 @@ struct OleTlsData { MTA = 0x140, }; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #reinterpret-cast-trivial-type - RAW_PTR_EXCLUSION void* thread_base; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #reinterpret-cast-trivial-type - RAW_PTR_EXCLUSION void* sm_allocator; + uintptr_t thread_base; + uintptr_t sm_allocator; DWORD apartment_id; DWORD apartment_flags; // There are many more fields than this, but for our purposes, we only care diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc index c158559fe..9568f0b2f 100644 --- a/base/win/message_window_unittest.cc +++ b/base/win/message_window_unittest.cc @@ -7,8 +7,8 @@ #include <windows.h> #include "base/functional/bind.h" -#include "base/guid.h" #include "base/strings/utf_string_conversions.h" +#include "base/uuid.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -57,7 +57,8 @@ TEST(MessageWindowTest, SendMessage) { // Verifies that a named window can be found by name. TEST(MessageWindowTest, FindWindow) { - std::wstring name = UTF8ToWide(base::GenerateGUID()); + std::wstring name = + UTF8ToWide(base::Uuid::GenerateRandomV4().AsLowercaseString()); win::MessageWindow window; EXPECT_TRUE(window.CreateNamed(base::BindRepeating(&HandleMessage), name)); diff --git a/base/win/nt_status.cc b/base/win/nt_status.cc index fc7444292..4dbeb6208 100644 --- a/base/win/nt_status.cc +++ b/base/win/nt_status.cc @@ -5,14 +5,8 @@ #include "base/win/nt_status.h" #include <windows.h> -#include <winternl.h> -#include "base/check.h" - -using GetLastNtStatusFn = NTSTATUS NTAPI (*)(); - -constexpr const wchar_t kNtDllName[] = L"ntdll.dll"; -constexpr const char kLastStatusFnName[] = "RtlGetLastNtStatus"; +extern "C" NTSTATUS WINAPI RtlGetLastNtStatus(); namespace base { namespace win { @@ -22,10 +16,8 @@ NTSTATUS GetLastNtStatus() { // LastStatusValue from the returned _TEB structure, except that the public // _TEB struct definition does not actually specify the location of the // LastStatusValue field. We avoid depending on such a definition by - // internally using RtGetLastNtStatus() from ntdll.dll instead. - static auto* get_last_nt_status = reinterpret_cast<GetLastNtStatusFn>( - ::GetProcAddress(::GetModuleHandle(kNtDllName), kLastStatusFnName)); - return get_last_nt_status(); + // internally using RtlGetLastNtStatus() from ntdll.dll instead. + return ::RtlGetLastNtStatus(); } } // namespace win diff --git a/base/win/registry.cc b/base/win/registry.cc index 473f5fdc8..9e67b3596 100644 --- a/base/win/registry.cc +++ b/base/win/registry.cc @@ -14,16 +14,12 @@ #include <vector> #include "base/check_op.h" -#include "base/containers/fixed_flat_map.h" #include "base/functional/callback.h" -#include "base/native_library.h" #include "base/notreached.h" -#include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/string_util_win.h" #include "base/threading/thread_restrictions.h" #include "base/win/object_watcher.h" -#include "base/win/pe_image.h" #include "base/win/scoped_handle.h" #include "base/win/shlwapi.h" @@ -50,326 +46,8 @@ constexpr DWORD kInvalidIterValue = static_cast<DWORD>(-1); } // namespace -namespace internal { - -// A forwarder to the normal delayloaded Windows Registry API. -class Standard { - public: - static inline LSTATUS CreateKey(HKEY hKey, - LPCWSTR lpSubKey, - DWORD Reserved, - LPWSTR lpClass, - DWORD dwOptions, - REGSAM samDesired, - CONST LPSECURITY_ATTRIBUTES - lpSecurityAttributes, - PHKEY phkResult, - LPDWORD lpdwDisposition) { - return ::RegCreateKeyExW(hKey, lpSubKey, Reserved, lpClass, dwOptions, - samDesired, lpSecurityAttributes, phkResult, - lpdwDisposition); - } - - static inline LSTATUS OpenKey(HKEY hKey, - LPCWSTR lpSubKey, - DWORD ulOptions, - REGSAM samDesired, - PHKEY phkResult) { - return ::RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult); - } - - static inline LSTATUS DeleteKey(HKEY hKey, - LPCWSTR lpSubKey, - REGSAM samDesired, - DWORD Reserved) { - return ::RegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved); - } - - static inline LSTATUS QueryInfoKey(HKEY hKey, - LPWSTR lpClass, - LPDWORD lpcchClass, - LPDWORD lpReserved, - LPDWORD lpcSubKeys, - LPDWORD lpcbMaxSubKeyLen, - LPDWORD lpcbMaxClassLen, - LPDWORD lpcValues, - LPDWORD lpcbMaxValueNameLen, - LPDWORD lpcbMaxValueLen, - LPDWORD lpcbSecurityDescriptor, - PFILETIME lpftLastWriteTime) { - return ::RegQueryInfoKeyW(hKey, lpClass, lpcchClass, lpReserved, lpcSubKeys, - lpcbMaxSubKeyLen, lpcbMaxClassLen, lpcValues, - lpcbMaxValueNameLen, lpcbMaxValueLen, - lpcbSecurityDescriptor, lpftLastWriteTime); - } - - static inline LSTATUS EnumKey(HKEY hKey, - DWORD dwIndex, - LPWSTR lpName, - LPDWORD lpcchName, - LPDWORD lpReserved, - LPWSTR lpClass, - LPDWORD lpcchClass, - PFILETIME lpftLastWriteTime) { - return ::RegEnumKeyExW(hKey, dwIndex, lpName, lpcchName, lpReserved, - lpClass, lpcchClass, lpftLastWriteTime); - } - - static inline LSTATUS CloseKey(HKEY hKey) { return ::RegCloseKey(hKey); } - - static inline LSTATUS QueryValue(HKEY hKey, - LPCWSTR lpValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData) { - return ::RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, - lpcbData); - } - - static inline LSTATUS SetValue(HKEY hKey, - LPCWSTR lpValueName, - DWORD Reserved, - DWORD dwType, - CONST BYTE* lpData, - DWORD cbData) { - return ::RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, - cbData); - } - - static inline LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) { - return ::RegDeleteValueW(hKey, lpValueName); - } - - static inline LSTATUS EnumValue(HKEY hKey, - DWORD dwIndex, - LPWSTR lpValueName, - LPDWORD lpcchValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData) { - return ::RegEnumValueW(hKey, dwIndex, lpValueName, lpcchValueName, - lpReserved, lpType, lpData, lpcbData); - } -}; - -// An implementation derived from the export table of advapi32. -class ExportDerived { - public: - static LSTATUS CreateKey(HKEY hKey, - LPCWSTR lpSubKey, - DWORD Reserved, - LPWSTR lpClass, - DWORD dwOptions, - REGSAM samDesired, - CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes, - PHKEY phkResult, - LPDWORD lpdwDisposition) { - if (!ResolveRegistryFunctions() || !reg_create_key_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_create_key_ex_(hKey, lpSubKey, Reserved, lpClass, dwOptions, - samDesired, lpSecurityAttributes, phkResult, - lpdwDisposition); - } - - static LSTATUS OpenKey(HKEY hKey, - LPCWSTR lpSubKey, - DWORD ulOptions, - REGSAM samDesired, - PHKEY phkResult) { - if (!ResolveRegistryFunctions() || !reg_open_key_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_open_key_ex_(hKey, lpSubKey, ulOptions, samDesired, phkResult); - } - - static LSTATUS DeleteKey(HKEY hKey, - LPCWSTR lpSubKey, - REGSAM samDesired, - DWORD Reserved) { - if (!ResolveRegistryFunctions() || !reg_delete_key_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_delete_key_ex_(hKey, lpSubKey, samDesired, Reserved); - } - - static LSTATUS QueryInfoKey(HKEY hKey, - LPWSTR lpClass, - LPDWORD lpcchClass, - LPDWORD lpReserved, - LPDWORD lpcSubKeys, - LPDWORD lpcbMaxSubKeyLen, - LPDWORD lpcbMaxClassLen, - LPDWORD lpcValues, - LPDWORD lpcbMaxValueNameLen, - LPDWORD lpcbMaxValueLen, - LPDWORD lpcbSecurityDescriptor, - PFILETIME lpftLastWriteTime) { - if (!ResolveRegistryFunctions() || !reg_query_info_key_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_query_info_key_(hKey, lpClass, lpcchClass, lpReserved, - lpcSubKeys, lpcbMaxSubKeyLen, lpcbMaxClassLen, - lpcValues, lpcbMaxValueNameLen, lpcbMaxValueLen, - lpcbSecurityDescriptor, lpftLastWriteTime); - } - - static LSTATUS EnumKey(HKEY hKey, - DWORD dwIndex, - LPWSTR lpName, - LPDWORD lpcchName, - LPDWORD lpReserved, - LPWSTR lpClass, - LPDWORD lpcchClass, - PFILETIME lpftLastWriteTime) { - if (!ResolveRegistryFunctions() || !reg_enum_key_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_enum_key_ex_(hKey, dwIndex, lpName, lpcchName, lpReserved, - lpClass, lpcchClass, lpftLastWriteTime); - } - - static LSTATUS CloseKey(HKEY hKey) { - if (!ResolveRegistryFunctions() || !reg_close_key_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_close_key_(hKey); - } - - static LSTATUS QueryValue(HKEY hKey, - LPCWSTR lpValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData) { - if (!ResolveRegistryFunctions() || !reg_query_value_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_query_value_ex_(hKey, lpValueName, lpReserved, lpType, lpData, - lpcbData); - } - - static LSTATUS SetValue(HKEY hKey, - LPCWSTR lpValueName, - DWORD Reserved, - DWORD dwType, - CONST BYTE* lpData, - DWORD cbData) { - if (!ResolveRegistryFunctions() || !reg_set_value_ex_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_set_value_ex_(hKey, lpValueName, Reserved, dwType, lpData, - cbData); - } - - static LSTATUS DeleteValue(HKEY hKey, LPCWSTR lpValueName) { - if (!ResolveRegistryFunctions() || !reg_delete_value_) { - return ERROR_ERRORS_ENCOUNTERED; - } - return reg_delete_value_(hKey, lpValueName); - } - static LSTATUS EnumValue(HKEY hKey, - DWORD dwIndex, - LPWSTR lpValueName, - LPDWORD lpcchValueName, - LPDWORD lpReserved, - LPDWORD lpType, - LPBYTE lpData, - LPDWORD lpcbData) { - if (!ResolveRegistryFunctions() || !reg_enum_value_) { - return ERROR_ERRORS_ENCOUNTERED; - } - - return reg_enum_value_(hKey, dwIndex, lpValueName, lpcchValueName, - lpReserved, lpType, lpData, lpcbData); - } - - private: - static bool ProcessOneExport(const base::win::PEImage& image, - DWORD ordinal, - DWORD hint, - LPCSTR name, - PVOID function_addr, - LPCSTR forward, - PVOID cookie) { - if (!name || !function_addr) { - return true; - } - - static const auto kMap = - base::MakeFixedFlatMapSorted<base::StringPiece, void**>({ - {"RegCloseKey", reinterpret_cast<void**>(®_close_key_)}, - {"RegCreateKeyExW", reinterpret_cast<void**>(®_create_key_ex_)}, - {"RegDeleteKeyExW", reinterpret_cast<void**>(®_delete_key_ex_)}, - {"RegDeleteValueW", reinterpret_cast<void**>(®_delete_value_)}, - {"RegEnumKeyExW", reinterpret_cast<void**>(®_enum_key_ex_)}, - {"RegEnumValueW", reinterpret_cast<void**>(®_enum_value_)}, - {"RegOpenKeyExW", reinterpret_cast<void**>(®_open_key_ex_)}, - {"RegQueryInfoKeyW", - reinterpret_cast<void**>(®_query_info_key_)}, - {"RegQueryValueExW", - reinterpret_cast<void**>(®_query_value_ex_)}, - {"RegSetValueExW", reinterpret_cast<void**>(®_set_value_ex_)}, - }); - - auto* entry = kMap.find(name); - if (entry == kMap.end()) { - return true; - } - - static size_t num_init_functions = 0; - if (!std::exchange(*(entry->second), function_addr)) { - ++num_init_functions; - } - - bool& fully_resolved = *static_cast<bool*>(cookie); - fully_resolved = num_init_functions == kMap.size(); - return !fully_resolved; - } - - static bool ResolveRegistryFunctions() { - static bool initialized = []() { - base::NativeLibraryLoadError error; - HMODULE advapi32 = base::PinSystemLibrary(L"advapi32.dll", &error); - if (!advapi32 || error.code) { - return false; - } - bool fully_resolved = false; - base::win::PEImage(advapi32).EnumExports(&ProcessOneExport, - &fully_resolved); - return fully_resolved; - }(); - return initialized; - } - - static decltype(::RegCreateKeyExW)* reg_create_key_ex_; - static decltype(::RegOpenKeyExW)* reg_open_key_ex_; - static decltype(::RegDeleteKeyExW)* reg_delete_key_ex_; - static decltype(::RegQueryInfoKeyW)* reg_query_info_key_; - static decltype(::RegEnumKeyExW)* reg_enum_key_ex_; - static decltype(::RegCloseKey)* reg_close_key_; - static decltype(::RegQueryValueExW)* reg_query_value_ex_; - static decltype(::RegSetValueExW)* reg_set_value_ex_; - static decltype(::RegDeleteValueW)* reg_delete_value_; - static decltype(::RegEnumValueW)* reg_enum_value_; -}; - -decltype(::RegCreateKeyEx)* ExportDerived::reg_create_key_ex_ = nullptr; -decltype(::RegOpenKeyExW)* ExportDerived::reg_open_key_ex_ = nullptr; -decltype(::RegDeleteKeyExW)* ExportDerived::reg_delete_key_ex_ = nullptr; -decltype(::RegQueryInfoKeyW)* ExportDerived::reg_query_info_key_ = nullptr; -decltype(::RegEnumKeyExW)* ExportDerived::reg_enum_key_ex_ = nullptr; -decltype(::RegCloseKey)* ExportDerived::reg_close_key_ = nullptr; -decltype(::RegQueryValueEx)* ExportDerived::reg_query_value_ex_ = nullptr; -decltype(::RegSetValueExW)* ExportDerived::reg_set_value_ex_ = nullptr; -decltype(::RegDeleteValueW)* ExportDerived::reg_delete_value_ = nullptr; -decltype(::RegEnumValueW)* ExportDerived::reg_enum_value_ = nullptr; - // Watches for modifications to a key. -template <typename Reg> -class GenericRegKey<Reg>::Watcher : public ObjectWatcher::Delegate { +class RegKey::Watcher : public ObjectWatcher::Delegate { public: Watcher() = default; @@ -393,9 +71,7 @@ class GenericRegKey<Reg>::Watcher : public ObjectWatcher::Delegate { ChangeCallback callback_; }; -template <typename Reg> -bool GenericRegKey<Reg>::Watcher::StartWatching(HKEY key, - ChangeCallback callback) { +bool RegKey::Watcher::StartWatching(HKEY key, ChangeCallback callback) { DCHECK(key); DCHECK(callback_.is_null()); @@ -423,24 +99,18 @@ bool GenericRegKey<Reg>::Watcher::StartWatching(HKEY key, return object_watcher_.StartWatchingOnce(watch_event_.get(), this); } -// GenericRegKey<Reg> -// ---------------------------------------------------------------------- +// RegKey ---------------------------------------------------------------------- -template <typename Reg> -GenericRegKey<Reg>::GenericRegKey() = default; +RegKey::RegKey() = default; -template <typename Reg> -GenericRegKey<Reg>::GenericRegKey(HKEY key) : key_(key) {} +RegKey::RegKey(HKEY key) : key_(key) {} -template <typename Reg> -GenericRegKey<Reg>::GenericRegKey(HKEY rootkey, - const wchar_t* subkey, - REGSAM access) { +RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) { if (rootkey) { if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) { - Create(rootkey, subkey, access); + (void)Create(rootkey, subkey, access); } else { - Open(rootkey, subkey, access); + (void)Open(rootkey, subkey, access); } } else { DCHECK(!subkey); @@ -448,8 +118,7 @@ GenericRegKey<Reg>::GenericRegKey(HKEY rootkey, } } -template <typename Reg> -GenericRegKey<Reg>::GenericRegKey(GenericRegKey<Reg>&& other) noexcept +RegKey::RegKey(RegKey&& other) noexcept : key_(other.key_), wow64access_(other.wow64access_), key_watcher_(std::move(other.key_watcher_)) { @@ -457,8 +126,7 @@ GenericRegKey<Reg>::GenericRegKey(GenericRegKey<Reg>&& other) noexcept other.wow64access_ = 0; } -template <typename Reg> -GenericRegKey<Reg>& GenericRegKey<Reg>::operator=(GenericRegKey<Reg>&& other) { +RegKey& RegKey::operator=(RegKey&& other) { Close(); std::swap(key_, other.key_); std::swap(wow64access_, other.wow64access_); @@ -466,28 +134,23 @@ GenericRegKey<Reg>& GenericRegKey<Reg>::operator=(GenericRegKey<Reg>&& other) { return *this; } -template <typename Reg> -GenericRegKey<Reg>::~GenericRegKey() { +RegKey::~RegKey() { Close(); } -template <typename Reg> -LONG GenericRegKey<Reg>::Create(HKEY rootkey, - const wchar_t* subkey, - REGSAM access) { +LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { DWORD disposition_value; return CreateWithDisposition(rootkey, subkey, &disposition_value, access); } -template <typename Reg> -LONG GenericRegKey<Reg>::CreateWithDisposition(HKEY rootkey, - const wchar_t* subkey, - DWORD* disposition, - REGSAM access) { +LONG RegKey::CreateWithDisposition(HKEY rootkey, + const wchar_t* subkey, + DWORD* disposition, + REGSAM access) { DCHECK(rootkey && subkey && access && disposition); HKEY subhkey = nullptr; LONG result = - Reg::CreateKey(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE, + RegCreateKeyEx(rootkey, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE, access, nullptr, &subhkey, disposition); if (result == ERROR_SUCCESS) { Close(); @@ -498,9 +161,14 @@ LONG GenericRegKey<Reg>::CreateWithDisposition(HKEY rootkey, return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) { +LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) { DCHECK(name && access); + + if (!Valid()) { + // The parent key has not been opened or created. + return ERROR_INVALID_HANDLE; + } + // After the application has accessed an alternate registry view using one // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent // operations (create, delete, or open) on child registry keys must @@ -512,7 +180,7 @@ LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) { return ERROR_INVALID_PARAMETER; } HKEY subkey = nullptr; - LONG result = Reg::CreateKey(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE, + LONG result = RegCreateKeyEx(key_, name, 0, nullptr, REG_OPTION_NON_VOLATILE, access, nullptr, &subkey, nullptr); if (result == ERROR_SUCCESS) { Close(); @@ -523,14 +191,11 @@ LONG GenericRegKey<Reg>::CreateKey(const wchar_t* name, REGSAM access) { return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::Open(HKEY rootkey, - const wchar_t* subkey, - REGSAM access) { +LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { DCHECK(rootkey && subkey && access); HKEY subhkey = nullptr; - LONG result = Reg::OpenKey(rootkey, subkey, 0, access, &subhkey); + LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey); if (result == ERROR_SUCCESS) { Close(); key_ = subhkey; @@ -540,10 +205,14 @@ LONG GenericRegKey<Reg>::Open(HKEY rootkey, return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name, - REGSAM access) { +LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) { DCHECK(relative_key_name && access); + + if (!Valid()) { + // The parent key has not been opened or created. + return ERROR_INVALID_HANDLE; + } + // After the application has accessed an alternate registry view using one // of the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent // operations (create, delete, or open) on child registry keys must @@ -555,7 +224,7 @@ LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name, return ERROR_INVALID_PARAMETER; } HKEY subkey = nullptr; - LONG result = Reg::OpenKey(key_, relative_key_name, 0, access, &subkey); + LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey); // We have to close the current opened key before replacing it with the new // one. @@ -567,62 +236,54 @@ LONG GenericRegKey<Reg>::OpenKey(const wchar_t* relative_key_name, return result; } -template <typename Reg> -void GenericRegKey<Reg>::Close() { +void RegKey::Close() { if (key_) { - Reg::CloseKey(key_); + ::RegCloseKey(key_); key_ = nullptr; wow64access_ = 0; } } -// TODO(wfh): Remove this and other unsafe methods. See -// http://crbug.com/375400 -template <typename Reg> -void GenericRegKey<Reg>::Set(HKEY key) { +// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 +void RegKey::Set(HKEY key) { if (key_ != key) { Close(); key_ = key; } } -template <typename Reg> -HKEY GenericRegKey<Reg>::Take() { +HKEY RegKey::Take() { DCHECK_EQ(wow64access_, 0u); HKEY key = key_; key_ = nullptr; return key; } -template <typename Reg> -bool GenericRegKey<Reg>::HasValue(const wchar_t* name) const { - return Reg::QueryValue(key_, name, nullptr, nullptr, nullptr, nullptr) == +bool RegKey::HasValue(const wchar_t* name) const { + return RegQueryValueEx(key_, name, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS; } -template <typename Reg> -DWORD GenericRegKey<Reg>::GetValueCount() const { +DWORD RegKey::GetValueCount() const { DWORD count = 0; LONG result = - Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &count, nullptr, nullptr, nullptr, nullptr); + RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &count, nullptr, nullptr, nullptr, nullptr); return (result == ERROR_SUCCESS) ? count : 0; } -template <typename Reg> -FILETIME GenericRegKey<Reg>::GetLastWriteTime() const { +FILETIME RegKey::GetLastWriteTime() const { FILETIME last_write_time; - LONG result = Reg::QueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &last_write_time); + LONG result = RegQueryInfoKey(key_, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &last_write_time); return (result == ERROR_SUCCESS) ? last_write_time : FILETIME{}; } -template <typename Reg> -LONG GenericRegKey<Reg>::GetValueNameAt(DWORD index, std::wstring* name) const { +LONG RegKey::GetValueNameAt(DWORD index, std::wstring* name) const { wchar_t buf[256]; DWORD bufsize = std::size(buf); - LONG r = Reg::EnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr, + LONG r = ::RegEnumValue(key_, index, buf, &bufsize, nullptr, nullptr, nullptr, nullptr); if (r == ERROR_SUCCESS) { name->assign(buf, bufsize); @@ -631,8 +292,7 @@ LONG GenericRegKey<Reg>::GetValueNameAt(DWORD index, std::wstring* name) const { return r; } -template <typename Reg> -LONG GenericRegKey<Reg>::DeleteKey(const wchar_t* name) { +LONG RegKey::DeleteKey(const wchar_t* name) { DCHECK(name); // Verify the key exists before attempting delete to replicate previous @@ -640,23 +300,22 @@ LONG GenericRegKey<Reg>::DeleteKey(const wchar_t* name) { // `RegOpenKeyEx()` will return an error if `key_` is invalid. HKEY subkey = nullptr; LONG result = - Reg::OpenKey(key_, name, 0, READ_CONTROL | wow64access_, &subkey); + RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey); if (result != ERROR_SUCCESS) { return result; } - Reg::CloseKey(subkey); + RegCloseKey(subkey); return RegDelRecurse(key_, name, wow64access_); } -template <typename Reg> -LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) { +LONG RegKey::DeleteEmptyKey(const wchar_t* name) { DCHECK(name); // `RegOpenKeyEx()` will return an error if `key_` is invalid. HKEY target_key = nullptr; LONG result = - Reg::OpenKey(key_, name, 0, KEY_READ | wow64access_, &target_key); + RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_, &target_key); if (result != ERROR_SUCCESS) { return result; @@ -664,10 +323,10 @@ LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) { DWORD count = 0; result = - Reg::QueryInfoKey(target_key, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, &count, nullptr, nullptr, nullptr, nullptr); + RegQueryInfoKey(target_key, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, &count, nullptr, nullptr, nullptr, nullptr); - Reg::CloseKey(target_key); + RegCloseKey(target_key); if (result != ERROR_SUCCESS) { return result; @@ -680,16 +339,13 @@ LONG GenericRegKey<Reg>::DeleteEmptyKey(const wchar_t* name) { return ERROR_DIR_NOT_EMPTY; } -template <typename Reg> -LONG GenericRegKey<Reg>::DeleteValue(const wchar_t* value_name) { +LONG RegKey::DeleteValue(const wchar_t* value_name) { // `RegDeleteValue()` will return an error if `key_` is invalid. - LONG result = Reg::DeleteValue(key_, value_name); + LONG result = RegDeleteValue(key_, value_name); return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::ReadValueDW(const wchar_t* name, - DWORD* out_value) const { +LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const { DCHECK(out_value); DWORD type = REG_DWORD; DWORD size = sizeof(DWORD); @@ -706,9 +362,7 @@ LONG GenericRegKey<Reg>::ReadValueDW(const wchar_t* name, return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::ReadInt64(const wchar_t* name, - int64_t* out_value) const { +LONG RegKey::ReadInt64(const wchar_t* name, int64_t* out_value) const { DCHECK(out_value); DWORD type = REG_QWORD; int64_t local_value = 0; @@ -726,9 +380,7 @@ LONG GenericRegKey<Reg>::ReadInt64(const wchar_t* name, return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name, - std::wstring* out_value) const { +LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const { DCHECK(out_value); const size_t kMaxStringLength = 1024; // This is after expansion. // Use the one of the other forms of ReadValue if 1024 is too small for you. @@ -758,19 +410,17 @@ LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name, return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::ReadValue(const wchar_t* name, - void* data, - DWORD* dsize, - DWORD* dtype) const { - LONG result = Reg::QueryValue(key_, name, nullptr, dtype, +LONG RegKey::ReadValue(const wchar_t* name, + void* data, + DWORD* dsize, + DWORD* dtype) const { + LONG result = RegQueryValueEx(key_, name, nullptr, dtype, reinterpret_cast<LPBYTE>(data), dsize); return result; } -template <typename Reg> -LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name, - std::vector<std::wstring>* values) { +LONG RegKey::ReadValues(const wchar_t* name, + std::vector<std::wstring>* values) { values->clear(); DWORD type = REG_MULTI_SZ; @@ -791,8 +441,8 @@ LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name, } // Parse the double-null-terminated list of strings. - // Note: This code is paranoid to not read outside of |buf|, in the case - // where it may not be properly terminated. + // Note: This code is paranoid to not read outside of |buf|, in the case where + // it may not be properly terminated. auto entry = buffer.cbegin(); auto buffer_end = buffer.cend(); while (entry < buffer_end && *entry != '\0') { @@ -803,15 +453,12 @@ LONG GenericRegKey<Reg>::ReadValues(const wchar_t* name, return 0; } -template <typename Reg> -LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, DWORD in_value) { +LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) { return WriteValue(name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD); } -template <typename Reg> -LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, - const wchar_t* in_value) { +LONG RegKey::WriteValue(const wchar_t* name, const wchar_t* in_value) { return WriteValue( name, in_value, static_cast<DWORD>(sizeof(*in_value) * @@ -819,21 +466,19 @@ LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, REG_SZ); } -template <typename Reg> -LONG GenericRegKey<Reg>::WriteValue(const wchar_t* name, - const void* data, - DWORD dsize, - DWORD dtype) { +LONG RegKey::WriteValue(const wchar_t* name, + const void* data, + DWORD dsize, + DWORD dtype) { DCHECK(data || !dsize); LONG result = - Reg::SetValue(key_, name, 0, dtype, + RegSetValueEx(key_, name, 0, dtype, reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); return result; } -template <typename Reg> -bool GenericRegKey<Reg>::StartWatching(ChangeCallback callback) { +bool RegKey::StartWatching(ChangeCallback callback) { if (!key_watcher_) { key_watcher_ = std::make_unique<Watcher>(); } @@ -846,18 +491,15 @@ bool GenericRegKey<Reg>::StartWatching(ChangeCallback callback) { } // static -template <typename Reg> -LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key, - const wchar_t* name, - REGSAM access) { +LONG RegKey::RegDelRecurse(HKEY root_key, const wchar_t* name, REGSAM access) { // First, see if the key can be deleted without having to recurse. - LONG result = Reg::DeleteKey(root_key, name, access, 0); + LONG result = RegDeleteKeyEx(root_key, name, access, 0); if (result == ERROR_SUCCESS) { return result; } HKEY target_key = nullptr; - result = Reg::OpenKey(root_key, name, 0, KEY_ENUMERATE_SUB_KEYS | access, + result = RegOpenKeyEx(root_key, name, 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key); if (result == ERROR_FILE_NOT_FOUND) { @@ -881,7 +523,7 @@ LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key, while (result == ERROR_SUCCESS) { DWORD key_size = kMaxKeyNameLength; result = - Reg::EnumKey(target_key, 0, WriteInto(&key_name, kMaxKeyNameLength), + RegEnumKeyEx(target_key, 0, WriteInto(&key_name, kMaxKeyNameLength), &key_size, nullptr, nullptr, nullptr, nullptr); if (result != ERROR_SUCCESS) { @@ -897,54 +539,14 @@ LONG GenericRegKey<Reg>::RegDelRecurse(HKEY root_key, } } - Reg::CloseKey(target_key); + RegCloseKey(target_key); // Try again to delete the key. - result = Reg::DeleteKey(root_key, name, access, 0); + result = RegDeleteKeyEx(root_key, name, access, 0); return result; } -// Instantiate the only two allowed versions of GenericRegKey for use by the -// public base::win::RegKey and base::win::ExportDerivedRegKey. -template class GenericRegKey<internal::Standard>; -template class GenericRegKey<internal::ExportDerived>; - -} // namespace internal - -RegKey::RegKey() : GenericRegKey<internal::Standard>() {} -RegKey::RegKey(HKEY key) : GenericRegKey<internal::Standard>(key) {} -RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) - : GenericRegKey<internal::Standard>(rootkey, subkey, access) {} - -RegKey::RegKey(RegKey&& other) noexcept - : GenericRegKey<internal::Standard>(std::move(other)) {} -RegKey& RegKey::operator=(RegKey&& other) { - GenericRegKey<internal::Standard>::operator=(std::move(other)); - return *this; -} - -RegKey::~RegKey() = default; - -ExportDerivedRegKey::ExportDerivedRegKey() - : GenericRegKey<internal::ExportDerived>() {} -ExportDerivedRegKey::ExportDerivedRegKey(HKEY key) - : GenericRegKey<internal::ExportDerived>(key) {} -ExportDerivedRegKey::ExportDerivedRegKey(HKEY rootkey, - const wchar_t* subkey, - REGSAM access) - : GenericRegKey<internal::ExportDerived>(rootkey, subkey, access) {} - -ExportDerivedRegKey::ExportDerivedRegKey(ExportDerivedRegKey&& other) noexcept - : GenericRegKey<internal::ExportDerived>(std::move(other)) {} -ExportDerivedRegKey& ExportDerivedRegKey::operator=( - ExportDerivedRegKey&& other) { - GenericRegKey<internal::ExportDerived>::operator=(std::move(other)); - return *this; -} - -ExportDerivedRegKey::~ExportDerivedRegKey() = default; - // RegistryValueIterator ------------------------------------------------------ RegistryValueIterator::RegistryValueIterator(HKEY root_key, diff --git a/base/win/registry.h b/base/win/registry.h index 8e6372a40..4c7b1ae0e 100644 --- a/base/win/registry.h +++ b/base/win/registry.h @@ -13,11 +13,8 @@ #include "base/base_export.h" #include "base/functional/callback_forward.h" -#include "base/gtest_prod_util.h" #include "base/win/windows_types.h" -class ShellUtil; - namespace base { namespace win { @@ -30,47 +27,43 @@ namespace win { // is not touched in case of failure. // * Functions returning LONG indicate success as ERROR_SUCCESS or an // error as a (non-zero) win32 error code. -// -// Most developers should use base::win::RegKey subclass below. -namespace internal { - -class Standard; -class ExportDerived; -template <typename T> -class RegTestTraits; - -template <typename Reg> -class GenericRegKey { +class BASE_EXPORT RegKey { public: // Called from the MessageLoop when the key changes. using ChangeCallback = OnceCallback<void()>; - GenericRegKey(); - explicit GenericRegKey(HKEY key); - GenericRegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); - GenericRegKey(GenericRegKey&& other) noexcept; - GenericRegKey& operator=(GenericRegKey&& other); + RegKey(); + explicit RegKey(HKEY key); + RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); + RegKey(RegKey&& other) noexcept; + RegKey& operator=(RegKey&& other); - GenericRegKey(const GenericRegKey&) = delete; - GenericRegKey& operator=(const GenericRegKey&) = delete; + RegKey(const RegKey&) = delete; + RegKey& operator=(const RegKey&) = delete; - virtual ~GenericRegKey(); + ~RegKey(); - LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access); + // Creates a new reg key, replacing `this` with a reference to the + // newly-opened key. In case of error, `this` is unchanged. + [[nodiscard]] LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access); - LONG CreateWithDisposition(HKEY rootkey, - const wchar_t* subkey, - DWORD* disposition, - REGSAM access); + // Creates a new reg key, replacing `this` with a reference to the + // newly-opened key. In case of error, `this` is unchanged. + [[nodiscard]] LONG CreateWithDisposition(HKEY rootkey, + const wchar_t* subkey, + DWORD* disposition, + REGSAM access); - // Creates a subkey or open it if it already exists. - LONG CreateKey(const wchar_t* name, REGSAM access); + // Creates a subkey or opens it if it already exists. In case of error, `this` + // is unchanged. + [[nodiscard]] LONG CreateKey(const wchar_t* name, REGSAM access); - // Opens an existing reg key. - LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access); + // Opens an existing reg key, replacing `this` with a reference to the + // newly-opened key. In case of error, `this` is unchanged. + [[nodiscard]] LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access); // Opens an existing reg key, given the relative key name. - LONG OpenKey(const wchar_t* relative_key_name, REGSAM access); + [[nodiscard]] LONG OpenKey(const wchar_t* relative_key_name, REGSAM access); // Closes this reg key. void Close(); @@ -152,8 +145,8 @@ class GenericRegKey { // Starts watching the key to see if any of its values have changed. // The key must have been opened with the KEY_NOTIFY access privilege. // Returns true on success. - // To stop watching, delete this GenericRegKey object. To continue watching - // the object after the callback is invoked, call StartWatching again. + // To stop watching, delete this RegKey object. To continue watching the + // object after the callback is invoked, call StartWatching again. bool StartWatching(ChangeCallback callback); HKEY Handle() const { return key_; } @@ -169,47 +162,6 @@ class GenericRegKey { std::unique_ptr<Watcher> key_watcher_; }; -} // namespace internal - -// The Windows registry utility class most developers should use. -class BASE_EXPORT RegKey : public internal::GenericRegKey<internal::Standard> { - public: - RegKey(); - explicit RegKey(HKEY key); - RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); - RegKey(RegKey&& other) noexcept; - RegKey& operator=(RegKey&& other); - - RegKey(const RegKey&) = delete; - RegKey& operator=(const RegKey&) = delete; - - ~RegKey() override; -}; - -// A Windows registry class that derives its calls directly from advapi32.dll. -// Generally, you should use RegKey above. Note that use of this API will pin -// advapi32.dll. If you need to use this class, please reach out to the -// base/win/OWNERS first. -class BASE_EXPORT ExportDerivedRegKey - : public internal::GenericRegKey<internal::ExportDerived> { - public: - ExportDerivedRegKey(ExportDerivedRegKey&& other) noexcept; - ExportDerivedRegKey& operator=(ExportDerivedRegKey&& other); - - ExportDerivedRegKey(const ExportDerivedRegKey&) = delete; - ExportDerivedRegKey& operator=(const ExportDerivedRegKey&) = delete; - - ~ExportDerivedRegKey() override; - - private: - friend class ::ShellUtil; - friend class internal::RegTestTraits<ExportDerivedRegKey>; - - ExportDerivedRegKey(); - explicit ExportDerivedRegKey(HKEY key); - ExportDerivedRegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); -}; - // Iterates the entries found in a particular folder on the registry. class BASE_EXPORT RegistryValueIterator { public: diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc index 030d01e02..219144315 100644 --- a/base/win/registry_unittest.cc +++ b/base/win/registry_unittest.cc @@ -11,7 +11,6 @@ #include <cstring> #include <iterator> -#include <type_traits> #include <utility> #include "base/compiler_specific.h" @@ -20,6 +19,7 @@ #include "base/location.h" #include "base/memory/scoped_refptr.h" #include "base/run_loop.h" +#include "base/strings/strcat.h" #include "base/test/bind.h" #include "base/test/mock_callback.h" #include "base/test/task_environment.h" @@ -38,7 +38,6 @@ constexpr wchar_t kRootKey[] = L"Base_Registry_Unittest"; // A test harness for registry tests that operate in HKCU. Each test is given // a valid key distinct from that used by other tests. -template <typename Traits> class RegistryTest : public testing::Test { protected: RegistryTest() : root_key_(std::wstring(L"Software\\") + kRootKey) {} @@ -48,8 +47,7 @@ class RegistryTest : public testing::Test { registry_override_.OverrideRegistry(HKEY_CURRENT_USER)); // Create the test's root key. - typename Traits::RegType key( - Traits::Create(HKEY_CURRENT_USER, L"", KEY_CREATE_SUB_KEY)); + RegKey key(HKEY_CURRENT_USER, L"", KEY_CREATE_SUB_KEY); ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, @@ -67,48 +65,10 @@ class RegistryTest : public testing::Test { } // namespace -namespace internal { +TEST_F(RegistryTest, ValueTest) { + RegKey key; -template <typename T> -class RegTestTraits { - public: - using RegType = T; - - static T Create() { return T(); } - - static T Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { - return T(rootkey, subkey, access); - } -}; - -} // namespace internal - -namespace { - -class RegistryTypeNames { - public: - template <typename T> - static std::string GetName(int index) { - if (std::is_same<typename T::RegType, RegKey>()) { - return "RegKey"; - } - if (std::is_same<typename T::RegType, ExportDerivedRegKey>()) { - return "ExportDerivedRegKey"; - } - } -}; - -} // namespace - -using RegistryTypes = - ::testing::Types<internal::RegTestTraits<RegKey>, - internal::RegTestTraits<ExportDerivedRegKey>>; -TYPED_TEST_SUITE(RegistryTest, RegistryTypes, RegistryTypeNames); - -TYPED_TEST(RegistryTest, ValueTest) { - typename TypeParam::RegType key(TypeParam::Create()); - - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), + ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ | KEY_SET_VALUE)); ASSERT_TRUE(key.Valid()); @@ -159,9 +119,9 @@ TYPED_TEST(RegistryTest, ValueTest) { EXPECT_FALSE(key.HasValue(kInt64ValueName)); } -TYPED_TEST(RegistryTest, BigValueIteratorTest) { - typename TypeParam::RegType key(TypeParam::Create()); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), +TEST_F(RegistryTest, BigValueIteratorTest) { + RegKey key; + ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ | KEY_SET_VALUE)); ASSERT_TRUE(key.Valid()); @@ -170,7 +130,7 @@ TYPED_TEST(RegistryTest, BigValueIteratorTest) { ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str())); - RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str()); + RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str()); ASSERT_TRUE(iterator.Valid()); EXPECT_EQ(data, iterator.Name()); EXPECT_EQ(data, iterator.Value()); @@ -180,9 +140,9 @@ TYPED_TEST(RegistryTest, BigValueIteratorTest) { EXPECT_FALSE(iterator.Valid()); } -TYPED_TEST(RegistryTest, TruncatedCharTest) { - typename TypeParam::RegType key(TypeParam::Create()); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), +TEST_F(RegistryTest, TruncatedCharTest) { + RegKey key; + ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ | KEY_SET_VALUE)); ASSERT_TRUE(key.Valid()); @@ -193,7 +153,7 @@ TYPED_TEST(RegistryTest, TruncatedCharTest) { ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData, std::size(kData), REG_BINARY)); - RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str()); + RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str()); ASSERT_TRUE(iterator.Valid()); // Avoid having to use EXPECT_STREQ here by leveraging StringPiece's // operator== to perform a deep comparison. @@ -210,20 +170,19 @@ TYPED_TEST(RegistryTest, TruncatedCharTest) { } // Tests that the value iterator is okay with an empty key. -TYPED_TEST(RegistryTest, ValueIteratorEmptyKey) { - RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str()); +TEST_F(RegistryTest, ValueIteratorEmptyKey) { + RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str()); EXPECT_EQ(iterator.ValueCount(), 0U); EXPECT_FALSE(iterator.Valid()); } // Tests that the default value is seen by a value iterator. -TYPED_TEST(RegistryTest, ValueIteratorDefaultValue) { +TEST_F(RegistryTest, ValueIteratorDefaultValue) { const WStringPiece kTestString(L"i miss you"); - ASSERT_EQ(TypeParam::Create(HKEY_CURRENT_USER, this->root_key().c_str(), - KEY_SET_VALUE) + ASSERT_EQ(RegKey(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE) .WriteValue(nullptr, kTestString.data()), ERROR_SUCCESS); - RegistryValueIterator iterator(HKEY_CURRENT_USER, this->root_key().c_str()); + RegistryValueIterator iterator(HKEY_CURRENT_USER, root_key().c_str()); EXPECT_EQ(iterator.ValueCount(), 1U); ASSERT_TRUE(iterator.Valid()); EXPECT_EQ(WStringPiece(iterator.Name()), WStringPiece()); @@ -234,8 +193,8 @@ TYPED_TEST(RegistryTest, ValueIteratorDefaultValue) { EXPECT_FALSE(iterator.Valid()); } -TYPED_TEST(RegistryTest, RecursiveDelete) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTest, RecursiveDelete) { + RegKey key; // Create root_key() // \->Bar (TestValue) // \->Foo (TestValue) @@ -244,7 +203,7 @@ TYPED_TEST(RegistryTest, RecursiveDelete) { // \->Moo // \->Foo // and delete root_key() - std::wstring key_path = this->root_key(); + std::wstring key_path = root_key(); ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_CREATE_SUB_KEY)); ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE)); @@ -266,7 +225,7 @@ TYPED_TEST(RegistryTest, RecursiveDelete) { key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE)); + key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE)); ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"")); ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Bar\\Foo")); ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Bar")); @@ -283,33 +242,49 @@ TYPED_TEST(RegistryTest, RecursiveDelete) { key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE)); + key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE)); ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Bar")); ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar")); ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ)); } -TYPED_TEST(RegistryTest, OpenSubKey) { - typename TypeParam::RegType key(TypeParam::Create()); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), +TEST_F(RegistryTest, OpenSubKey) { + RegKey key; + ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ | KEY_CREATE_SUB_KEY)); ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ)); + key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); - std::wstring foo_key = this->root_key() + L"\\Foo"; + std::wstring foo_key = root_key() + L"\\Foo"; ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_WRITE)); + key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_WRITE)); ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo")); } +TEST_F(RegistryTest, InvalidRelativeKeyCreate) { + RegKey key(HKEY_CURRENT_USER, + base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(), + KEY_WOW64_32KEY | KEY_READ); + ASSERT_EQ(key.CreateKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_WRITE), + ERROR_INVALID_HANDLE); +} + +TEST_F(RegistryTest, InvalidRelativeKeyOpen) { + RegKey key(HKEY_CURRENT_USER, + base::StrCat({this->root_key(), L"_DoesNotExist"}).c_str(), + KEY_WOW64_32KEY | KEY_READ); + ASSERT_EQ(key.OpenKey(L"SomeSubKey", KEY_WOW64_32KEY | KEY_READ), + ERROR_INVALID_HANDLE); +} + namespace { class TestChangeDelegate { @@ -334,23 +309,22 @@ class TestChangeDelegate { } // namespace -TYPED_TEST(RegistryTest, ChangeCallback) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTest, ChangeCallback) { + RegKey key; TestChangeDelegate delegate; test::TaskEnvironment task_environment; ASSERT_EQ(ERROR_SUCCESS, - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ)); + key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ)); ASSERT_TRUE(key.StartWatching( BindOnce(&TestChangeDelegate::OnKeyChanged, Unretained(&delegate)))); EXPECT_FALSE(delegate.WasCalled()); // Make some change. - typename TypeParam::RegType key2(TypeParam::Create()); - ASSERT_EQ(ERROR_SUCCESS, - key2.Open(HKEY_CURRENT_USER, this->root_key().c_str(), - KEY_READ | KEY_SET_VALUE)); + RegKey key2; + ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, root_key().c_str(), + KEY_READ | KEY_SET_VALUE)); ASSERT_TRUE(key2.Valid()); EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data")); @@ -395,21 +369,20 @@ class RegistryWatcherThread : public SimpleThread { } // namespace -TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) { + RegKey key; - ASSERT_EQ(key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_READ), + ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ), ERROR_SUCCESS); auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>( base::TestMockTimeTaskRunner::Type::kBoundToThread); - ::testing::StrictMock< - base::MockCallback<typename TypeParam::RegType::ChangeCallback>> + ::testing::StrictMock<base::MockCallback<base::win::RegKey::ChangeCallback>> change_cb; - test_task_runner->PostTask( - FROM_HERE, BindOnce(IgnoreResult(&TypeParam::RegType::StartWatching), - Unretained(&key), change_cb.Get())); + test_task_runner->PostTask(FROM_HERE, + BindOnce(IgnoreResult(&RegKey::StartWatching), + Unretained(&key), change_cb.Get())); { // Start the watch on a thread that then goes away. @@ -429,8 +402,8 @@ TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) { EXPECT_CALL(change_cb, Run).WillOnce([&run_loop]() { run_loop.Quit(); }); // Make some change. - typename TypeParam::RegType key2(TypeParam::Create()); - ASSERT_EQ(key2.Open(HKEY_CURRENT_USER, this->root_key().c_str(), + RegKey key2; + ASSERT_EQ(key2.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_READ | KEY_SET_VALUE), ERROR_SUCCESS); ASSERT_TRUE(key2.Valid()); @@ -440,13 +413,12 @@ TYPED_TEST(RegistryTest, WatcherNotSignaledOnInitiatingThreadExit) { run_loop.Run(); } -TYPED_TEST(RegistryTest, TestMoveConstruct) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTest, TestMoveConstruct) { + RegKey key; - ASSERT_EQ( - key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), KEY_SET_VALUE), - ERROR_SUCCESS); - typename TypeParam::RegType key2(std::move(key)); + ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE), + ERROR_SUCCESS); + RegKey key2(std::move(key)); // The old key should be meaningless now. EXPECT_EQ(key.Handle(), nullptr); @@ -456,17 +428,17 @@ TYPED_TEST(RegistryTest, TestMoveConstruct) { EXPECT_EQ(key2.WriteValue(L"foo", 1U), ERROR_SUCCESS); } -TYPED_TEST(RegistryTest, TestMoveAssign) { - typename TypeParam::RegType key(TypeParam::Create()); - typename TypeParam::RegType key2(TypeParam::Create()); +TEST_F(RegistryTest, TestMoveAssign) { + RegKey key; + RegKey key2; const wchar_t kFooValueName[] = L"foo"; - ASSERT_EQ(key.Open(HKEY_CURRENT_USER, this->root_key().c_str(), + ASSERT_EQ(key.Open(HKEY_CURRENT_USER, root_key().c_str(), KEY_SET_VALUE | KEY_QUERY_VALUE), ERROR_SUCCESS); ASSERT_EQ(key.WriteValue(kFooValueName, 1U), ERROR_SUCCESS); - ASSERT_EQ(key2.Create(HKEY_CURRENT_USER, - (this->root_key() + L"\\child").c_str(), KEY_SET_VALUE), + ASSERT_EQ(key2.Create(HKEY_CURRENT_USER, (root_key() + L"\\child").c_str(), + KEY_SET_VALUE), ERROR_SUCCESS); key2 = std::move(key); @@ -482,8 +454,8 @@ TYPED_TEST(RegistryTest, TestMoveAssign) { // Verify that either the platform, or the API-integration, causes deletion // attempts via an invalid handle to fail with the expected error code. -TYPED_TEST(RegistryTest, DeleteWithInvalidRegKey) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTest, DeleteWithInvalidRegKey) { + RegKey key; static const wchar_t kFooName[] = L"foo"; @@ -492,12 +464,9 @@ TYPED_TEST(RegistryTest, DeleteWithInvalidRegKey) { EXPECT_EQ(key.DeleteValue(kFooName), ERROR_INVALID_HANDLE); } -namespace { - // A test harness for tests that use HKLM to test WoW redirection and such. // TODO(https://crbug.com/377917): The tests here that write to the registry are // disabled because they need work to handle parallel runs of different tests. -template <typename Traits> class RegistryTestHKLM : public ::testing::Test { protected: enum : REGSAM { @@ -524,17 +493,10 @@ class RegistryTestHKLM : public ::testing::Test { const std::wstring foo_software_key_; }; -} // namespace - -TYPED_TEST_SUITE(RegistryTestHKLM, RegistryTypes, RegistryTypeNames); - -namespace { - -template <typename Traits> -class RegistryTestHKLMAdmin : public RegistryTestHKLM<Traits> { +class RegistryTestHKLMAdmin : public RegistryTestHKLM { protected: void SetUp() override { - if (!this->IsRedirectorPresent()) { + if (!IsRedirectorPresent()) { GTEST_SKIP(); } if (!::IsUserAnAdmin()) { @@ -543,52 +505,50 @@ class RegistryTestHKLMAdmin : public RegistryTestHKLM<Traits> { // Clean up any stale registry keys. for (const REGSAM mask : {this->kNativeViewMask, this->kRedirectedViewMask}) { - typename Traits::RegType key(Traits::Create()); - key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE | mask); - key.DeleteKey(kRootKey); + RegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE | mask) == + ERROR_SUCCESS) { + key.DeleteKey(kRootKey); + } } } }; -} // namespace - -TYPED_TEST_SUITE(RegistryTestHKLMAdmin, RegistryTypes, RegistryTypeNames); - // This test requires running as an Administrator as it tests redirected // registry writes to HKLM\Software // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx -TYPED_TEST(RegistryTestHKLMAdmin, Wow64RedirectedFromNative) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTestHKLMAdmin, Wow64RedirectedFromNative) { + RegKey key; // Test redirected key access from non-redirected. ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(), - KEY_WRITE | this->kRedirectedViewMask)); - ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, - this->foo_software_key_.c_str(), KEY_READ)); + key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), + KEY_WRITE | kRedirectedViewMask)); ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(), - KEY_READ | this->kNativeViewMask)); + key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); + ASSERT_NE(ERROR_SUCCESS, + key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), + KEY_READ | kNativeViewMask)); // Open the non-redirected view of the parent and try to delete the test key. ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE)); ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", - KEY_SET_VALUE | this->kNativeViewMask)); + KEY_SET_VALUE | kNativeViewMask)); ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); // Open the redirected view and delete the key created above. ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", - KEY_SET_VALUE | this->kRedirectedViewMask)); + KEY_SET_VALUE | kRedirectedViewMask)); ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); } // Test for the issue found in http://crbug.com/384587 where OpenKey would call // Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a // subsequent OpenKey call. -TYPED_TEST(RegistryTestHKLM, SameWowFlags) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTestHKLM, SameWowFlags) { + RegKey key; ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_READ | KEY_WOW64_64KEY)); @@ -597,27 +557,27 @@ TYPED_TEST(RegistryTestHKLM, SameWowFlags) { ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"Windows", KEY_READ | KEY_WOW64_64KEY)); } -TYPED_TEST(RegistryTestHKLMAdmin, Wow64NativeFromRedirected) { - typename TypeParam::RegType key(TypeParam::Create()); +TEST_F(RegistryTestHKLMAdmin, Wow64NativeFromRedirected) { + RegKey key; // Test non-redirected key access from redirected. ASSERT_EQ(ERROR_SUCCESS, - key.Create(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(), - KEY_WRITE | this->kNativeViewMask)); - ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, - this->foo_software_key_.c_str(), KEY_READ)); + key.Create(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), + KEY_WRITE | kNativeViewMask)); + ASSERT_EQ(ERROR_SUCCESS, + key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); ASSERT_NE(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, this->foo_software_key_.c_str(), - KEY_READ | this->kRedirectedViewMask)); + key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), + KEY_READ | kRedirectedViewMask)); // Open the redirected view of the parent and try to delete the test key // from the non-redirected view. ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", - KEY_SET_VALUE | this->kRedirectedViewMask)); + KEY_SET_VALUE | kRedirectedViewMask)); ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_LOCAL_MACHINE, L"Software", - KEY_SET_VALUE | this->kNativeViewMask)); + KEY_SET_VALUE | kNativeViewMask)); ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); } diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc index 42aefebfa..364254277 100644 --- a/base/win/scoped_handle_unittest.cc +++ b/base/win/scoped_handle_unittest.cc @@ -9,7 +9,6 @@ #include <string> #include <utility> -#include "base/base_switches.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/scoped_native_library.h" @@ -153,11 +152,7 @@ TEST_F(ScopedHandleDeathTest, HandleVerifierUntrackedHandle) { #endif TEST_F(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( "HandleVerifierChildProcess", command_line, LaunchOptions()); diff --git a/base/win/scoped_safearray.h b/base/win/scoped_safearray.h index d83fdf998..ab604ff63 100644 --- a/base/win/scoped_safearray.h +++ b/base/win/scoped_safearray.h @@ -107,8 +107,9 @@ class BASE_EXPORT ScopedSafearray { array_size_ = 0U; } - // This field is not a raw_ptr<> because it was filtered by the rewriter - // for: #union + // Cannot rewrite this pointer to raw_ptr<>, because this pointer + // comes from the operating system and may have been laundered + // if rewritten it may generate incorrect DPD error. RAW_PTR_EXCLUSION SAFEARRAY* safearray_ = nullptr; VARTYPE vartype_ = VT_EMPTY; pointer array_ = nullptr; |