tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SharedPrefMap.cpp (7519B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SharedPrefMap.h"
      8 
      9 #include "mozilla/dom/ipc/MemMapSnapshot.h"
     10 
     11 #include "mozilla/BinarySearch.h"
     12 #include "mozilla/ResultExtensions.h"
     13 #include "mozilla/Try.h"
     14 #include "mozilla/ipc/FileDescriptor.h"
     15 
     16 namespace mozilla {
     17 
     18 using namespace ipc;
     19 
     20 static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
     21  auto mod = aOffset % aAlign;
     22  return mod ? aAlign - mod : 0;
     23 }
     24 
     25 SharedPrefMap::SharedPrefMap(const ReadOnlySharedMemoryHandle& aMapHandle) {
     26  auto map = aMapHandle.Map();
     27  MOZ_RELEASE_ASSERT(map);
     28 
     29  mHandle = aMapHandle.Clone();
     30  // We return literal nsCStrings pointing to the mapped data for preference
     31  // names and string values, which means that we may still have references to
     32  // the mapped data even after this instance is destroyed. That means that we
     33  // need to keep the mapping alive until process shutdown, in order to be safe.
     34  mMappedMemory = std::move(map).Release();
     35 }
     36 
     37 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
     38  ReadOnlySharedMemoryMappingWithHandle mapWithHandle;
     39  auto result = aBuilder.Finalize();
     40  MOZ_RELEASE_ASSERT(result.isOk());
     41  mHandle = result.unwrap();
     42  auto map = mHandle.Map();
     43  MOZ_RELEASE_ASSERT(map.IsValid());
     44  mMappedMemory = std::move(map).Release();
     45 }
     46 
     47 mozilla::ipc::ReadOnlySharedMemoryHandle SharedPrefMap::CloneHandle() const {
     48  MOZ_ASSERT(XRE_IsParentProcess());
     49  return mHandle.Clone();
     50 }
     51 
     52 bool SharedPrefMap::Has(const char* aKey) const {
     53  size_t index;
     54  return Find(aKey, &index);
     55 }
     56 
     57 Maybe<const SharedPrefMap::Pref> SharedPrefMap::Get(const char* aKey) const {
     58  Maybe<const Pref> result;
     59 
     60  size_t index;
     61  if (Find(aKey, &index)) {
     62    result.emplace(Pref{this, &Entries()[index]});
     63  }
     64 
     65  return result;
     66 }
     67 
     68 bool SharedPrefMap::Find(const char* aKey, size_t* aIndex) const {
     69  const auto& keys = KeyTable();
     70 
     71  return BinarySearchIf(
     72      Entries(), 0, EntryCount(),
     73      [&](const Entry& aEntry) {
     74        return strcmp(aKey, keys.GetBare(aEntry.mKey));
     75      },
     76      aIndex);
     77 }
     78 
     79 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
     80                               bool aDefaultValue, bool aUserValue) {
     81  mEntries.AppendElement(Entry{
     82      aKey.get(),
     83      mKeyTable.Add(aKey),
     84      {aDefaultValue, aUserValue},
     85      uint8_t(PrefType::Bool),
     86      aFlags.mHasDefaultValue,
     87      aFlags.mHasUserValue,
     88      aFlags.mIsSticky,
     89      aFlags.mIsLocked,
     90      aFlags.mIsSanitized,
     91      aFlags.mIsSkippedByIteration,
     92  });
     93 }
     94 
     95 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
     96                               int32_t aDefaultValue, int32_t aUserValue) {
     97  ValueIdx index;
     98  if (aFlags.mHasUserValue) {
     99    index = mIntValueTable.Add(aDefaultValue, aUserValue);
    100  } else {
    101    index = mIntValueTable.Add(aDefaultValue);
    102  }
    103 
    104  mEntries.AppendElement(Entry{
    105      aKey.get(),
    106      mKeyTable.Add(aKey),
    107      {index},
    108      uint8_t(PrefType::Int),
    109      aFlags.mHasDefaultValue,
    110      aFlags.mHasUserValue,
    111      aFlags.mIsSticky,
    112      aFlags.mIsLocked,
    113      aFlags.mIsSanitized,
    114      aFlags.mIsSkippedByIteration,
    115  });
    116 }
    117 
    118 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
    119                               const nsCString& aDefaultValue,
    120                               const nsCString& aUserValue) {
    121  ValueIdx index;
    122  StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue);
    123  if (aFlags.mHasUserValue) {
    124    StringTableEntry userVal = mValueStringTable.Add(aUserValue);
    125    index = mStringValueTable.Add(defaultVal, userVal);
    126  } else {
    127    index = mStringValueTable.Add(defaultVal);
    128  }
    129 
    130  mEntries.AppendElement(Entry{
    131      aKey.get(),
    132      mKeyTable.Add(aKey),
    133      {index},
    134      uint8_t(PrefType::String),
    135      aFlags.mHasDefaultValue,
    136      aFlags.mHasUserValue,
    137      aFlags.mIsSticky,
    138      aFlags.mIsLocked,
    139      aFlags.mIsSanitized,
    140      aFlags.mIsSkippedByIteration,
    141  });
    142 }
    143 
    144 Result<ReadOnlySharedMemoryHandle, nsresult> SharedPrefMapBuilder::Finalize() {
    145  using Header = SharedPrefMap::Header;
    146 
    147  // Create an array of entry pointers for the entry array, and sort it by
    148  // preference name prior to serialization, so that entries can be looked up
    149  // using binary search.
    150  nsTArray<Entry*> entries(mEntries.Length());
    151  for (auto& entry : mEntries) {
    152    entries.AppendElement(&entry);
    153  }
    154  entries.Sort([](const Entry* aA, const Entry* aB) {
    155    return strcmp(aA->mKeyString, aB->mKeyString);
    156  });
    157 
    158  Header header = {uint32_t(entries.Length())};
    159 
    160  size_t offset = sizeof(header);
    161  offset += GetAlignmentOffset(offset, alignof(Header));
    162 
    163  offset += entries.Length() * sizeof(SharedPrefMap::Entry);
    164 
    165  header.mKeyStrings.mOffset = offset;
    166  header.mKeyStrings.mSize = mKeyTable.Size();
    167  offset += header.mKeyStrings.mSize;
    168 
    169  offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
    170  header.mUserIntValues.mOffset = offset;
    171  header.mUserIntValues.mSize = mIntValueTable.UserSize();
    172  offset += header.mUserIntValues.mSize;
    173 
    174  offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
    175  header.mDefaultIntValues.mOffset = offset;
    176  header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize();
    177  offset += header.mDefaultIntValues.mSize;
    178 
    179  offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
    180  header.mUserStringValues.mOffset = offset;
    181  header.mUserStringValues.mSize = mStringValueTable.UserSize();
    182  offset += header.mUserStringValues.mSize;
    183 
    184  offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
    185  header.mDefaultStringValues.mOffset = offset;
    186  header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize();
    187  offset += header.mDefaultStringValues.mSize;
    188 
    189  header.mValueStrings.mOffset = offset;
    190  header.mValueStrings.mSize = mValueStringTable.Size();
    191  offset += header.mValueStrings.mSize;
    192 
    193  MemMapSnapshot mem;
    194  MOZ_TRY(mem.Init(offset));
    195 
    196  auto headerPtr = mem.Get<Header>();
    197  headerPtr[0] = header;
    198 
    199  auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]);
    200  for (auto* entry : entries) {
    201    *entryPtr = {
    202        entry->mKey,
    203        GetValue(*entry),
    204        entry->mType,
    205        entry->mHasDefaultValue,
    206        entry->mHasUserValue,
    207        entry->mIsSticky,
    208        entry->mIsLocked,
    209        entry->mIsSanitized,
    210        entry->mIsSkippedByIteration,
    211    };
    212    entryPtr++;
    213  }
    214 
    215  auto ptr = mem.Get<uint8_t>();
    216 
    217  mKeyTable.Write({&ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize});
    218 
    219  mValueStringTable.Write(
    220      {&ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize});
    221 
    222  mIntValueTable.WriteDefaultValues(
    223      {&ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize});
    224  mIntValueTable.WriteUserValues(
    225      {&ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize});
    226 
    227  mStringValueTable.WriteDefaultValues(
    228      {&ptr[header.mDefaultStringValues.mOffset],
    229       header.mDefaultStringValues.mSize});
    230  mStringValueTable.WriteUserValues(
    231      {&ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize});
    232 
    233  mKeyTable.Clear();
    234  mValueStringTable.Clear();
    235  mIntValueTable.Clear();
    236  mStringValueTable.Clear();
    237  mEntries.Clear();
    238 
    239  return mem.Finalize();
    240 }
    241 
    242 }  // namespace mozilla