Coverage Report

Created: 2018-09-25 14:53

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