Home | History | Annotate | Download | only in win
      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