Bug 1842773 - Part 21: Throw for out-of-bounds in (PossiblyWrapped)TypedArrayLength...
[gecko.git] / modules / libpref / SharedPrefMap.cpp
blob7782ffdcbf564f3a8a6db1df01ca3520bc31542f
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/. */
7 #include "SharedPrefMap.h"
9 #include "mozilla/dom/ipc/MemMapSnapshot.h"
11 #include "mozilla/BinarySearch.h"
12 #include "mozilla/ResultExtensions.h"
13 #include "mozilla/Try.h"
14 #include "mozilla/ipc/FileDescriptor.h"
16 using namespace mozilla::loader;
18 namespace mozilla {
20 using namespace ipc;
22 static inline size_t GetAlignmentOffset(size_t aOffset, size_t aAlign) {
23 auto mod = aOffset % aAlign;
24 return mod ? aAlign - mod : 0;
27 SharedPrefMap::SharedPrefMap(const FileDescriptor& aMapFile, size_t aMapSize) {
28 auto result = mMap.initWithHandle(aMapFile, aMapSize);
29 MOZ_RELEASE_ASSERT(result.isOk());
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 mMap.setPersistent();
37 SharedPrefMap::SharedPrefMap(SharedPrefMapBuilder&& aBuilder) {
38 auto result = aBuilder.Finalize(mMap);
39 MOZ_RELEASE_ASSERT(result.isOk());
40 mMap.setPersistent();
43 mozilla::ipc::FileDescriptor SharedPrefMap::CloneFileDescriptor() const {
44 return mMap.cloneHandle();
47 bool SharedPrefMap::Has(const char* aKey) const {
48 size_t index;
49 return Find(aKey, &index);
52 Maybe<const SharedPrefMap::Pref> SharedPrefMap::Get(const char* aKey) const {
53 Maybe<const Pref> result;
55 size_t index;
56 if (Find(aKey, &index)) {
57 result.emplace(Pref{this, &Entries()[index]});
60 return result;
63 bool SharedPrefMap::Find(const char* aKey, size_t* aIndex) const {
64 const auto& keys = KeyTable();
66 return BinarySearchIf(
67 Entries(), 0, EntryCount(),
68 [&](const Entry& aEntry) {
69 return strcmp(aKey, keys.GetBare(aEntry.mKey));
71 aIndex);
74 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
75 bool aDefaultValue, bool aUserValue) {
76 mEntries.AppendElement(Entry{
77 aKey.get(),
78 mKeyTable.Add(aKey),
79 {aDefaultValue, aUserValue},
80 uint8_t(PrefType::Bool),
81 aFlags.mHasDefaultValue,
82 aFlags.mHasUserValue,
83 aFlags.mIsSticky,
84 aFlags.mIsLocked,
85 aFlags.mIsSanitized,
86 aFlags.mIsSkippedByIteration,
87 });
90 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
91 int32_t aDefaultValue, int32_t aUserValue) {
92 ValueIdx index;
93 if (aFlags.mHasUserValue) {
94 index = mIntValueTable.Add(aDefaultValue, aUserValue);
95 } else {
96 index = mIntValueTable.Add(aDefaultValue);
99 mEntries.AppendElement(Entry{
100 aKey.get(),
101 mKeyTable.Add(aKey),
102 {index},
103 uint8_t(PrefType::Int),
104 aFlags.mHasDefaultValue,
105 aFlags.mHasUserValue,
106 aFlags.mIsSticky,
107 aFlags.mIsLocked,
108 aFlags.mIsSanitized,
109 aFlags.mIsSkippedByIteration,
113 void SharedPrefMapBuilder::Add(const nsCString& aKey, const Flags& aFlags,
114 const nsCString& aDefaultValue,
115 const nsCString& aUserValue) {
116 ValueIdx index;
117 StringTableEntry defaultVal = mValueStringTable.Add(aDefaultValue);
118 if (aFlags.mHasUserValue) {
119 StringTableEntry userVal = mValueStringTable.Add(aUserValue);
120 index = mStringValueTable.Add(defaultVal, userVal);
121 } else {
122 index = mStringValueTable.Add(defaultVal);
125 mEntries.AppendElement(Entry{
126 aKey.get(),
127 mKeyTable.Add(aKey),
128 {index},
129 uint8_t(PrefType::String),
130 aFlags.mHasDefaultValue,
131 aFlags.mHasUserValue,
132 aFlags.mIsSticky,
133 aFlags.mIsLocked,
134 aFlags.mIsSanitized,
135 aFlags.mIsSkippedByIteration,
139 Result<Ok, nsresult> SharedPrefMapBuilder::Finalize(loader::AutoMemMap& aMap) {
140 using Header = SharedPrefMap::Header;
142 // Create an array of entry pointers for the entry array, and sort it by
143 // preference name prior to serialization, so that entries can be looked up
144 // using binary search.
145 nsTArray<Entry*> entries(mEntries.Length());
146 for (auto& entry : mEntries) {
147 entries.AppendElement(&entry);
149 entries.Sort([](const Entry* aA, const Entry* aB) {
150 return strcmp(aA->mKeyString, aB->mKeyString);
153 Header header = {uint32_t(entries.Length())};
155 size_t offset = sizeof(header);
156 offset += GetAlignmentOffset(offset, alignof(Header));
158 offset += entries.Length() * sizeof(SharedPrefMap::Entry);
160 header.mKeyStrings.mOffset = offset;
161 header.mKeyStrings.mSize = mKeyTable.Size();
162 offset += header.mKeyStrings.mSize;
164 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
165 header.mUserIntValues.mOffset = offset;
166 header.mUserIntValues.mSize = mIntValueTable.UserSize();
167 offset += header.mUserIntValues.mSize;
169 offset += GetAlignmentOffset(offset, mIntValueTable.Alignment());
170 header.mDefaultIntValues.mOffset = offset;
171 header.mDefaultIntValues.mSize = mIntValueTable.DefaultSize();
172 offset += header.mDefaultIntValues.mSize;
174 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
175 header.mUserStringValues.mOffset = offset;
176 header.mUserStringValues.mSize = mStringValueTable.UserSize();
177 offset += header.mUserStringValues.mSize;
179 offset += GetAlignmentOffset(offset, mStringValueTable.Alignment());
180 header.mDefaultStringValues.mOffset = offset;
181 header.mDefaultStringValues.mSize = mStringValueTable.DefaultSize();
182 offset += header.mDefaultStringValues.mSize;
184 header.mValueStrings.mOffset = offset;
185 header.mValueStrings.mSize = mValueStringTable.Size();
186 offset += header.mValueStrings.mSize;
188 MemMapSnapshot mem;
189 MOZ_TRY(mem.Init(offset));
191 auto headerPtr = mem.Get<Header>();
192 headerPtr[0] = header;
194 auto* entryPtr = reinterpret_cast<SharedPrefMap::Entry*>(&headerPtr[1]);
195 for (auto* entry : entries) {
196 *entryPtr = {
197 entry->mKey,
198 GetValue(*entry),
199 entry->mType,
200 entry->mHasDefaultValue,
201 entry->mHasUserValue,
202 entry->mIsSticky,
203 entry->mIsLocked,
204 entry->mIsSanitized,
205 entry->mIsSkippedByIteration,
207 entryPtr++;
210 auto ptr = mem.Get<uint8_t>();
212 mKeyTable.Write({&ptr[header.mKeyStrings.mOffset], header.mKeyStrings.mSize});
214 mValueStringTable.Write(
215 {&ptr[header.mValueStrings.mOffset], header.mValueStrings.mSize});
217 mIntValueTable.WriteDefaultValues(
218 {&ptr[header.mDefaultIntValues.mOffset], header.mDefaultIntValues.mSize});
219 mIntValueTable.WriteUserValues(
220 {&ptr[header.mUserIntValues.mOffset], header.mUserIntValues.mSize});
222 mStringValueTable.WriteDefaultValues(
223 {&ptr[header.mDefaultStringValues.mOffset],
224 header.mDefaultStringValues.mSize});
225 mStringValueTable.WriteUserValues(
226 {&ptr[header.mUserStringValues.mOffset], header.mUserStringValues.mSize});
228 mKeyTable.Clear();
229 mValueStringTable.Clear();
230 mIntValueTable.Clear();
231 mStringValueTable.Clear();
232 mEntries.Clear();
234 return mem.Finalize(aMap);
237 } // namespace mozilla