Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/CrashReporterMetadataShmem.cpp
Line
Count
Source (jump to first uncovered line)
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 "CrashReporterMetadataShmem.h"
8
#include "mozilla/Attributes.h"
9
#include "mozilla/EnumeratedRange.h"
10
#include "nsISupportsImpl.h"
11
12
namespace mozilla {
13
namespace ipc {
14
15
using CrashReporter::Annotation;
16
17
enum class EntryType : uint8_t {
18
  None,
19
  Annotation,
20
};
21
22
CrashReporterMetadataShmem::CrashReporterMetadataShmem(const Shmem& aShmem)
23
 : mShmem(aShmem)
24
0
{
25
0
  MOZ_COUNT_CTOR(CrashReporterMetadataShmem);
26
0
}
27
28
CrashReporterMetadataShmem::~CrashReporterMetadataShmem()
29
0
{
30
0
  MOZ_COUNT_DTOR(CrashReporterMetadataShmem);
31
0
}
32
33
void
34
CrashReporterMetadataShmem::AnnotateCrashReport(Annotation aKey,
35
                                                const nsCString& aData)
36
0
{
37
0
  mAnnotations[aKey] = aData;
38
0
  SyncNotesToShmem();
39
0
}
40
41
void
42
CrashReporterMetadataShmem::AppendAppNotes(const nsCString& aData)
43
0
{
44
0
  mAppNotes.Append(aData);
45
0
  mAnnotations[Annotation::Notes] = mAppNotes;
46
0
  SyncNotesToShmem();
47
0
}
48
49
class MOZ_STACK_CLASS MetadataShmemWriter
50
{
51
public:
52
  explicit MetadataShmemWriter(const Shmem& aShmem)
53
   : mCursor(aShmem.get<uint8_t>()),
54
     mEnd(mCursor + aShmem.Size<uint8_t>())
55
0
  {
56
0
    *mCursor = uint8_t(EntryType::None);
57
0
  }
58
59
0
  MOZ_MUST_USE bool WriteAnnotation(Annotation aKey, const nsCString& aValue) {
60
0
    // This shouldn't happen because Commit() guarantees mCursor < mEnd. But
61
0
    // we might as well be safe.
62
0
    if (mCursor >= mEnd) {
63
0
      return false;
64
0
    }
65
0
66
0
    // Save the current position so we can write the entry type if the entire
67
0
    // entry fits.
68
0
    uint8_t* start = mCursor++;
69
0
    if (!Write(aKey) || !Write(aValue)) {
70
0
      return false;
71
0
    }
72
0
    return Commit(start, EntryType::Annotation);
73
0
  }
74
75
private:
76
  // On success, append a new terminal byte. On failure, rollback the cursor.
77
0
  MOZ_MUST_USE bool Commit(uint8_t* aStart, EntryType aType) {
78
0
    MOZ_ASSERT(aStart < mEnd);
79
0
    MOZ_ASSERT(EntryType(*aStart) == EntryType::None);
80
0
81
0
    if (mCursor >= mEnd) {
82
0
      // No room for a terminating byte - rollback.
83
0
      mCursor = aStart;
84
0
      return false;
85
0
    }
86
0
87
0
    // Commit the entry and write a new terminal byte.
88
0
    *aStart = uint8_t(aType);
89
0
    *mCursor = uint8_t(EntryType::None);
90
0
    return true;
91
0
  }
92
93
0
  MOZ_MUST_USE bool Write(const nsCString& aString) {
94
0
    // 32-bit length is okay since our shmems are very small (16K),
95
0
    // a huge write would fail anyway.
96
0
    return Write(static_cast<uint32_t>(aString.Length())) &&
97
0
           Write(aString.get(), aString.Length());
98
0
  }
99
100
  template <typename T>
101
0
  MOZ_MUST_USE bool Write(const T& aT) {
102
0
    return Write(&aT, sizeof(T));
103
0
  }
Unexecuted instantiation: bool mozilla::ipc::MetadataShmemWriter::Write<CrashReporter::Annotation>(CrashReporter::Annotation const&)
Unexecuted instantiation: bool mozilla::ipc::MetadataShmemWriter::Write<unsigned int>(unsigned int const&)
104
105
0
  MOZ_MUST_USE bool Write(const void* aData, size_t aLength) {
106
0
    if (size_t(mEnd - mCursor) < aLength) {
107
0
      return false;
108
0
    }
109
0
    memcpy(mCursor, aData, aLength);
110
0
    mCursor += aLength;
111
0
    return true;
112
0
  }
113
114
 private:
115
  // The cursor (beginning at start) always points to a single byte
116
  // representing the next EntryType. An EntryType is either None,
117
  // indicating there are no more entries, or Annotation, meaning
118
  // two strings follow.
119
  //
120
  // Strings are written as a 32-bit length and byte sequence. After each new
121
  // entry, a None entry is always appended, and a subsequent entry will
122
  // overwrite this byte.
123
  uint8_t* mCursor;
124
  uint8_t* mEnd;
125
};
126
127
void
128
CrashReporterMetadataShmem::SyncNotesToShmem()
129
0
{
130
0
  MetadataShmemWriter writer(mShmem);
131
0
132
0
  for (auto key : MakeEnumeratedRange(Annotation::Count)) {
133
0
    if (!mAnnotations[key].IsEmpty()) {
134
0
      if (!writer.WriteAnnotation(key, mAnnotations[key])) {
135
0
        return;
136
0
      }
137
0
    }
138
0
  }
139
0
}
140
141
// Helper class to iterate over metadata entries encoded in shmem.
142
class MOZ_STACK_CLASS MetadataShmemReader
143
{
144
public:
145
  explicit MetadataShmemReader(const Shmem& aShmem)
146
   : mEntryType(EntryType::None)
147
0
  {
148
0
    mCursor = aShmem.get<uint8_t>();
149
0
    mEnd = mCursor + aShmem.Size<uint8_t>();
150
0
151
0
    // Advance to the first item, if any.
152
0
    Next();
153
0
  }
154
155
0
  bool Done() const {
156
0
    return mCursor >= mEnd || Type() == EntryType::None;
157
0
  }
158
0
  EntryType Type() const {
159
0
    return mEntryType;
160
0
  }
161
0
  void Next() {
162
0
    if (mCursor < mEnd) {
163
0
      mEntryType = EntryType(*mCursor++);
164
0
    } else {
165
0
      mEntryType = EntryType::None;
166
0
    }
167
0
  }
168
169
  template <typename T>
170
0
  bool Read(T* aOut) {
171
0
    return Read(aOut, sizeof(T));
172
0
  }
Unexecuted instantiation: bool mozilla::ipc::MetadataShmemReader::Read<unsigned int>(unsigned int*)
Unexecuted instantiation: bool mozilla::ipc::MetadataShmemReader::Read<CrashReporter::Annotation>(CrashReporter::Annotation*)
173
174
0
  bool Read(nsCString& aOut) {
175
0
    uint32_t length = 0;
176
0
    if (!Read(&length)) {
177
0
      return false;
178
0
    }
179
0
180
0
    const uint8_t* src = Read(length);
181
0
    if (!src) {
182
0
      return false;
183
0
    }
184
0
185
0
    aOut.Assign((const char *)src, length);
186
0
    return true;
187
0
  }
188
189
private:
190
0
  bool Read(void* aOut, size_t aLength) {
191
0
    const uint8_t* src = Read(aLength);
192
0
    if (!src) {
193
0
      return false;
194
0
    }
195
0
    memcpy(aOut, src, aLength);
196
0
    return true;
197
0
  }
198
199
  // If buffer has |aLength| bytes, return cursor and then advance it.
200
  // Otherwise, return null.
201
0
  const uint8_t* Read(size_t aLength) {
202
0
    if (size_t(mEnd - mCursor) < aLength) {
203
0
      return nullptr;
204
0
    }
205
0
    const uint8_t* result = mCursor;
206
0
    mCursor += aLength;
207
0
    return result;
208
0
  }
209
210
private:
211
  const uint8_t* mCursor;
212
  const uint8_t* mEnd;
213
  EntryType mEntryType;
214
};
215
216
void
217
CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem,
218
                                         AnnotationTable& aNotes)
219
0
{
220
0
  for (MetadataShmemReader reader(aShmem); !reader.Done(); reader.Next()) {
221
0
    switch (reader.Type()) {
222
0
      case EntryType::Annotation: {
223
0
        Annotation key;
224
0
        nsCString value;
225
0
        if (!reader.Read(&key) || !reader.Read(value)) {
226
0
          return;
227
0
        }
228
0
229
0
        aNotes[key] = value;
230
0
        break;
231
0
      }
232
0
      default:
233
0
        NS_ASSERTION(false, "Unknown metadata entry type");
234
0
        break;
235
0
    }
236
0
  }
237
0
}
238
239
} // namespace ipc
240
} // namespace mozilla