tor-browser

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

SharedStringMap.h (7446B)


      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 #ifndef dom_ipc_SharedStringMap_h
      8 #define dom_ipc_SharedStringMap_h
      9 
     10 #include "mozilla/Result.h"
     11 #include "mozilla/dom/ipc/StringTable.h"
     12 #include "mozilla/ipc/SharedMemoryHandle.h"
     13 #include "mozilla/ipc/SharedMemoryMapping.h"
     14 #include "nsTHashMap.h"
     15 
     16 namespace mozilla::dom::ipc {
     17 
     18 class SharedStringMapBuilder;
     19 
     20 /**
     21 * This class provides a simple, read-only key-value string store, with all
     22 * data packed into a single segment of memory, which can be shared between
     23 * processes.
     24 *
     25 * Look-ups are performed by binary search of a static table in the mapped
     26 * memory region, and all returned strings are literals which reference the
     27 * mapped data. No copies are performed on instantiation or look-up.
     28 *
     29 * Important: The mapped memory created by this class is persistent. Once an
     30 * instance has been initialized, the memory that it allocates can never be
     31 * freed before process shutdown. Do not use it for short-lived mappings.
     32 */
     33 class SharedStringMap {
     34 public:
     35  /**
     36   * The header at the beginning of the shared memory region describing its
     37   * layout. The layout of the shared memory is as follows:
     38   *
     39   * - Header:
     40   *   A Header struct describing the contents of the rest of the memory region.
     41   *
     42   * - Optional alignment padding for Header[].
     43   *
     44   * - Entry[header.mEntryCount]:
     45   *   An array of Entry structs, one for each entry in the map. Entries are
     46   *   lexocographically sorted by key.
     47   *
     48   * - StringTable<nsCString>:
     49   *   A region of flat, null-terminated C strings. Entry key strings are
     50   *   encoded as character offsets into this region.
     51   *
     52   * - Optional alignment padding for char16_t[]
     53   *
     54   * - StringTable<nsString>:
     55   *   A region of flat, null-terminated UTF-16 strings. Entry value strings are
     56   *   encoded as character (*not* byte) offsets into this region.
     57   */
     58  struct Header {
     59    uint32_t mMagic;
     60    // The number of entries in this map.
     61    uint32_t mEntryCount;
     62 
     63    // The raw byte offset of the beginning of the key string table, from the
     64    // start of the shared memory region, and its size in bytes.
     65    size_t mKeyStringsOffset;
     66    size_t mKeyStringsSize;
     67 
     68    // The raw byte offset of the beginning of the value string table, from the
     69    // start of the shared memory region, and its size in bytes (*not*
     70    // characters).
     71    size_t mValueStringsOffset;
     72    size_t mValueStringsSize;
     73  };
     74 
     75  /**
     76   * Describes a value in the string map, as offsets into the key and value
     77   * string tables.
     78   */
     79  struct Entry {
     80    // The offset and size of the entry's UTF-8 key in the key string table.
     81    StringTableEntry mKey;
     82    // The offset and size of the entry's UTF-16 value in the value string
     83    // table.
     84    StringTableEntry mValue;
     85  };
     86 
     87  NS_INLINE_DECL_REFCOUNTING(SharedStringMap)
     88 
     89  // Note: These constructors are infallible on the premise that this class
     90  // is used primarily in cases where it is critical to platform
     91  // functionality.
     92  explicit SharedStringMap(const mozilla::ipc::ReadOnlySharedMemoryHandle&);
     93  explicit SharedStringMap(SharedStringMapBuilder&&);
     94 
     95  /**
     96   * Searches for the given value in the map, and returns true if it exists.
     97   */
     98  bool Has(const nsCString& aKey);
     99 
    100  /**
    101   * Searches for the given value in the map, and, if it exists, returns true
    102   * and places its value in aValue.
    103   *
    104   * The returned value is a literal string which references the mapped memory
    105   * region.
    106   */
    107  bool Get(const nsCString& aKey, nsAString& aValue);
    108 
    109 private:
    110  /**
    111   * Searches for an entry for the given key. If found, returns true, and
    112   * places its index in the entry array in aIndex.
    113   */
    114  bool Find(const nsCString& aKey, size_t* aIndex);
    115 
    116 public:
    117  /**
    118   * Returns the number of entries in the map.
    119   */
    120  uint32_t Count() const { return EntryCount(); }
    121 
    122  /**
    123   * Returns the string entry at the given index. Keys are guaranteed to be
    124   * sorted lexographically.
    125   *
    126   * The given index *must* be less than the value returned by Count().
    127   *
    128   * The returned value is a literal string which references the mapped memory
    129   * region.
    130   */
    131  nsCString GetKeyAt(uint32_t aIndex) const {
    132    MOZ_ASSERT(aIndex < Count());
    133    return KeyTable().Get(Entries()[aIndex].mKey);
    134  }
    135 
    136  /**
    137   * Returns the string value for the entry at the given index.
    138   *
    139   * The given index *must* be less than the value returned by Count().
    140   *
    141   * The returned value is a literal string which references the mapped memory
    142   * region.
    143   */
    144  nsString GetValueAt(uint32_t aIndex) const {
    145    MOZ_ASSERT(aIndex < Count());
    146    return ValueTable().Get(Entries()[aIndex].mValue);
    147  }
    148 
    149  /**
    150   * Returns a copy of the read-only shared memory handle which backs the shared
    151   * memory region for this map. The handle may be passed between processes, and
    152   * used to construct new instances of SharedStringMap with the same data as
    153   * this instance.
    154   */
    155  mozilla::ipc::ReadOnlySharedMemoryHandle CloneHandle() const;
    156 
    157  size_t MapSize() const { return mMappedMemory.size(); }
    158 
    159 protected:
    160  ~SharedStringMap() = default;
    161 
    162 private:
    163  // Type-safe getters for values in the shared memory region:
    164  const Header& GetHeader() const {
    165    return *reinterpret_cast<const Header*>(mMappedMemory.data());
    166  }
    167 
    168  RangedPtr<const Entry> Entries() const {
    169    return {reinterpret_cast<const Entry*>(&GetHeader() + 1), EntryCount()};
    170  }
    171 
    172  uint32_t EntryCount() const { return GetHeader().mEntryCount; }
    173 
    174  StringTable<nsCString> KeyTable() const {
    175    const auto& header = GetHeader();
    176    return {
    177        {const_cast<uint8_t*>(&mMappedMemory.data()[header.mKeyStringsOffset]),
    178         header.mKeyStringsSize}};
    179  }
    180 
    181  StringTable<nsString> ValueTable() const {
    182    const auto& header = GetHeader();
    183    return {{const_cast<uint8_t*>(
    184                 &mMappedMemory.data()[header.mValueStringsOffset]),
    185             header.mValueStringsSize}};
    186  }
    187 
    188  mozilla::ipc::ReadOnlySharedMemoryHandle mHandle;
    189  // This is a leaked shared memory mapping (see the constructor definition for
    190  // an explanation). It replaces AutoMemMap::setPersistent behavior as part of
    191  // bug 1454816.
    192  mozilla::ipc::shared_memory::LeakedReadOnlyMapping mMappedMemory;
    193 };
    194 
    195 /**
    196 * A helper class which builds the contiguous look-up table used by
    197 * SharedStringMap. Each key-value pair in the final map is added to the
    198 * builder, before it is finalized and transformed into a snapshot.
    199 */
    200 class MOZ_RAII SharedStringMapBuilder {
    201 public:
    202  SharedStringMapBuilder() = default;
    203 
    204  /**
    205   * Adds a key-value pair to the map.
    206   */
    207  void Add(const nsCString& aKey, const nsString& aValue);
    208 
    209  /**
    210   * Finalizes the binary representation of the map, writes it to a shared
    211   * memory region, and then returns a read-only handle to it.
    212   */
    213  Result<mozilla::ipc::ReadOnlySharedMemoryHandle, nsresult> Finalize();
    214 
    215 private:
    216  using Entry = SharedStringMap::Entry;
    217 
    218  StringTableBuilder<nsCStringHashKey, nsCString> mKeyTable;
    219  StringTableBuilder<nsStringHashKey, nsString> mValueTable;
    220 
    221  nsTHashMap<nsCStringHashKey, Entry> mEntries;
    222 };
    223 
    224 }  // namespace mozilla::dom::ipc
    225 
    226 #endif  // dom_ipc_SharedStringMap_h