diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 10:33:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:45:12 +0000 |
commit | be59a35641616a4cf23c4a13fa0632624b021c1b (patch) | |
tree | 9da183258bdf9cc413f7562079d25ace6955467f /chromium/chrome_elf | |
parent | d702e4b6a64574e97fc7df8fe3238cde70242080 (diff) | |
download | qtwebengine-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.gn | 33 | ||||
-rw-r--r-- | chromium/chrome_elf/DEPS | 1 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf.def | 16 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_main.cc | 10 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_main.h | 24 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_test_stubs.cc | 35 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_x64.def | 45 | ||||
-rw-r--r-- | chromium/chrome_elf/chrome_elf_x86.def | 41 | ||||
-rw-r--r-- | chromium/chrome_elf/crash/crash_helper.cc | 15 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry.cc | 124 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry.h | 14 | ||||
-rw-r--r-- | chromium/chrome_elf/nt_registry/nt_registry_unittest.cc | 119 |
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); } |