1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/win/registry.h" 6 7 #include <cstring> 8 #include <vector> 9 10 #include "base/compiler_specific.h" 11 #include "base/stl_util.h" 12 #include "base/win/windows_version.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 15 namespace base { 16 namespace win { 17 18 namespace { 19 20 class RegistryTest : public testing::Test { 21 protected: 22 #if defined(_WIN64) 23 static const REGSAM kNativeViewMask = KEY_WOW64_64KEY; 24 static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY; 25 #else 26 static const REGSAM kNativeViewMask = KEY_WOW64_32KEY; 27 static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY; 28 #endif // _WIN64 29 30 RegistryTest() {} 31 virtual void SetUp() OVERRIDE { 32 // Create a temporary key. 33 RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS); 34 key.DeleteKey(kRootKey); 35 ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); 36 ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ)); 37 foo_software_key_ = L"Software\\"; 38 foo_software_key_ += kRootKey; 39 foo_software_key_ += L"\\Foo"; 40 } 41 42 virtual void TearDown() OVERRIDE { 43 // Clean up the temporary key. 44 RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE); 45 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 46 ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); 47 } 48 49 static bool IsRedirectorPresent() { 50 #if defined(_WIN64) 51 return true; 52 #else 53 return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED; 54 #endif 55 } 56 57 const wchar_t* const kRootKey = L"Base_Registry_Unittest"; 58 std::wstring foo_software_key_; 59 60 private: 61 DISALLOW_COPY_AND_ASSIGN(RegistryTest); 62 }; 63 64 // static 65 const REGSAM RegistryTest::kNativeViewMask; 66 const REGSAM RegistryTest::kRedirectedViewMask; 67 68 TEST_F(RegistryTest, ValueTest) { 69 RegKey key; 70 71 std::wstring foo_key(kRootKey); 72 foo_key += L"\\Foo"; 73 ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), 74 KEY_READ)); 75 76 { 77 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), 78 KEY_READ | KEY_SET_VALUE)); 79 ASSERT_TRUE(key.Valid()); 80 81 const wchar_t kStringValueName[] = L"StringValue"; 82 const wchar_t kDWORDValueName[] = L"DWORDValue"; 83 const wchar_t kInt64ValueName[] = L"Int64Value"; 84 const wchar_t kStringData[] = L"string data"; 85 const DWORD kDWORDData = 0xdeadbabe; 86 const int64 kInt64Data = 0xdeadbabedeadbabeLL; 87 88 // Test value creation 89 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData)); 90 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData)); 91 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data, 92 sizeof(kInt64Data), REG_QWORD)); 93 EXPECT_EQ(3U, key.GetValueCount()); 94 EXPECT_TRUE(key.HasValue(kStringValueName)); 95 EXPECT_TRUE(key.HasValue(kDWORDValueName)); 96 EXPECT_TRUE(key.HasValue(kInt64ValueName)); 97 98 // Test Read 99 std::wstring string_value; 100 DWORD dword_value = 0; 101 int64 int64_value = 0; 102 ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value)); 103 ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value)); 104 ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value)); 105 EXPECT_STREQ(kStringData, string_value.c_str()); 106 EXPECT_EQ(kDWORDData, dword_value); 107 EXPECT_EQ(kInt64Data, int64_value); 108 109 // Make sure out args are not touched if ReadValue fails 110 const wchar_t* kNonExistent = L"NonExistent"; 111 ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value)); 112 ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value)); 113 ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value)); 114 EXPECT_STREQ(kStringData, string_value.c_str()); 115 EXPECT_EQ(kDWORDData, dword_value); 116 EXPECT_EQ(kInt64Data, int64_value); 117 118 // Test delete 119 ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName)); 120 ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName)); 121 ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName)); 122 EXPECT_EQ(0U, key.GetValueCount()); 123 EXPECT_FALSE(key.HasValue(kStringValueName)); 124 EXPECT_FALSE(key.HasValue(kDWORDValueName)); 125 EXPECT_FALSE(key.HasValue(kInt64ValueName)); 126 } 127 } 128 129 TEST_F(RegistryTest, BigValueIteratorTest) { 130 RegKey key; 131 std::wstring foo_key(kRootKey); 132 foo_key += L"\\Foo"; 133 ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), 134 KEY_READ)); 135 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), 136 KEY_READ | KEY_SET_VALUE)); 137 ASSERT_TRUE(key.Valid()); 138 139 // Create a test value that is larger than MAX_PATH. 140 std::wstring data(MAX_PATH * 2, L'a'); 141 142 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str())); 143 144 RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); 145 ASSERT_TRUE(iterator.Valid()); 146 EXPECT_STREQ(data.c_str(), iterator.Name()); 147 EXPECT_STREQ(data.c_str(), iterator.Value()); 148 // ValueSize() is in bytes, including NUL. 149 EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize()); 150 ++iterator; 151 EXPECT_FALSE(iterator.Valid()); 152 } 153 154 TEST_F(RegistryTest, TruncatedCharTest) { 155 RegKey key; 156 std::wstring foo_key(kRootKey); 157 foo_key += L"\\Foo"; 158 ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(), 159 KEY_READ)); 160 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(), 161 KEY_READ | KEY_SET_VALUE)); 162 ASSERT_TRUE(key.Valid()); 163 164 const wchar_t kName[] = L"name"; 165 // kData size is not a multiple of sizeof(wchar_t). 166 const uint8 kData[] = { 1, 2, 3, 4, 5 }; 167 EXPECT_EQ(5, arraysize(kData)); 168 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData, 169 arraysize(kData), REG_BINARY)); 170 171 RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str()); 172 ASSERT_TRUE(iterator.Valid()); 173 EXPECT_STREQ(kName, iterator.Name()); 174 // ValueSize() is in bytes. 175 ASSERT_EQ(arraysize(kData), iterator.ValueSize()); 176 // Value() is NUL terminated. 177 int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t); 178 EXPECT_NE(L'\0', iterator.Value()[end-1]); 179 EXPECT_EQ(L'\0', iterator.Value()[end]); 180 EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData))); 181 ++iterator; 182 EXPECT_FALSE(iterator.Valid()); 183 } 184 185 TEST_F(RegistryTest, RecursiveDelete) { 186 RegKey key; 187 // Create kRootKey->Foo 188 // \->Bar (TestValue) 189 // \->Foo (TestValue) 190 // \->Bar 191 // \->Foo 192 // \->Moo 193 // \->Foo 194 // and delete kRootKey->Foo 195 std::wstring foo_key(kRootKey); 196 foo_key += L"\\Foo"; 197 ASSERT_EQ(ERROR_SUCCESS, 198 key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 199 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE)); 200 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData")); 201 ASSERT_EQ(ERROR_SUCCESS, 202 key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 203 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE)); 204 ASSERT_EQ(ERROR_SUCCESS, 205 key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 206 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); 207 foo_key += L"\\Bar"; 208 ASSERT_EQ(ERROR_SUCCESS, 209 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 210 foo_key += L"\\Foo"; 211 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); 212 ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData")); 213 ASSERT_EQ(ERROR_SUCCESS, 214 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); 215 216 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); 217 ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar")); 218 ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo")); 219 ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo")); 220 ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar")); 221 ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo")); 222 223 ASSERT_EQ(ERROR_SUCCESS, 224 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 225 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE)); 226 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE)); 227 ASSERT_EQ(ERROR_SUCCESS, 228 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE)); 229 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"")); 230 ASSERT_NE(ERROR_SUCCESS, 231 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); 232 233 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); 234 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo")); 235 ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo")); 236 ASSERT_NE(ERROR_SUCCESS, 237 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); 238 } 239 240 // This test requires running as an Administrator as it tests redirected 241 // registry writes to HKLM\Software 242 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx 243 // TODO(wfh): flaky test on Vista. See http://crbug.com/377917 244 TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) { 245 if (!IsRedirectorPresent()) 246 return; 247 248 RegKey key; 249 250 // Test redirected key access from non-redirected. 251 ASSERT_EQ(ERROR_SUCCESS, 252 key.Create(HKEY_LOCAL_MACHINE, 253 foo_software_key_.c_str(), 254 KEY_WRITE | kRedirectedViewMask)); 255 ASSERT_NE(ERROR_SUCCESS, 256 key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); 257 ASSERT_NE(ERROR_SUCCESS, 258 key.Open(HKEY_LOCAL_MACHINE, 259 foo_software_key_.c_str(), 260 KEY_READ | kNativeViewMask)); 261 262 // Open the non-redirected view of the parent and try to delete the test key. 263 ASSERT_EQ(ERROR_SUCCESS, 264 key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE)); 265 ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 266 ASSERT_EQ(ERROR_SUCCESS, 267 key.Open(HKEY_LOCAL_MACHINE, 268 L"Software", 269 KEY_SET_VALUE | kNativeViewMask)); 270 ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 271 272 // Open the redirected view and delete the key created above. 273 ASSERT_EQ(ERROR_SUCCESS, 274 key.Open(HKEY_LOCAL_MACHINE, 275 L"Software", 276 KEY_SET_VALUE | kRedirectedViewMask)); 277 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 278 } 279 280 // Test for the issue found in http://crbug.com/384587 where OpenKey would call 281 // Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a 282 // subsequent OpenKey call. 283 TEST_F(RegistryTest, SameWowFlags) { 284 RegKey key; 285 286 ASSERT_EQ(ERROR_SUCCESS, 287 key.Open(HKEY_LOCAL_MACHINE, 288 L"Software", 289 KEY_READ | KEY_WOW64_64KEY)); 290 ASSERT_EQ(ERROR_SUCCESS, 291 key.OpenKey(L"Microsoft", 292 KEY_READ | KEY_WOW64_64KEY)); 293 ASSERT_EQ(ERROR_SUCCESS, 294 key.OpenKey(L"Windows", 295 KEY_READ | KEY_WOW64_64KEY)); 296 } 297 298 // TODO(wfh): flaky test on Vista. See http://crbug.com/377917 299 TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) { 300 if (!IsRedirectorPresent()) 301 return; 302 RegKey key; 303 304 // Test non-redirected key access from redirected. 305 ASSERT_EQ(ERROR_SUCCESS, 306 key.Create(HKEY_LOCAL_MACHINE, 307 foo_software_key_.c_str(), 308 KEY_WRITE | kNativeViewMask)); 309 ASSERT_EQ(ERROR_SUCCESS, 310 key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ)); 311 ASSERT_NE(ERROR_SUCCESS, 312 key.Open(HKEY_LOCAL_MACHINE, 313 foo_software_key_.c_str(), 314 KEY_READ | kRedirectedViewMask)); 315 316 // Open the redirected view of the parent and try to delete the test key 317 // from the non-redirected view. 318 ASSERT_EQ(ERROR_SUCCESS, 319 key.Open(HKEY_LOCAL_MACHINE, 320 L"Software", 321 KEY_SET_VALUE | kRedirectedViewMask)); 322 ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 323 324 ASSERT_EQ(ERROR_SUCCESS, 325 key.Open(HKEY_LOCAL_MACHINE, 326 L"Software", 327 KEY_SET_VALUE | kNativeViewMask)); 328 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey)); 329 } 330 331 TEST_F(RegistryTest, OpenSubKey) { 332 RegKey key; 333 ASSERT_EQ(ERROR_SUCCESS, 334 key.Open(HKEY_CURRENT_USER, 335 kRootKey, 336 KEY_READ | KEY_CREATE_SUB_KEY)); 337 338 ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); 339 ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ)); 340 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ)); 341 ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ)); 342 343 std::wstring foo_key(kRootKey); 344 foo_key += L"\\Foo"; 345 ASSERT_EQ(ERROR_SUCCESS, 346 key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ)); 347 348 ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE)); 349 ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo")); 350 } 351 352 } // namespace 353 354 } // namespace win 355 } // namespace base 356