summaryrefslogtreecommitdiff
path: root/chromium/chrome_elf
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/chrome_elf
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/chrome_elf')
-rw-r--r--chromium/chrome_elf/BUILD.gn33
-rw-r--r--chromium/chrome_elf/DEPS1
-rw-r--r--chromium/chrome_elf/chrome_elf.def16
-rw-r--r--chromium/chrome_elf/chrome_elf_main.cc10
-rw-r--r--chromium/chrome_elf/chrome_elf_main.h24
-rw-r--r--chromium/chrome_elf/chrome_elf_test_stubs.cc35
-rw-r--r--chromium/chrome_elf/chrome_elf_x64.def45
-rw-r--r--chromium/chrome_elf/chrome_elf_x86.def41
-rw-r--r--chromium/chrome_elf/crash/crash_helper.cc15
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry.cc124
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry.h14
-rw-r--r--chromium/chrome_elf/nt_registry/nt_registry_unittest.cc119
12 files changed, 388 insertions, 89 deletions
diff --git a/chromium/chrome_elf/BUILD.gn b/chromium/chrome_elf/BUILD.gn
index 8ae2c85d230..f8ac4823fa0 100644
--- a/chromium/chrome_elf/BUILD.gn
+++ b/chromium/chrome_elf/BUILD.gn
@@ -26,17 +26,21 @@ windows_manifest("chrome_elf_manifest") {
sources = [
as_invoker_manifest,
]
- type = "dll"
}
# We should move chrome_result_codes.h to another target which does not bring
# in the world.
shared_library("chrome_elf") {
sources = [
- "chrome_elf.def",
"chrome_elf_main.cc",
"chrome_elf_main.h",
]
+ if (target_cpu == "x86") {
+ sources += [ "chrome_elf_x86.def" ]
+ } else {
+ sources += [ "chrome_elf_x64.def" ]
+ }
+
deps = [
":blacklist",
":chrome_elf_manifest",
@@ -49,6 +53,7 @@ shared_library("chrome_elf") {
"//build/config:exe_and_shlib_deps",
"//chrome/install_static:install_static_util",
"//chrome/install_static:primary_module",
+ "//components/crash/content/app:crash_export_thunks",
]
configs += [ "//build/config/win:windowed" ]
configs -= [ "//build/config/win:console" ]
@@ -67,6 +72,22 @@ shared_library("chrome_elf") {
}
}
+# For code that isn't Chrome-the browser, like test binaries, these stubs stand
+# in for chrome_elf.;
+static_library("test_stubs") {
+ testonly = true
+
+ sources = [
+ "chrome_elf_main.h",
+ "chrome_elf_test_stubs.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//chrome/common:constants",
+ ]
+}
+
##------------------------------------------------------------------------------
## source sets
##------------------------------------------------------------------------------
@@ -145,15 +166,15 @@ static_library("crash") {
]
deps = [
":hook_util",
- "//base:base", # This needs to go. DEP of app, crash_keys, client.
+ "//base", # This needs to go. DEP of app, crash_keys, client.
"//base:base_static", # pe_image
"//chrome/install_static:install_static_util",
- "//components/crash/content/app:app",
+ "//components/crash/content/app",
"//components/crash/core/common", # crash_keys
"//components/version_info:channel",
"//content/public/common:result_codes",
"//gpu/config:crash_keys",
- "//third_party/crashpad/crashpad/client:client", # DumpWithoutCrash
+ "//third_party/crashpad/crashpad/client", # DumpWithoutCrash
]
}
@@ -219,6 +240,7 @@ test("chrome_elf_unittests") {
"//chrome/common:version_header",
"//chrome/install_static:install_static_util",
"//chrome/install_static/test:test_support",
+ "//components/crash/content/app:test_support",
"//sandbox",
"//testing/gtest",
]
@@ -262,6 +284,7 @@ shared_library("blacklist_test_main_dll") {
"//base",
"//build/config:exe_and_shlib_deps",
"//chrome/install_static:install_static_util",
+ "//components/crash/content/app:test_support",
]
}
diff --git a/chromium/chrome_elf/DEPS b/chromium/chrome_elf/DEPS
index a0ef5ecb484..484d1cf8239 100644
--- a/chromium/chrome_elf/DEPS
+++ b/chromium/chrome_elf/DEPS
@@ -2,6 +2,7 @@ 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",
diff --git a/chromium/chrome_elf/chrome_elf.def b/chromium/chrome_elf/chrome_elf.def
deleted file mode 100644
index d1517e2be81..00000000000
--- a/chromium/chrome_elf/chrome_elf.def
+++ /dev/null
@@ -1,16 +0,0 @@
-; 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
- AddDllToBlacklist
- GetBlacklistIndex
- GetInstallDetailsPayload
- GetUserDataDirectoryThunk
- IsBlacklistInitialized
- SignalChromeElf
- SignalInitializeCrashReporting
- SuccessfullyBlocked
- DumpProcessWithoutCrash
diff --git a/chromium/chrome_elf/chrome_elf_main.cc b/chromium/chrome_elf/chrome_elf_main.cc
index d830563c147..2df2f56070d 100644
--- a/chromium/chrome_elf/chrome_elf_main.cc
+++ b/chromium/chrome_elf/chrome_elf_main.cc
@@ -29,10 +29,10 @@ void SignalChromeElf() {
blacklist::ResetBeacon();
}
-extern "C" void GetUserDataDirectoryThunk(wchar_t* user_data_dir,
- size_t user_data_dir_length,
- wchar_t* invalid_user_data_dir,
- size_t invalid_user_data_dir_length) {
+bool GetUserDataDirectoryThunk(wchar_t* user_data_dir,
+ size_t user_data_dir_length,
+ wchar_t* invalid_user_data_dir,
+ size_t invalid_user_data_dir_length) {
std::wstring user_data_dir_str, invalid_user_data_dir_str;
bool ret = install_static::GetUserDataDirectory(&user_data_dir_str,
&invalid_user_data_dir_str);
@@ -42,6 +42,8 @@ extern "C" void GetUserDataDirectoryThunk(wchar_t* user_data_dir,
_TRUNCATE);
wcsncpy_s(invalid_user_data_dir, invalid_user_data_dir_length,
invalid_user_data_dir_str.c_str(), _TRUNCATE);
+
+ return true;
}
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved) {
diff --git a/chromium/chrome_elf/chrome_elf_main.h b/chromium/chrome_elf/chrome_elf_main.h
index 3923afd7960..71eb69b6d60 100644
--- a/chromium/chrome_elf/chrome_elf_main.h
+++ b/chromium/chrome_elf/chrome_elf_main.h
@@ -5,8 +5,26 @@
#ifndef CHROME_ELF_CHROME_ELF_MAIN_H_
#define CHROME_ELF_CHROME_ELF_MAIN_H_
-extern "C" void SignalInitializeCrashReporting();
-extern "C" void SignalChromeElf();
-extern "C" void DumpProcessWithoutCrash();
+// 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.
+// In tests, these functions are stubbed by implementations in
+// chrome_elf_test_stubs.cc.
+extern "C" {
+
+void DumpProcessWithoutCrash();
+
+// Returns true if |user_data_dir| or |invalid_data_dir| contain data.
+// This should always be the case in non-test builds.
+bool GetUserDataDirectoryThunk(wchar_t* user_data_dir,
+ size_t user_data_dir_length,
+ wchar_t* invalid_user_data_dir,
+ size_t invalid_user_data_dir_length);
+// This function is a temporary workaround for https://crbug.com/655788. We
+// need to come up with a better way to initialize crash reporting that can
+// happen inside DllMain().
+void SignalInitializeCrashReporting();
+void SignalChromeElf();
+
+} // 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
new file mode 100644
index 00000000000..bec3eea7276
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_test_stubs.cc
@@ -0,0 +1,35 @@
+// Copyright 2017 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.
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome_elf/chrome_elf_main.h"
+
+// This function is a temporary workaround for https://crbug.com/655788. We
+// need to come up with a better way to initialize crash reporting that can
+// happen inside DllMain().
+void SignalInitializeCrashReporting() {}
+
+void SignalChromeElf() {}
+
+bool GetUserDataDirectoryThunk(wchar_t* user_data_dir,
+ size_t user_data_dir_length,
+ wchar_t* invalid_user_data_dir,
+ size_t invalid_user_data_dir_length) {
+ // In tests, just respect the user-data-dir switch if given.
+ base::FilePath user_data_dir_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kUserDataDir);
+ if (!user_data_dir_path.empty() && user_data_dir_path.EndsWithSeparator())
+ user_data_dir_path = user_data_dir_path.StripTrailingSeparators();
+
+ wcsncpy_s(user_data_dir, user_data_dir_length,
+ user_data_dir_path.value().c_str(), _TRUNCATE);
+ wcsncpy_s(invalid_user_data_dir, invalid_user_data_dir_length, L"",
+ _TRUNCATE);
+
+ return !user_data_dir_path.empty();
+}
diff --git a/chromium/chrome_elf/chrome_elf_x64.def b/chromium/chrome_elf/chrome_elf_x64.def
new file mode 100644
index 00000000000..184b7989a29
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_x64.def
@@ -0,0 +1,45 @@
+; 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_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 chrome_elf/crash_helper.cc
+ GetCrashReportsImpl
+ SetMetricsClientId
+
+ ; From chrome_elf_main.cc
+ DumpProcessWithoutCrash
+ GetUserDataDirectoryThunk
+ SignalChromeElf
+ SignalInitializeCrashReporting
+
+ ; From chrome/install_static
+ GetInstallDetailsPayload
+
+ ; 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
new file mode 100644
index 00000000000..d49b5e50cca
--- /dev/null
+++ b/chromium/chrome_elf/chrome_elf_x86.def
@@ -0,0 +1,41 @@
+; 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
+
+ ; From chrome_elf/crash_helper.cc
+ GetCrashReportsImpl
+ SetMetricsClientId
+
+ ; From chrome_elf_main.cc
+ DumpProcessWithoutCrash
+ GetUserDataDirectoryThunk
+ SignalChromeElf
+ SignalInitializeCrashReporting
+
+ ; From chrome/install_static
+ GetInstallDetailsPayload
+
+ ; 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 31ed15080ab..e1bede4790c 100644
--- a/chromium/chrome_elf/crash/crash_helper.cc
+++ b/chromium/chrome_elf/crash/crash_helper.cc
@@ -132,22 +132,15 @@ void DumpWithoutCrashing() {
// 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" __declspec(dllexport) void GetCrashReportsImpl(
- const crash_reporter::Report** reports,
- size_t* report_count) {
- if (!g_crash_helper_enabled)
- return;
- crash_reporter::GetReports(g_crash_reports);
- *reports = g_crash_reports->data();
- *report_count = g_crash_reports->size();
-}
+extern "C" {
// This helper is invoked by debugging code in chrome to register the client
// id.
-extern "C" __declspec(dllexport) void SetMetricsClientId(
- const char* client_id) {
+void SetMetricsClientId(const char* client_id) {
if (!g_crash_helper_enabled)
return;
if (client_id)
crash_keys::SetMetricsClientIdFromGUID(client_id);
}
+
+} // extern "C"
diff --git a/chromium/chrome_elf/nt_registry/nt_registry.cc b/chromium/chrome_elf/nt_registry/nt_registry.cc
index 4c65af8daff..aca2a074da9 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry.cc
+++ b/chromium/chrome_elf/nt_registry/nt_registry.cc
@@ -7,6 +7,8 @@
#include <assert.h>
#include <stdlib.h>
+#include <memory>
+
namespace {
// Function pointers used for registry access.
@@ -542,6 +544,45 @@ bool ParseFullRegPath(const std::wstring& converted_root,
return true;
}
+// String safety.
+// - NOTE: only working with wchar_t here.
+// - Also ensures the content of |value_bytes| is at least a terminator.
+// - Pass "true" for |multi| for MULTISZ.
+void EnsureTerminatedSZ(std::vector<BYTE>* value_bytes, bool multi) {
+ DWORD terminator_size = sizeof(wchar_t);
+
+ if (multi)
+ terminator_size = 2 * sizeof(wchar_t);
+
+ // Ensure content is at least the size of a terminator.
+ if (value_bytes->size() < terminator_size) {
+ value_bytes->insert(value_bytes->end(),
+ terminator_size - value_bytes->size(), 0);
+ }
+
+ // Sanity check content size based on character size.
+ DWORD modulo = value_bytes->size() % sizeof(wchar_t);
+ value_bytes->insert(value_bytes->end(), modulo, 0);
+
+ // Now finally check for trailing terminator.
+ bool terminated = true;
+ size_t last_element = value_bytes->size() - 1;
+ for (size_t i = 0; i < terminator_size; i++) {
+ if ((*value_bytes)[last_element - i] != 0) {
+ terminated = false;
+ break;
+ }
+ }
+
+ if (terminated)
+ return;
+
+ // Append a full terminator to be safe.
+ value_bytes->insert(value_bytes->end(), terminator_size, 0);
+
+ return;
+}
+
//------------------------------------------------------------------------------
// Misc wrapper functions - LOCAL
//------------------------------------------------------------------------------
@@ -749,8 +790,7 @@ void CloseRegKey(HANDLE key) {
bool QueryRegKeyValue(HANDLE key,
const wchar_t* value_name,
ULONG* out_type,
- BYTE** out_buffer,
- DWORD* out_size) {
+ std::vector<BYTE>* out_buffer) {
if (!g_initialized)
InitNativeRegApi();
@@ -758,7 +798,6 @@ bool QueryRegKeyValue(HANDLE key,
UNICODE_STRING value_uni = {};
g_rtl_init_unicode_string(&value_uni, value_name);
DWORD size_needed = 0;
- bool success = false;
// First call to find out how much room we need for the value!
ntstatus = g_nt_query_value_key(key, &value_uni, KeyValueFullInformation,
@@ -766,24 +805,28 @@ bool QueryRegKeyValue(HANDLE key,
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*>(new BYTE[size_needed]);
+ reinterpret_cast<KEY_VALUE_FULL_INFORMATION*>(buffer.get());
// 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)) {
- *out_type = value_info->Type;
- *out_size = value_info->DataLength;
- *out_buffer = new BYTE[*out_size];
- ::memcpy(*out_buffer,
- (reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset),
- *out_size);
- success = true;
+ if (!NT_SUCCESS(ntstatus))
+ return false;
+
+ *out_type = value_info->Type;
+ DWORD data_size = value_info->DataLength;
+
+ if (data_size) {
+ // Move the data into |out_buffer| vector.
+ BYTE* data = reinterpret_cast<BYTE*>(value_info) + value_info->DataOffset;
+ out_buffer->assign(data, data + data_size);
+ } else {
+ out_buffer->clear();
}
- delete[] value_info;
- return success;
+ return true;
}
// wrapper function
@@ -791,16 +834,18 @@ bool QueryRegValueDWORD(HANDLE key,
const wchar_t* value_name,
DWORD* out_dword) {
ULONG type = REG_NONE;
- BYTE* value_bytes = nullptr;
- DWORD ret_size = 0;
+ std::vector<BYTE> value_bytes;
+
+ if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
+ type != REG_DWORD) {
+ return false;
+ }
- if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
- type != REG_DWORD)
+ if (value_bytes.size() < sizeof(*out_dword))
return false;
- *out_dword = *(reinterpret_cast<DWORD*>(value_bytes));
+ *out_dword = *(reinterpret_cast<DWORD*>(value_bytes.data()));
- delete[] value_bytes;
return true;
}
@@ -828,17 +873,18 @@ bool QueryRegValueDWORD(ROOT_KEY root,
bool QueryRegValueSZ(HANDLE key,
const wchar_t* value_name,
std::wstring* out_sz) {
- BYTE* value_bytes = nullptr;
- DWORD ret_size = 0;
+ std::vector<BYTE> value_bytes;
ULONG type = REG_NONE;
- if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
- type != REG_SZ)
+ if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
+ (type != REG_SZ && type != REG_EXPAND_SZ)) {
return false;
+ }
- *out_sz = reinterpret_cast<wchar_t*>(value_bytes);
+ EnsureTerminatedSZ(&value_bytes, false);
+
+ *out_sz = reinterpret_cast<wchar_t*>(value_bytes.data());
- delete[] value_bytes;
return true;
}
@@ -866,33 +912,29 @@ bool QueryRegValueSZ(ROOT_KEY root,
bool QueryRegValueMULTISZ(HANDLE key,
const wchar_t* value_name,
std::vector<std::wstring>* out_multi_sz) {
- BYTE* value_bytes = nullptr;
- DWORD ret_size = 0;
+ std::vector<BYTE> value_bytes;
ULONG type = REG_NONE;
- if (!QueryRegKeyValue(key, value_name, &type, &value_bytes, &ret_size) ||
- type != REG_MULTI_SZ)
+ if (!QueryRegKeyValue(key, value_name, &type, &value_bytes) ||
+ type != REG_MULTI_SZ) {
return false;
+ }
- // Make sure the vector is empty to start.
- (*out_multi_sz).resize(0);
+ EnsureTerminatedSZ(&value_bytes, true);
- wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes);
+ // Make sure the out vector is empty to start.
+ out_multi_sz->clear();
+
+ wchar_t* pointer = reinterpret_cast<wchar_t*>(value_bytes.data());
std::wstring temp = pointer;
// Loop. Each string is separated by '\0'. Another '\0' at very end (so 2 in
// a row).
- while (temp.length() != 0) {
- (*out_multi_sz).push_back(temp);
-
+ while (!temp.empty()) {
pointer += temp.length() + 1;
+ out_multi_sz->push_back(std::move(temp));
temp = pointer;
}
- // Handle the case of "empty multi_sz".
- if (out_multi_sz->size() == 0)
- out_multi_sz->push_back(L"");
-
- delete[] value_bytes;
return true;
}
diff --git a/chromium/chrome_elf/nt_registry/nt_registry.h b/chromium/chrome_elf/nt_registry/nt_registry.h
index 5115410bcd2..5db8771c030 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry.h
+++ b/chromium/chrome_elf/nt_registry/nt_registry.h
@@ -92,12 +92,10 @@ void CloseRegKey(HANDLE key);
// Main function to query a registry value.
// - Key handle should have been opened with CreateRegKey or OpenRegKey.
// - Types defined in winnt.h. E.g.: REG_DWORD, REG_SZ.
-// - Caller is responsible for calling "delete[] *out_buffer" (on success).
bool QueryRegKeyValue(HANDLE key,
const wchar_t* value_name,
ULONG* out_type,
- BYTE** out_buffer,
- DWORD* out_size);
+ std::vector<BYTE>* out_buffer);
// Query DWORD value.
// - WRAPPER: Function works with DWORD data type.
@@ -118,17 +116,23 @@ bool QueryRegValueDWORD(ROOT_KEY root,
DWORD* out_dword);
// Query SZ (string) value.
-// - WRAPPER: Function works with SZ data type.
+// - WRAPPER: Function works with SZ or EXPAND_SZ data type.
// - Key handle should have been opened with CreateRegKey or OpenRegKey.
// - Handle will be left open. Caller must still call CloseRegKey when done.
+// - Note: this function only returns the string up to the first end-of-string.
+// Any string packed with embedded nulls can be accessed via the raw
+// QueryRegKeyValue function.
bool QueryRegValueSZ(HANDLE key,
const wchar_t* value_name,
std::wstring* out_sz);
// Query SZ (string) value.
// - WRAPPER: Function opens and closes the target key for caller, and works
-// with SZ data type.
+// with SZ or EXPAND_SZ data type.
// - Use |wow64_override| to force redirection behaviour, or pass nt::NONE.
+// - Note: this function only returns the string up to the first end-of-string.
+// Any string packed with embedded nulls can be accessed via the raw
+// QueryRegKeyValue function.
bool QueryRegValueSZ(ROOT_KEY root,
WOW64_OVERRIDE wow64_override,
const wchar_t* key_path,
diff --git a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
index 0d54cb5f753..ee8f1af0ee8 100644
--- a/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
+++ b/chromium/chrome_elf/nt_registry/nt_registry_unittest.cc
@@ -348,8 +348,17 @@ TEST_F(NtRegistryTest, API_SZ) {
std::wstring sz_val = L"blah de blah de blahhhhh.";
const wchar_t* sz_val_name2 = L"SzTestValueEmpty";
std::wstring sz_val2 = L"";
+ const wchar_t* sz_val_name3 = L"SzTestValueMalformed";
+ const wchar_t* sz_val_name4 = L"SzTestValueMalformed2";
+ std::wstring sz_val3 = L"malformed";
+ BYTE* sz_val3_byte = reinterpret_cast<BYTE*>(&sz_val3[0]);
+ std::vector<BYTE> malform;
+ for (size_t i = 0; i < (sz_val3.size() * sizeof(wchar_t)); i++)
+ malform.push_back(sz_val3_byte[i]);
+ const wchar_t* sz_val_name5 = L"SzTestValueSize0";
// Create a subkey to play under.
+ // ------------------------------
ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, L"NTRegistry\\sz", KEY_ALL_ACCESS,
&key_handle));
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
@@ -359,16 +368,39 @@ TEST_F(NtRegistryTest, API_SZ) {
EXPECT_FALSE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
// Set
+ // ------------------------------
EXPECT_TRUE(nt::SetRegValueSZ(key_handle, sz_val_name, sz_val));
EXPECT_TRUE(nt::SetRegValueSZ(key_handle, sz_val_name2, sz_val2));
+ // No null terminator.
+ EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name3, REG_SZ,
+ malform.data(),
+ static_cast<DWORD>(malform.size())));
+ malform.push_back(0);
+ // Single trailing 0 byte.
+ EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name4, REG_SZ,
+ malform.data(),
+ static_cast<DWORD>(malform.size())));
+ // Size 0 value.
+ EXPECT_TRUE(nt::SetRegKeyValue(key_handle, sz_val_name5, REG_SZ, nullptr, 0));
// Get
+ // ------------------------------
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name, &get_sz));
EXPECT_TRUE(get_sz.compare(sz_val) == 0);
EXPECT_TRUE(nt::QueryRegValueSZ(key_handle, sz_val_name2, &get_sz));
EXPECT_TRUE(get_sz.compare(sz_val2) == 0);
+ 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_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_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);
// Clean up
+ // ------------------------------
EXPECT_TRUE(nt::DeleteRegKey(key_handle));
nt::CloseRegKey(key_handle);
}
@@ -382,8 +414,19 @@ TEST_F(NtRegistryTest, API_MULTISZ) {
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";
// Create a subkey to play under.
+ // ------------------------------
ASSERT_TRUE(nt::CreateRegKey(nt::HKCU, L"NTRegistry\\multisz", KEY_ALL_ACCESS,
&key_handle));
ASSERT_NE(key_handle, INVALID_HANDLE_VALUE);
@@ -392,17 +435,44 @@ TEST_F(NtRegistryTest, API_MULTISZ) {
multisz_val.push_back(multi1);
multisz_val.push_back(multi2);
multisz_val.push_back(multi3);
+
// Set
+ // ------------------------------
EXPECT_TRUE(
nt::SetRegValueMULTISZ(key_handle, multisz_val_name, multisz_val));
multisz_val.clear();
multisz_val.push_back(multi_empty);
- // Set
+
EXPECT_TRUE(
nt::SetRegValueMULTISZ(key_handle, multisz_val_name2, multisz_val));
multisz_val.clear();
+ // No null terminator.
+ EXPECT_TRUE(nt::SetRegKeyValue(key_handle, multisz_val_name3, REG_MULTI_SZ,
+ malform.data(),
+ static_cast<DWORD>(malform.size())));
+ 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())));
+ 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())));
+ 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::SetRegKeyValue(key_handle, multisz_val_name7, REG_MULTI_SZ,
+ nullptr, 0));
+
// Get
+ // ------------------------------
EXPECT_TRUE(
nt::QueryRegValueMULTISZ(key_handle, multisz_val_name, &multisz_val));
if (multisz_val.size() == 3) {
@@ -414,17 +484,58 @@ TEST_F(NtRegistryTest, API_MULTISZ) {
}
multisz_val.clear();
- // Get
EXPECT_TRUE(
nt::QueryRegValueMULTISZ(key_handle, multisz_val_name2, &multisz_val));
- if (multisz_val.size() == 1) {
- EXPECT_TRUE(multi_empty.compare(multisz_val.at(0)) == 0);
+ 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);
}