summaryrefslogtreecommitdiff
path: root/chromium/chrome_elf
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 15:06:40 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:48:58 +0000
commitdaa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch)
tree96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/chrome_elf
parentbe59a35641616a4cf23c4a13fa0632624b021c1b (diff)
downloadqtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/chrome_elf')
-rw-r--r--chromium/chrome_elf/BUILD.gn35
-rw-r--r--chromium/chrome_elf/DEPS6
-rw-r--r--chromium/chrome_elf/blacklist/blacklist.cc10
-rw-r--r--chromium/chrome_elf/blacklist/blacklist.h4
-rw-r--r--chromium/chrome_elf/chrome_elf_main.cc4
-rw-r--r--chromium/chrome_elf/chrome_elf_main.h5
-rw-r--r--chromium/chrome_elf/chrome_elf_test_stubs.cc2
-rw-r--r--chromium/chrome_elf/chrome_elf_x64.def38
-rw-r--r--chromium/chrome_elf/chrome_elf_x86.def34
-rw-r--r--chromium/chrome_elf/crash/crash_helper.cc22
-rw-r--r--chromium/chrome_elf/crash/crash_helper.h3
-rw-r--r--chromium/chrome_elf/elf_imports_unittest.cc44
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry.cc161
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry.h27
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry_unittest.cc303
-rw-r--r--chromium/chrome_elf/run_all_unittests.cc3
16 files changed, 451 insertions, 250 deletions
diff --git a/chromium/chrome_elf/BUILD.gn b/chromium/chrome_elf/BUILD.gn
index f8ac4823fa0..1276a06ac02 100644
--- a/chromium/chrome_elf/BUILD.gn
+++ b/chromium/chrome_elf/BUILD.gn
@@ -28,6 +28,14 @@ windows_manifest("chrome_elf_manifest") {
]
}
+# Users of chrome_elf exports can depend on this target, which doesn't
+# pin them to linking either chrome_elf.dll or test_stubs.
+source_set("chrome_elf_main_include") {
+ sources = [
+ "chrome_elf_main.h",
+ ]
+}
+
# We should move chrome_result_codes.h to another target which does not bring
# in the world.
shared_library("chrome_elf") {
@@ -219,7 +227,6 @@ test("chrome_elf_unittests") {
sources = [
"blacklist/test/blacklist_test.cc",
"chrome_elf_util_unittest.cc",
- "elf_imports_unittest.cc",
"hook_util/test/hook_util_test.cc",
"nt_registry/nt_registry_unittest.cc",
"run_all_unittests.cc",
@@ -236,7 +243,6 @@ test("chrome_elf_unittests") {
":security",
"//base",
"//base/test:test_support",
- "//chrome",
"//chrome/common:version_header",
"//chrome/install_static:install_static_util",
"//chrome/install_static/test:test_support",
@@ -244,6 +250,28 @@ test("chrome_elf_unittests") {
"//sandbox",
"//testing/gtest",
]
+ data_deps = [
+ ":blacklist_test_dll_1",
+ ":blacklist_test_dll_2",
+ ":blacklist_test_dll_3",
+ ":chrome_elf",
+ ]
+}
+
+test("chrome_elf_import_unittests") {
+ output_name = "chrome_elf_import_unittests"
+ sources = [
+ "elf_imports_unittest.cc",
+ ]
+ include_dirs = [ "$target_gen_dir" ]
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//chrome",
+ "//chrome/install_static:install_static_util",
+ "//chrome/install_static/test:test_support",
+ "//testing/gtest",
+ ]
# It's not easily possible to have //chrome in data_deps without changing
# the //chrome target to bundle up both initial/chrome.exe and chrome.exe.
@@ -253,9 +281,6 @@ test("chrome_elf_unittests") {
"$root_out_dir/chrome.exe",
]
data_deps = [
- ":blacklist_test_dll_1",
- ":blacklist_test_dll_2",
- ":blacklist_test_dll_3",
":chrome_elf",
]
diff --git a/chromium/chrome_elf/DEPS b/chromium/chrome_elf/DEPS
index 484d1cf8239..978ee2231d3 100644
--- a/chromium/chrome_elf/DEPS
+++ b/chromium/chrome_elf/DEPS
@@ -1,11 +1,11 @@
include_rules = [
- "+sandbox",
- "+breakpad/src/client",
"+chrome/app/chrome_crash_reporter_client_win.h",
"+chrome/common/chrome_switches.h",
"+chrome/common/chrome_version.h",
"+chrome/install_static",
- "+third_party/crashpad/crashpad/client/crashpad_client.h",
"+components/crash/content/app/crashpad.h",
"+components/crash/core/common/crash_keys.h",
+ "+sandbox",
+ "+third_party/breakpad/breakpad/src/client",
+ "+third_party/crashpad/crashpad/client/crashpad_client.h",
]
diff --git a/chromium/chrome_elf/blacklist/blacklist.cc b/chromium/chrome_elf/blacklist/blacklist.cc
index d7609d4a851..cfcb86cf323 100644
--- a/chromium/chrome_elf/blacklist/blacklist.cc
+++ b/chromium/chrome_elf/blacklist/blacklist.cc
@@ -194,16 +194,6 @@ bool IsBlacklistInitialized() {
return g_blacklist_initialized;
}
-int GetBlacklistIndex(const wchar_t* dll_name) {
- for (int i = 0;
- i < static_cast<int>(kTroublesomeDllsMaxCount) && g_troublesome_dlls[i];
- ++i) {
- if (_wcsicmp(dll_name, g_troublesome_dlls[i]) == 0)
- return i;
- }
- return -1;
-}
-
bool AddDllToBlacklist(const wchar_t* dll_name) {
int blacklist_size = BlacklistSize();
// We need to leave one space at the end for the null pointer.
diff --git a/chromium/chrome_elf/blacklist/blacklist.h b/chromium/chrome_elf/blacklist/blacklist.h
index 0b6a0a72e1e..1f47dfe4099 100644
--- a/chromium/chrome_elf/blacklist/blacklist.h
+++ b/chromium/chrome_elf/blacklist/blacklist.h
@@ -42,10 +42,6 @@ extern "C" int BlacklistSize();
// Returns if true if the blacklist has been initialized.
extern "C" bool IsBlacklistInitialized();
-// Returns the index of the DLL named |dll_name| on the blacklist, or -1 if not
-// found.
-extern "C" int GetBlacklistIndex(const wchar_t* dll_name);
-
// Adds the given dll name to the blacklist. Returns true if the dll name is in
// the blacklist when this returns, false on error. Note that this will copy
// |dll_name| and will leak it on exit if the string is not subsequently removed
diff --git a/chromium/chrome_elf/chrome_elf_main.cc b/chromium/chrome_elf/chrome_elf_main.cc
index 2df2f56070d..50912fe157e 100644
--- a/chromium/chrome_elf/chrome_elf_main.cc
+++ b/chromium/chrome_elf/chrome_elf_main.cc
@@ -69,3 +69,7 @@ BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
void DumpProcessWithoutCrash() {
elf_crash::DumpWithoutCrashing();
}
+
+void SetMetricsClientId(const char* client_id) {
+ elf_crash::SetMetricsClientIdImpl(client_id);
+}
diff --git a/chromium/chrome_elf/chrome_elf_main.h b/chromium/chrome_elf/chrome_elf_main.h
index 71eb69b6d60..c313294fe6f 100644
--- a/chromium/chrome_elf/chrome_elf_main.h
+++ b/chromium/chrome_elf/chrome_elf_main.h
@@ -6,7 +6,7 @@
#define CHROME_ELF_CHROME_ELF_MAIN_H_
// These functions are the cross-module import interface to chrome_elf.dll.
-// It is used chrome.exe, chrome.dll and other clients of chrome_elf.
+// It is used by chrome.exe, chrome.dll and other clients of chrome_elf.
// In tests, these functions are stubbed by implementations in
// chrome_elf_test_stubs.cc.
extern "C" {
@@ -25,6 +25,9 @@ bool GetUserDataDirectoryThunk(wchar_t* user_data_dir,
void SignalInitializeCrashReporting();
void SignalChromeElf();
+// Sets the metrics client ID in crash keys.
+void SetMetricsClientId(const char* client_id);
+
} // extern "C"
#endif // CHROME_ELF_CHROME_ELF_MAIN_H_
diff --git a/chromium/chrome_elf/chrome_elf_test_stubs.cc b/chromium/chrome_elf/chrome_elf_test_stubs.cc
index bec3eea7276..240c6b22931 100644
--- a/chromium/chrome_elf/chrome_elf_test_stubs.cc
+++ b/chromium/chrome_elf/chrome_elf_test_stubs.cc
@@ -33,3 +33,5 @@ bool GetUserDataDirectoryThunk(wchar_t* user_data_dir,
return !user_data_dir_path.empty();
}
+
+void SetMetricsClientId(const char* client_id) {}
diff --git a/chromium/chrome_elf/chrome_elf_x64.def b/chromium/chrome_elf/chrome_elf_x64.def
index 184b7989a29..c8b8a249a56 100644
--- a/chromium/chrome_elf/chrome_elf_x64.def
+++ b/chromium/chrome_elf/chrome_elf_x64.def
@@ -7,21 +7,27 @@ EXPORTS
; When functions are added to this file, they must also be added to
; chrome_elf_x86.def
- ; From components/crash/content/app/crashpad.cc
- ClearCrashKeyValueImpl
- ClearCrashKeyValueImplEx
- RequestSingleCrashUploadImpl
- SetCrashKeyValueImpl
- SetCrashKeyValueImplEx
- SetUploadConsentImpl
-
- ; From components/crash/content/app/crashpad_win.cc
- CrashForException
- InjectDumpForHungInput
- InjectDumpForHungInputNoCrashKeys
+ ; From components/crash/content/app/crash_export_stubs.cc
+ ClearCrashKeyValueEx_ExportThunk
+ ClearCrashKeyValue_ExportThunk
+ CrashForException_ExportThunk
+ GetCrashReports_ExportThunk
+ InjectDumpForHungInputNoCrashKeys_ExportThunk
+ InjectDumpForHungInput_ExportThunk
+ RequestSingleCrashUpload_ExportThunk
+ SetCrashKeyValueEx_ExportThunk
+ SetCrashKeyValue_ExportThunk
+ SetUploadConsent_ExportThunk
+
+ ; X64-only exports
+ RegisterNonABICompliantCodeRange_ExportThunk
+ UnregisterNonABICompliantCodeRange_ExportThunk
+
+ ; This export is used by SyzyASAN, do not rename or remove without talking
+ ; to syzygy-team@chromium.org first.
+ SetCrashKeyValue = SetCrashKeyValue_ExportThunk
; From chrome_elf/crash_helper.cc
- GetCrashReportsImpl
SetMetricsClientId
; From chrome_elf_main.cc
@@ -35,11 +41,5 @@ EXPORTS
; From chrome_elf/blacklist.cc
AddDllToBlacklist
- GetBlacklistIndex
IsBlacklistInitialized
SuccessfullyBlocked
-
- ; X64-only exports
- ; From components/crash/content/app/crashpad_win.cc
- RegisterNonABICompliantCodeRange
- UnregisterNonABICompliantCodeRange
diff --git a/chromium/chrome_elf/chrome_elf_x86.def b/chromium/chrome_elf/chrome_elf_x86.def
index d49b5e50cca..e51bf1653cb 100644
--- a/chromium/chrome_elf/chrome_elf_x86.def
+++ b/chromium/chrome_elf/chrome_elf_x86.def
@@ -1,28 +1,29 @@
; Copyright 2013 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.
-
LIBRARY "chrome_elf.dll"
EXPORTS
; When functions are added to this file, they must also be added to
- ; chrome_elf_x64.def
-
- ; From components/crash/content/app/crashpad.cc
- ClearCrashKeyValueImpl
- ClearCrashKeyValueImplEx
- RequestSingleCrashUploadImpl
- SetCrashKeyValueImpl
- SetCrashKeyValueImplEx
- SetUploadConsentImpl
-
- ; From components/crash/content/app/crashpad_win.cc
- CrashForException
- InjectDumpForHungInput
- InjectDumpForHungInputNoCrashKeys
+ ; chrome_elf_x86.def
+
+ ; From components/crash/content/app/crash_export_stubs.cc
+ ClearCrashKeyValueEx_ExportThunk
+ ClearCrashKeyValue_ExportThunk
+ CrashForException_ExportThunk
+ GetCrashReports_ExportThunk
+ InjectDumpForHungInputNoCrashKeys_ExportThunk
+ InjectDumpForHungInput_ExportThunk
+ RequestSingleCrashUpload_ExportThunk
+ SetCrashKeyValueEx_ExportThunk
+ SetCrashKeyValue_ExportThunk
+ SetUploadConsent_ExportThunk
+
+ ; This export is used by SyzyASAN, do not rename or remove without talking
+ ; to syzygy-team@chromium.org first.
+ SetCrashKeyValue = SetCrashKeyValue_ExportThunk
; From chrome_elf/crash_helper.cc
- GetCrashReportsImpl
SetMetricsClientId
; From chrome_elf_main.cc
@@ -36,6 +37,5 @@ EXPORTS
; From chrome_elf/blacklist.cc
AddDllToBlacklist
- GetBlacklistIndex
IsBlacklistInitialized
SuccessfullyBlocked
diff --git a/chromium/chrome_elf/crash/crash_helper.cc b/chromium/chrome_elf/crash/crash_helper.cc
index e1bede4790c..e8e27dc4ebd 100644
--- a/chromium/chrome_elf/crash/crash_helper.cc
+++ b/chromium/chrome_elf/crash/crash_helper.cc
@@ -118,29 +118,11 @@ void DumpWithoutCrashing() {
crash_reporter::DumpWithoutCrashing();
}
-} // namespace elf_crash
-
-//------------------------------------------------------------------------------
-// Exported crash APIs for the rest of the process.
-//------------------------------------------------------------------------------
-
-// This helper is invoked by code in chrome.dll to retrieve the crash reports.
-// See CrashUploadListCrashpad. Note that we do not pass a std::vector here,
-// because we do not want to allocate/free in different modules. The returned
-// pointer is read-only.
-//
-// NOTE: Since the returned pointer references read-only memory that will be
-// cleaned up when this DLL unloads, be careful not to reference the memory
-// beyond that point (e.g. during tests).
-extern "C" {
-
-// This helper is invoked by debugging code in chrome to register the client
-// id.
-void SetMetricsClientId(const char* client_id) {
+void SetMetricsClientIdImpl(const char* client_id) {
if (!g_crash_helper_enabled)
return;
if (client_id)
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
-} // extern "C"
+} // namespace elf_crash
diff --git a/chromium/chrome_elf/crash/crash_helper.h b/chromium/chrome_elf/crash/crash_helper.h
index c1bc1cebd35..b15d67e8595 100644
--- a/chromium/chrome_elf/crash/crash_helper.h
+++ b/chromium/chrome_elf/crash/crash_helper.h
@@ -31,6 +31,9 @@ int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers);
// Generate a crash dump by calling into crashpad.
void DumpWithoutCrashing();
+// Set the metrics client ID in crash keys.
+void SetMetricsClientIdImpl(const char* client_id);
+
} // namespace elf_crash
#endif // CHROME_ELF_CRASH_CRASH_HELPER_H_
diff --git a/chromium/chrome_elf/elf_imports_unittest.cc b/chromium/chrome_elf/elf_imports_unittest.cc
index 96e078c96ca..dfcb9b9fddd 100644
--- a/chromium/chrome_elf/elf_imports_unittest.cc
+++ b/chromium/chrome_elf/elf_imports_unittest.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/base_paths.h"
+#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
@@ -17,7 +18,11 @@
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/test/launcher/test_launcher.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
#include "base/win/pe_image.h"
+#include "build/build_config.h"
+#include "chrome/install_static/test/scoped_install_details.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -75,8 +80,9 @@ TEST_F(ELFImportsTest, ChromeElfSanityCheck) {
GetImports(dll, &elf_imports);
// Check that ELF has imports.
- ASSERT_LT(0u, elf_imports.size()) << "Ensure the chrome_elf_unittests "
- "target was built, instead of chrome_elf_unittests.exe";
+ ASSERT_LT(0u, elf_imports.size())
+ << "Ensure the chrome_elf_import_unittests "
+ "target was built, instead of chrome_elf_import_unittests.exe";
static const char* const kValidFilePatterns[] = {
"KERNEL32.dll",
@@ -141,9 +147,9 @@ TEST_F(ELFImportsTest, DISABLED_ChromeElfLoadSanityTestImpl) {
ASSERT_TRUE(PathService::Get(base::DIR_EXE, &dll));
dll = dll.Append(L"chrome_elf.dll");
- // We don't expect user32 to be loaded in chrome_elf_unittests. If this test
- // case fails, then it means that a dependency on user32 has crept into the
- // chrome_elf_unittests executable, which needs to be removed.
+ // We don't expect user32 to be loaded in chrome_elf_import_unittests. If this
+ // test case fails, then it means that a dependency on user32 has crept into
+ // the chrome_elf_imports_unittests executable, which needs to be removed.
// NOTE: it may be a secondary dependency of another system DLL. If so,
// try adding a "/DELAYLOAD:<blah>.dll" to the build.gn file.
ASSERT_EQ(nullptr, ::GetModuleHandle(L"user32.dll"));
@@ -166,13 +172,31 @@ TEST_F(ELFImportsTest, ChromeExeSanityCheck) {
GetImports(exe, &exe_imports);
// Check that chrome.exe has imports.
- ASSERT_LT(0u, exe_imports.size()) << "Ensure the chrome_elf_unittests "
- "target was built, instead of chrome_elf_unittests.exe";
+ ASSERT_LT(0u, exe_imports.size())
+ << "Ensure the chrome_elf_import_unittests "
+ "target was built, instead of chrome_elf_import_unittests.exe";
// Chrome.exe's first import must be ELF.
- EXPECT_EQ("chrome_elf.dll", exe_imports[0]) <<
- "Illegal import order in chrome.exe (ensure the chrome_elf_unittest "
- "target was built, instead of just chrome_elf_unittests.exe)";
+ EXPECT_EQ("chrome_elf.dll", exe_imports[0])
+ << "Illegal import order in chrome.exe (ensure the "
+ "chrome_elf_import_unittest "
+ "target was built, instead of just chrome_elf_import_unittests.exe)";
}
} // namespace
+
+int main(int argc, char** argv) {
+ // Ensure that the CommandLine instance honors the command line passed in
+ // instead of the default behavior on Windows which is to use the shell32
+ // CommandLineToArgvW API. The chrome_elf_imports_unittests test suite should
+ // not depend on user32 directly or indirectly (For the curious shell32
+ // depends on user32)
+ base::CommandLine::InitUsingArgvForTesting(argc, argv);
+
+ install_static::ScopedInstallDetails scoped_install_details;
+
+ base::TestSuite test_suite(argc, argv);
+ return base::LaunchUnitTests(
+ argc, argv,
+ base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chromium/chrome_elf/nt_registry/nt_registry.cc b/chromium/chrome_elf/nt_registry/nt_registry.cc
index aca2a074da9..69b11c7557e 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry.cc
+++ b/chromium/chrome_elf/nt_registry/nt_registry.cc
@@ -17,6 +17,8 @@ NtCreateKeyFunction g_nt_create_key = nullptr;
NtDeleteKeyFunction g_nt_delete_key = nullptr;
NtOpenKeyExFunction g_nt_open_key_ex = nullptr;
NtCloseFunction g_nt_close = nullptr;
+NtQueryKeyFunction g_nt_query_key = nullptr;
+NtEnumerateKeyFunction g_nt_enumerate_key = nullptr;
NtQueryValueKeyFunction g_nt_query_value_key = nullptr;
NtSetValueKeyFunction g_nt_set_value_key = nullptr;
@@ -28,6 +30,10 @@ wchar_t g_kRegPathHKLM[] = L"\\Registry\\Machine\\";
wchar_t g_kRegPathHKCU[nt::g_kRegMaxPathLen + 1] = L"";
wchar_t g_current_user_sid_string[nt::g_kRegMaxPathLen + 1] = L"";
+// Max number of tries for system API calls when STATUS_BUFFER_TOO_SMALL can be
+// returned.
+enum { kMaxTries = 5 };
+
// For testing only.
wchar_t g_HKLM_override[nt::g_kRegMaxPathLen + 1] = L"";
wchar_t g_HKCU_override[nt::g_kRegMaxPathLen + 1] = L"";
@@ -88,6 +94,12 @@ bool InitNativeRegApi() {
g_nt_close =
reinterpret_cast<NtCloseFunction>(::GetProcAddress(ntdll, "NtClose"));
+ g_nt_query_key = reinterpret_cast<NtQueryKeyFunction>(
+ ::GetProcAddress(ntdll, "NtQueryKey"));
+
+ g_nt_enumerate_key = reinterpret_cast<NtEnumerateKeyFunction>(
+ ::GetProcAddress(ntdll, "NtEnumerateKey"));
+
g_nt_query_value_key = reinterpret_cast<NtQueryValueKeyFunction>(
::GetProcAddress(ntdll, "NtQueryValueKey"));
@@ -95,8 +107,8 @@ bool InitNativeRegApi() {
::GetProcAddress(ntdll, "NtSetValueKey"));
if (!g_rtl_init_unicode_string || !g_nt_create_key || !g_nt_open_key_ex ||
- !g_nt_delete_key || !g_nt_close || !g_nt_query_value_key ||
- !g_nt_set_value_key)
+ !g_nt_delete_key || !g_nt_close || !g_nt_query_key ||
+ !g_nt_enumerate_key || !g_nt_query_value_key || !g_nt_set_value_key)
return false;
// We need to set HKCU based on the sid of the current user account.
@@ -620,8 +632,8 @@ bool CreateRegKey(ROOT_KEY root,
::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
return false;
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
if (root == nt::AUTO)
root = g_system_install ? nt::HKLM : nt::HKCU;
@@ -711,8 +723,8 @@ bool OpenRegKey(ROOT_KEY root,
::wcsnlen(key_path, g_kRegMaxPathLen + 1) == g_kRegMaxPathLen + 1)
return false;
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
NTSTATUS status = STATUS_UNSUCCESSFUL;
UNICODE_STRING key_path_uni = {};
@@ -746,17 +758,12 @@ bool OpenRegKey(ROOT_KEY root,
}
bool DeleteRegKey(HANDLE key) {
- if (!g_initialized)
- InitNativeRegApi();
-
- NTSTATUS status = STATUS_UNSUCCESSFUL;
-
- status = g_nt_delete_key(key);
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
- if (NT_SUCCESS(status))
- return true;
+ NTSTATUS status = g_nt_delete_key(key);
- return false;
+ return NT_SUCCESS(status);
}
// wrapper function
@@ -791,27 +798,27 @@ bool QueryRegKeyValue(HANDLE key,
const wchar_t* value_name,
ULONG* out_type,
std::vector<BYTE>* out_buffer) {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
- NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
UNICODE_STRING value_uni = {};
g_rtl_init_unicode_string(&value_uni, value_name);
- DWORD size_needed = 0;
-
- // First call to find out how much room we need for the value!
- ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
- nullptr, 0, &size_needed);
- if (ntstatus != STATUS_BUFFER_TOO_SMALL)
- return false;
- std::unique_ptr<BYTE[]> buffer(new BYTE[size_needed]);
- KEY_VALUE_FULL_INFORMATION* value_info =
- reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.get());
+ // Use a loop here, to be a little more tolerant of concurrent registry
+ // changes.
+ NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
+ int tries = 0;
+ DWORD size_needed = 1;
+ std::vector<BYTE> buffer;
+ KEY_VALUE_FULL_INFORMATION* value_info = nullptr;
+ do {
+ buffer.resize(size_needed);
+ value_info = reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.data());
+
+ ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
+ value_info, size_needed, &size_needed);
+ } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries);
- // Second call to get the value.
- ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
- value_info, size_needed, &size_needed);
if (!NT_SUCCESS(ntstatus))
return false;
@@ -967,8 +974,8 @@ bool SetRegKeyValue(HANDLE key,
ULONG type,
const BYTE* data,
DWORD data_size) {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
UNICODE_STRING value_uni = {};
@@ -1093,26 +1100,98 @@ bool SetRegValueMULTISZ(ROOT_KEY root,
}
//------------------------------------------------------------------------------
+// Enumeration Support
+//------------------------------------------------------------------------------
+
+bool QueryRegEnumerationInfo(HANDLE key, ULONG* out_subkey_count) {
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
+
+ // Use a loop here, to be a little more tolerant of concurrent registry
+ // changes.
+ NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
+ int tries = 0;
+ // Start with sizeof the structure. It's very common for the variable sized
+ // "Class" element to be of length 0.
+ DWORD size_needed = sizeof(KEY_FULL_INFORMATION);
+ std::vector<BYTE> buffer;
+ KEY_FULL_INFORMATION* key_info = nullptr;
+ do {
+ buffer.resize(size_needed);
+ key_info = reinterpret_cast<KEY_FULL_INFORMATION*>(buffer.data());
+
+ ntstatus = g_nt_query_key(key, KeyFullInformation, key_info, size_needed,
+ &size_needed);
+ } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries);
+
+ if (!NT_SUCCESS(ntstatus))
+ return false;
+
+ // Move desired information to out variables.
+ *out_subkey_count = key_info->SubKeys;
+
+ return true;
+}
+
+bool QueryRegSubkey(HANDLE key,
+ ULONG subkey_index,
+ std::wstring* out_subkey_name) {
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
+
+ // Use a loop here, to be a little more tolerant of concurrent registry
+ // changes.
+ NTSTATUS ntstatus = STATUS_UNSUCCESSFUL;
+ int tries = 0;
+ // Start with sizeof the structure, plus 12 characters. It's very common for
+ // key names to be < 12 characters (without being inefficient as an initial
+ // allocation).
+ DWORD size_needed = sizeof(KEY_BASIC_INFORMATION) + (12 * sizeof(wchar_t));
+ std::vector<BYTE> buffer;
+ KEY_BASIC_INFORMATION* subkey_info = nullptr;
+ do {
+ buffer.resize(size_needed);
+ subkey_info = reinterpret_cast<KEY_BASIC_INFORMATION*>(buffer.data());
+
+ ntstatus = g_nt_enumerate_key(key, subkey_index, KeyBasicInformation,
+ subkey_info, size_needed, &size_needed);
+ } while (ntstatus == STATUS_BUFFER_TOO_SMALL && ++tries < kMaxTries);
+
+ if (!NT_SUCCESS(ntstatus))
+ return false;
+
+ // Move desired information to out variables.
+ // NOTE: NameLength is size of Name array in bytes. Name array is also
+ // NOT null terminated!
+ BYTE* name = reinterpret_cast<BYTE*>(subkey_info->Name);
+ std::vector<BYTE> content(name, name + subkey_info->NameLength);
+ EnsureTerminatedSZ(&content, false);
+ out_subkey_name->assign(reinterpret_cast<wchar_t*>(content.data()));
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
// Utils
//------------------------------------------------------------------------------
const wchar_t* GetCurrentUserSidString() {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return nullptr;
return g_current_user_sid_string;
}
bool IsCurrentProcWow64() {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
return g_wow64_proc;
}
bool SetTestingOverride(ROOT_KEY root, const std::wstring& new_path) {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return false;
std::wstring sani_new_path = new_path;
SanitizeSubkeyPath(&sani_new_path);
@@ -1128,8 +1207,8 @@ bool SetTestingOverride(ROOT_KEY root, const std::wstring& new_path) {
}
std::wstring GetTestingOverride(ROOT_KEY root) {
- if (!g_initialized)
- InitNativeRegApi();
+ if (!g_initialized && !InitNativeRegApi())
+ return std::wstring();
if (root == HKCU || (root == AUTO && !g_system_install))
return g_HKCU_override;
diff --git a/chromium/chrome_elf/nt_registry/nt_registry.h b/chromium/chrome_elf/nt_registry/nt_registry.h
index 5db8771c030..c5d37a3333e 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry.h
+++ b/chromium/chrome_elf/nt_registry/nt_registry.h
@@ -13,8 +13,10 @@
// Note that this API is currently lazy initialized. Any function that is
// NOT merely a wrapper function (i.e. any function that directly interacts with
// NTDLL) will immediately check:
-// if (!g_initialized)
-// InitNativeRegApi();
+//
+// if (!g_initialized && !InitNativeRegApi())
+// return false;
+//
// There is currently no multi-threading lock around the lazy initialization,
// as the main client for this API (chrome_elf) does not introduce
// a multi-threading concern. This can easily be changed if needed.
@@ -73,11 +75,13 @@ bool OpenRegKey(ROOT_KEY root,
// Delete a registry key.
// - Caller must still call CloseRegKey after the delete.
+// - Non-recursive. Must have no subkeys.
bool DeleteRegKey(HANDLE key);
// Delete a registry key.
// - WRAPPER: Function opens and closes the target key for caller.
// - Use |wow64_override| to force redirection behaviour, or pass nt::NONE.
+// - Non-recursive. Must have no subkeys.
bool DeleteRegKey(ROOT_KEY root,
WOW64_OVERRIDE wow64_override,
const wchar_t* key_path);
@@ -223,6 +227,25 @@ bool SetRegValueMULTISZ(ROOT_KEY root,
const std::vector<std::wstring>& values);
//------------------------------------------------------------------------------
+// Enumeration Support
+//------------------------------------------------------------------------------
+
+// Query key information for subkey enumeration.
+// - Key handle should have been opened with OpenRegKey (with at least
+// KEY_ENUMERATE_SUB_KEYS access rights).
+// - Currently only returns the number of subkeys. Use |subkey_count|
+// in a loop for calling QueryRegSubkey.
+bool QueryRegEnumerationInfo(HANDLE key, ULONG* out_subkey_count);
+
+// Enumerate subkeys by index.
+// - Key handle should have been opened with OpenRegKey (with at least
+// KEY_ENUMERATE_SUB_KEYS access rights).
+// - Get subkey count by calling QueryRegEnumerationInfo.
+bool QueryRegSubkey(HANDLE key,
+ ULONG subkey_index,
+ std::wstring* out_subkey_name);
+
+//------------------------------------------------------------------------------
// Utils
//------------------------------------------------------------------------------
diff --git a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
index ee8f1af0ee8..08728dbcaee 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
+++ b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
@@ -8,6 +8,7 @@
#include <rpc.h>
#include <stddef.h>
+#include "base/callback_helpers.h"
#include "base/test/test_reg_util_win.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -316,7 +317,7 @@ class NtRegistryTest : public testing::Test {
// NT registry API tests
//------------------------------------------------------------------------------
-TEST_F(NtRegistryTest, API_DWORD) {
+TEST_F(NtRegistryTest, ApiDword) {
HANDLE key_handle;
const wchar_t* dword_val_name = L"DwordTestValue";
DWORD dword_val = 1234;
@@ -326,6 +327,8 @@ TEST_F(NtRegistryTest, API_DWORD) {
&key_handle));
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
ASSERT_NE(key_handle, nullptr);
+ base::ScopedClosureRunner key_closer(
+ base::BindOnce(&nt::CloseRegKey, key_handle));
DWORD get_dword = 0;
EXPECT_FALSE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword));
@@ -335,14 +338,12 @@ TEST_F(NtRegistryTest, API_DWORD) {
// Get
EXPECT_TRUE(nt::QueryRegValueDWORD(key_handle, dword_val_name, &get_dword));
- EXPECT_TRUE(get_dword == dword_val);
+ EXPECT_EQ(get_dword, dword_val);
- // Clean up
- EXPECT_TRUE(nt::DeleteRegKey(key_handle));
- nt::CloseRegKey(key_handle);
+ // Clean up done by NtRegistryTest.
}
-TEST_F(NtRegistryTest, API_SZ) {
+TEST_F(NtRegistryTest, ApiSz) {
HANDLE key_handle;
const wchar_t* sz_val_name = L"SzTestValue";
std::wstring sz_val = L"blah de blah de blahhhhh.";
@@ -363,6 +364,8 @@ TEST_F(NtRegistryTest, API_SZ) {
&key_handle));
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
ASSERT_NE(key_handle, nullptr);
+ base::ScopedClosureRunner key_closer(
+ base::BindOnce(&nt::CloseRegKey, key_handle));
std::wstring get_sz;
EXPECT_FALSE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
@@ -386,44 +389,26 @@ TEST_F(NtRegistryTest, API_SZ) {
// Get
// ------------------------------
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
- EXPECT_TRUE(get_sz.compare(sz_val) == 0);
+ EXPECT_EQ(get_sz, sz_val);
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name2, &get_sz));
- EXPECT_TRUE(get_sz.compare(sz_val2) == 0);
+ EXPECT_EQ(get_sz, sz_val2);
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name3, &get_sz));
// Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(get_sz.compare(sz_val3) == 0);
+ EXPECT_EQ(get_sz, sz_val3);
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name4, &get_sz));
// Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(get_sz.compare(sz_val3) == 0);
+ EXPECT_EQ(get_sz, sz_val3);
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name5, &get_sz));
// Should be adjusted under the hood to an empty string.
- EXPECT_TRUE(get_sz.compare(sz_val2) == 0);
+ EXPECT_EQ(get_sz, sz_val2);
- // Clean up
- // ------------------------------
- EXPECT_TRUE(nt::DeleteRegKey(key_handle));
- nt::CloseRegKey(key_handle);
+ // Clean up done by NtRegistryTest.
}
-TEST_F(NtRegistryTest, API_MULTISZ) {
+TEST_F(NtRegistryTest, ApiMultiSz) {
HANDLE key_handle;
- const wchar_t* multisz_val_name = L"SzmultiTestValue";
- std::vector<std::wstring> multisz_val;
- std::wstring multi1 = L"one";
- std::wstring multi2 = L"two";
- std::wstring multi3 = L"three";
- const wchar_t* multisz_val_name2 = L"SzmultiTestValueBad";
- std::wstring multi_empty = L"";
- const wchar_t* multisz_val_name3 = L"SzmultiTestValueMalformed";
- const wchar_t* multisz_val_name4 = L"SzmultiTestValueMalformed2";
- const wchar_t* multisz_val_name5 = L"SzmultiTestValueMalformed3";
- const wchar_t* multisz_val_name6 = L"SzmultiTestValueMalformed4";
- std::wstring multisz_val3 = L"malformed";
- BYTE* multisz_val3_byte = reinterpret_cast<BYTE*>(&multisz_val3[0]);
- std::vector<BYTE> malform;
- for (size_t i = 0; i < (multisz_val3.size() * sizeof(wchar_t)); i++)
- malform.push_back(multisz_val3_byte[i]);
- const wchar_t* multisz_val_name7 = L"SzmultiTestValueSize0";
+ std::vector<std::wstring> multisz_val_set;
+ std::vector<std::wstring> multisz_val_get;
// Create a subkey to play under.
// ------------------------------
@@ -431,113 +416,115 @@ TEST_F(NtRegistryTest, API_MULTISZ) {
&key_handle));
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
ASSERT_NE(key_handle, nullptr);
+ base::ScopedClosureRunner key_closer(
+ base::BindOnce(&nt::CloseRegKey, key_handle));
- multisz_val.push_back(multi1);
- multisz_val.push_back(multi2);
- multisz_val.push_back(multi3);
-
- // Set
+ // Test 1 - Success
// ------------------------------
+ const wchar_t* multisz_val_name = L"SzmultiTestValue";
+ std::wstring multi1 = L"one";
+ std::wstring multi2 = L"two";
+ std::wstring multi3 = L"three";
+
+ multisz_val_set.push_back(multi1);
+ multisz_val_set.push_back(multi2);
+ multisz_val_set.push_back(multi3);
EXPECT_TRUE(
- nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val));
- multisz_val.clear();
- multisz_val.push_back(multi_empty);
+ nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val_set));
EXPECT_TRUE(
- nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val));
- multisz_val.clear();
+ nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val_get));
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
+ multisz_val_set.clear();
+ multisz_val_get.clear();
- // No null terminator.
+ // Test 2 - Bad value
+ // ------------------------------
+ const wchar_t* multisz_val_name2 = L"SzmultiTestValueBad";
+ std::wstring multi_empty = L"";
+
+ multisz_val_set.push_back(multi_empty);
+ EXPECT_TRUE(
+ nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val_set));
+
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2,
+ &multisz_val_get));
+ EXPECT_EQ(multisz_val_get.size(), static_cast<DWORD>(0));
+ multisz_val_set.clear();
+ multisz_val_get.clear();
+
+ // Test 3 - Malformed
+ // ------------------------------
+ std::wstring multisz_val3 = L"malformed";
+ multisz_val_set.push_back(multisz_val3);
+ BYTE* multisz_val3_byte = reinterpret_cast<BYTE*>(&multisz_val3[0]);
+ std::vector<BYTE> malform;
+ for (size_t i = 0; i < (multisz_val3.size() * sizeof(wchar_t)); i++)
+ malform.push_back(multisz_val3_byte[i]);
+
+ // 3.1: No null terminator.
+ // ------------------------------
+ const wchar_t* multisz_val_name3 = L"SzmultiTestValueMalformed";
EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name3, REG_MULTI_SZ,
malform.data(),
static_cast<DWORD>(malform.size())));
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name3,
+ &multisz_val_get));
+ // Should be adjusted under the hood to equal multisz_val3.
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
+ multisz_val_get.clear();
+
+ // 3.2: Single trailing 0 byte.
+ // ------------------------------
+ const wchar_t* multisz_val_name4 = L"SzmultiTestValueMalformed2";
malform.push_back(0);
- // Single trailing 0 byte.
EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name4, REG_MULTI_SZ,
malform.data(),
static_cast<DWORD>(malform.size())));
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name4,
+ &multisz_val_get));
+ // Should be adjusted under the hood to equal multisz_val3.
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
+ multisz_val_get.clear();
+
+ // 3.3: Two trailing 0 bytes.
+ // ------------------------------
+ const wchar_t* multisz_val_name5 = L"SzmultiTestValueMalformed3";
malform.push_back(0);
- // Two trailing 0 bytes.
EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name5, REG_MULTI_SZ,
malform.data(),
static_cast<DWORD>(malform.size())));
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name5,
+ &multisz_val_get));
+ // Should be adjusted under the hood to equal multisz_val3.
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
+ multisz_val_get.clear();
+
+ // 3.4: Three trailing 0 bytes.
+ // ------------------------------
+ const wchar_t* multisz_val_name6 = L"SzmultiTestValueMalformed4";
malform.push_back(0);
- // Three trailing 0 bytes.
EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name6, REG_MULTI_SZ,
malform.data(),
static_cast<DWORD>(malform.size())));
-
- // Size 0 value.
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name6,
+ &multisz_val_get));
+ // Should be adjusted under the hood to equal multisz_val3.
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
+ multisz_val_set.clear();
+ multisz_val_get.clear();
+
+ // Test 4 - Size zero
+ // ------------------------------
+ const wchar_t* multisz_val_name7 = L"SzmultiTestValueSize0";
EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name7, REG_MULTI_SZ,
nullptr, 0));
+ EXPECT_TRUE(nt::QueryRegValueMULTISZ(key_handle, multisz_val_name7,
+ &multisz_val_get));
+ // Should be empty.
+ EXPECT_EQ(multisz_val_get, multisz_val_set);
- // Get
- // ------------------------------
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val));
- if (multisz_val.size() == 3) {
- EXPECT_TRUE(multi1.compare(multisz_val.at(0)) == 0);
- EXPECT_TRUE(multi2.compare(multisz_val.at(1)) == 0);
- EXPECT_TRUE(multi3.compare(multisz_val.at(2)) == 0);
- } else {
- EXPECT_TRUE(false);
- }
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2, &multisz_val));
- EXPECT_EQ(multisz_val.size(), static_cast<DWORD>(0));
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name3, &multisz_val));
- if (multisz_val.size(), 1) {
- // Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0);
- } else {
- EXPECT_TRUE(false);
- }
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name4, &multisz_val));
- if (multisz_val.size(), 1) {
- // Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0);
- } else {
- EXPECT_TRUE(false);
- }
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name5, &multisz_val));
- if (multisz_val.size(), 1) {
- // Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0);
- } else {
- EXPECT_TRUE(false);
- }
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name6, &multisz_val));
- if (multisz_val.size(), 1) {
- // Should be adjusted under the hood to equal sz_val3.
- EXPECT_TRUE(multisz_val3.compare(multisz_val.at(0)) == 0);
- } else {
- EXPECT_TRUE(false);
- }
- multisz_val.clear();
-
- EXPECT_TRUE(
- nt::QueryRegValueMULTISZ(key_handle, multisz_val_name7, &multisz_val));
- // Should be adjusted under the hood to an empty string.
- EXPECT_TRUE(multisz_val.empty());
-
- // Clean up
- // ------------------------------
- EXPECT_TRUE(nt::DeleteRegKey(key_handle));
- nt::CloseRegKey(key_handle);
+ // Clean up done by NtRegistryTest.
}
TEST_F(NtRegistryTest, CreateRegKeyRecursion) {
@@ -573,6 +560,90 @@ TEST_F(NtRegistryTest, CreateRegKeyRecursion) {
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
ASSERT_NE(key_handle, nullptr);
nt::CloseRegKey(key_handle);
+
+ // Clean up done by NtRegistryTest.
+}
+
+TEST_F(NtRegistryTest, ApiEnumeration) {
+ HANDLE key_handle;
+ HANDLE subkey_handle;
+ static constexpr wchar_t key[] = L"NTRegistry\\enum";
+ static constexpr wchar_t subkey1[] = L"NTRegistry\\enum\\subkey1";
+ static constexpr wchar_t subkey2[] = L"NTRegistry\\enum\\subkey2";
+ static constexpr wchar_t subkey3[] = L"NTRegistry\\enum\\subkey3";
+ static constexpr const wchar_t* check_names[] = {
+ L"subkey1", L"subkey2", L"subkey3",
+ };
+ // Test out the "(Default)" value name in this suite.
+ static constexpr wchar_t subkey_val_name[] = L"";
+ DWORD subkey_val = 1234;
+
+ // Create a subkey to play under.
+ // ------------------------------
+ ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, key, KEY_ALL_ACCESS, &key_handle));
+ ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
+ ASSERT_NE(key_handle, nullptr);
+ base::ScopedClosureRunner key_closer(
+ base::BindOnce(&nt::CloseRegKey, key_handle));
+
+ // Set
+ // ------------------------------
+ // Sub-subkey with a default value.
+ ASSERT_TRUE(
+ nt::CreateRegKey(nt::HKCU, subkey1, KEY_ALL_ACCESS, &subkey_handle));
+ ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
+ ASSERT_NE(subkey_handle, nullptr);
+ EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
+ nt::CloseRegKey(subkey_handle);
+
+ // Sub-subkey with a default value.
+ ASSERT_TRUE(
+ nt::CreateRegKey(nt::HKCU, subkey2, KEY_ALL_ACCESS, &subkey_handle));
+ ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
+ ASSERT_NE(subkey_handle, nullptr);
+ EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
+ nt::CloseRegKey(subkey_handle);
+
+ // Sub-subkey with a default value.
+ ASSERT_TRUE(
+ nt::CreateRegKey(nt::HKCU, subkey3, KEY_ALL_ACCESS, &subkey_handle));
+ ASSERT_NE(subkey_handle, INVALID_HANDLE_VALUE);
+ ASSERT_NE(subkey_handle, nullptr);
+ EXPECT_TRUE(nt::SetRegValueDWORD(subkey_handle, subkey_val_name, subkey_val));
+ nt::CloseRegKey(subkey_handle);
+
+ // Get (via enumeration)
+ // ------------------------------
+ ULONG subkey_count = 0;
+ EXPECT_TRUE(nt::QueryRegEnumerationInfo(key_handle, &subkey_count));
+ ASSERT_EQ(subkey_count, ULONG{3});
+
+ std::wstring subkey_name;
+ for (ULONG i = 0; i < subkey_count; i++) {
+ ASSERT_TRUE(nt::QueryRegSubkey(key_handle, i, &subkey_name));
+
+ bool found = false;
+ for (size_t index = 0; index < arraysize(check_names); index++) {
+ if (0 == subkey_name.compare(check_names[index])) {
+ found = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(found);
+
+ // Grab the default DWORD value out of this subkey.
+ DWORD value = 0;
+ std::wstring temp(key);
+ temp.append(L"\\");
+ temp.append(subkey_name);
+ EXPECT_TRUE(nt::QueryRegValueDWORD(nt::HKCU, nt::NONE, temp.c_str(),
+ subkey_val_name, &value));
+ EXPECT_EQ(value, subkey_val);
+ }
+ // Also test a known bad index.
+ EXPECT_FALSE(nt::QueryRegSubkey(key_handle, subkey_count, &subkey_name));
+
+ // Clean up done by NtRegistryTest.
}
} // namespace
diff --git a/chromium/chrome_elf/run_all_unittests.cc b/chromium/chrome_elf/run_all_unittests.cc
index 0f2c930d84a..1f00c731e72 100644
--- a/chromium/chrome_elf/run_all_unittests.cc
+++ b/chromium/chrome_elf/run_all_unittests.cc
@@ -20,8 +20,7 @@ int main(int argc, char** argv) {
install_static::ScopedInstallDetails scoped_install_details;
base::TestSuite test_suite(argc, argv);
- int ret = base::LaunchUnitTests(
+ return base::LaunchUnitTests(
argc, argv,
base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
- return ret;
}