commit 4f7ce38037c0392ef856c3c407f216c9a357f55f
parent 92b3e73bb85a16e02a4c3044d6693a58ea9d6f5e
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Thu, 3 Dec 2020 14:24:25 -0800
Fix registry reading code to allow for a single null byte on a wide string value (#662)
Move to RegGetValue which normalizes null characters at the end of registry strings
Diffstat:
5 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt
@@ -135,6 +135,7 @@ IHost
IID
IInstalled
incosistencies
+INET
inl
inor
iosfwd
@@ -207,6 +208,7 @@ mysilentwithprogress
mytool
Newtonsoft
nfinity
+NOEXPAND
noreturn
nuffing
nullopt
@@ -240,6 +242,7 @@ REGSAM
REINSTALLMODE
rhs
rosoft
+RRF
rrr
rzkzqaqjwj
schematab
@@ -326,4 +329,3 @@ Wunused
WZDNCRFJ
xf
xl
-INET
diff --git a/src/AppInstallerCLITests/Registry.cpp b/src/AppInstallerCLITests/Registry.cpp
@@ -80,6 +80,30 @@ TEST_CASE("Values_String", "[registry]")
REQUIRE(value->GetValue<Value::Type::String>() == ConvertToUTF8(valueValue));
}
+TEST_CASE("Values_WideStringWithNarrowNull", "[registry]")
+{
+ std::wstring valueName = L"TestValueName";
+ std::wstring valueValue = L"TestValueValue";
+
+ wil::unique_hkey root = RegCreateVolatileTestRoot();
+
+ // Copy the bytes from the string value into a byte vector
+ std::vector<BYTE> valueBytes;
+ valueBytes.resize((valueValue.length() + 1) * sizeof(wchar_t));
+ memcpy_s(valueBytes.data(), valueBytes.size(), valueValue.c_str(), (valueValue.length() + 1) * sizeof(wchar_t));
+ // Remove the last byte to make a narrow null
+ valueBytes.resize(valueBytes.size() - 1);
+
+ SetRegistryValue(root.get(), valueName, valueBytes, REG_SZ);
+
+ Key key{ root.get(), L"" };
+
+ auto value = key[valueName];
+ REQUIRE(value);
+ REQUIRE(value->GetType() == Value::Type::String);
+ REQUIRE(value->GetValue<Value::Type::String>() == ConvertToUTF8(valueValue));
+}
+
TEST_CASE("Values_ExpandString", "[registry]")
{
std::wstring valueName = L"TestValueName";
diff --git a/src/AppInstallerCLITests/TestCommon.cpp b/src/AppInstallerCLITests/TestCommon.cpp
@@ -179,9 +179,9 @@ namespace TestCommon
THROW_IF_WIN32_ERROR(RegSetValueExW(key, name.c_str(), 0, type, reinterpret_cast<const BYTE*>(value.c_str()), static_cast<DWORD>(sizeof(wchar_t) * (value.size() + 1))));
}
- void SetRegistryValue(HKEY key, const std::wstring& name, const std::vector<BYTE>& value)
+ void SetRegistryValue(HKEY key, const std::wstring& name, const std::vector<BYTE>& value, DWORD type)
{
- THROW_IF_WIN32_ERROR(RegSetValueExW(key, name.c_str(), 0, REG_BINARY, reinterpret_cast<const BYTE*>(value.data()), static_cast<DWORD>(value.size())));
+ THROW_IF_WIN32_ERROR(RegSetValueExW(key, name.c_str(), 0, type, reinterpret_cast<const BYTE*>(value.data()), static_cast<DWORD>(value.size())));
}
void SetRegistryValue(HKEY key, const std::wstring& name, DWORD value)
diff --git a/src/AppInstallerCLITests/TestCommon.h b/src/AppInstallerCLITests/TestCommon.h
@@ -106,7 +106,7 @@ namespace TestCommon
// Set registry values.
void SetRegistryValue(HKEY key, const std::wstring& name, const std::wstring& value, DWORD type = REG_SZ);
- void SetRegistryValue(HKEY key, const std::wstring& name, const std::vector<BYTE>& value);
+ void SetRegistryValue(HKEY key, const std::wstring& name, const std::vector<BYTE>& value, DWORD type = REG_BINARY);
void SetRegistryValue(HKEY key, const std::wstring& name, DWORD value);
}
diff --git a/src/AppInstallerCommonCore/Registry.cpp b/src/AppInstallerCommonCore/Registry.cpp
@@ -231,7 +231,7 @@ namespace AppInstaller::Registry
while (data.size() < (64 << 20))
{
byteCount = wil::safe_cast<DWORD>(data.size());
- status = RegQueryValueExW(m_key.get(), name.c_str(), nullptr, &type, data.data(), &byteCount);
+ status = RegGetValueW(m_key.get(), nullptr, name.c_str(), RRF_RT_ANY | RRF_NOEXPAND, &type, data.data(), &byteCount);
if (status == ERROR_MORE_DATA && byteCount > data.size())
{