Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/devtools/DeserializedNode.h
Line
Count
Source (jump to first uncovered line)
1
/* -*-  Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef mozilla_devtools_DeserializedNode__
7
#define mozilla_devtools_DeserializedNode__
8
9
#include "js/UbiNode.h"
10
#include "js/UniquePtr.h"
11
#include "mozilla/devtools/CoreDump.pb.h"
12
#include "mozilla/HashFunctions.h"
13
#include "mozilla/Maybe.h"
14
#include "mozilla/Move.h"
15
#include "mozilla/Vector.h"
16
17
// `Deserialized{Node,Edge}` translate protobuf messages from our core dump
18
// format into structures we can rely upon for implementing `JS::ubi::Node`
19
// specializations on top of. All of the properties of the protobuf messages are
20
// optional for future compatibility, and this is the layer where we validate
21
// that the properties that do actually exist in any given message fulfill our
22
// semantic requirements.
23
//
24
// Both `DeserializedNode` and `DeserializedEdge` are always owned by a
25
// `HeapSnapshot` instance, and their lifetimes must not extend after that of
26
// their owning `HeapSnapshot`.
27
28
namespace mozilla {
29
namespace devtools {
30
31
class HeapSnapshot;
32
33
using NodeId = uint64_t;
34
using StackFrameId = uint64_t;
35
36
// A `DeserializedEdge` represents an edge in the heap graph pointing to the
37
// node with id equal to `DeserializedEdge::referent` that we deserialized from
38
// a core dump.
39
struct DeserializedEdge {
40
  NodeId         referent;
41
  // A borrowed reference to a string owned by this node's owning HeapSnapshot.
42
  const char16_t* name;
43
44
  explicit DeserializedEdge(NodeId referent, const char16_t* edgeName = nullptr)
45
    : referent(referent)
46
    , name(edgeName)
47
0
  { }
48
  DeserializedEdge(DeserializedEdge&& rhs);
49
  DeserializedEdge& operator=(DeserializedEdge&& rhs);
50
51
private:
52
  DeserializedEdge(const DeserializedEdge&) = delete;
53
  DeserializedEdge& operator=(const DeserializedEdge&) = delete;
54
};
55
56
// A `DeserializedNode` is a node in the heap graph that we deserialized from a
57
// core dump.
58
struct DeserializedNode {
59
  using EdgeVector = Vector<DeserializedEdge>;
60
  using UniqueStringPtr = UniquePtr<char16_t[]>;
61
62
  NodeId              id;
63
  JS::ubi::CoarseType coarseType;
64
  // A borrowed reference to a string owned by this node's owning HeapSnapshot.
65
  const char16_t*     typeName;
66
  uint64_t            size;
67
  EdgeVector          edges;
68
  Maybe<StackFrameId> allocationStack;
69
  // A borrowed reference to a string owned by this node's owning HeapSnapshot.
70
  const char*         jsObjectClassName;
71
  // A borrowed reference to a string owned by this node's owning HeapSnapshot.
72
  const char*         scriptFilename;
73
  // A borrowed reference to a string owned by this node's owning HeapSnapshot.
74
  const char16_t*     descriptiveTypeName;
75
  // A weak pointer to this node's owning `HeapSnapshot`. Safe without
76
  // AddRef'ing because this node's lifetime is equal to that of its owner.
77
  HeapSnapshot*       owner;
78
79
  DeserializedNode(NodeId id,
80
                   JS::ubi::CoarseType coarseType,
81
                   const char16_t* typeName,
82
                   uint64_t size,
83
                   EdgeVector&& edges,
84
                   const Maybe<StackFrameId>& allocationStack,
85
                   const char* className,
86
                   const char* filename,
87
                   const char16_t* descriptiveName,
88
                   HeapSnapshot& owner)
89
    : id(id)
90
    , coarseType(coarseType)
91
    , typeName(typeName)
92
    , size(size)
93
    , edges(std::move(edges))
94
    , allocationStack(allocationStack)
95
    , jsObjectClassName(className)
96
    , scriptFilename(filename)
97
    , descriptiveTypeName(descriptiveName)
98
    , owner(&owner)
99
0
  { }
100
0
  virtual ~DeserializedNode() { }
101
102
  DeserializedNode(DeserializedNode&& rhs)
103
    : id(rhs.id)
104
    , coarseType(rhs.coarseType)
105
    , typeName(rhs.typeName)
106
    , size(rhs.size)
107
    , edges(std::move(rhs.edges))
108
    , allocationStack(rhs.allocationStack)
109
    , jsObjectClassName(rhs.jsObjectClassName)
110
    , scriptFilename(rhs.scriptFilename)
111
    , descriptiveTypeName(rhs.descriptiveTypeName)
112
    , owner(rhs.owner)
113
0
  { }
114
115
  DeserializedNode& operator=(DeserializedNode&& rhs)
116
0
  {
117
0
    MOZ_ASSERT(&rhs != this);
118
0
    this->~DeserializedNode();
119
0
    new(this) DeserializedNode(std::move(rhs));
120
0
    return *this;
121
0
  }
122
123
  // Get a borrowed reference to the given edge's referent. This method is
124
  // virtual to provide a hook for gmock and gtest.
125
  virtual JS::ubi::Node getEdgeReferent(const DeserializedEdge& edge);
126
127
  struct HashPolicy;
128
129
protected:
130
  // This is only for use with `MockDeserializedNode` in testing.
131
  DeserializedNode(NodeId id, const char16_t* typeName, uint64_t size)
132
    : id(id)
133
    , coarseType(JS::ubi::CoarseType::Other)
134
    , typeName(typeName)
135
    , size(size)
136
    , edges()
137
    , allocationStack(Nothing())
138
    , jsObjectClassName(nullptr)
139
    , scriptFilename(nullptr)
140
    , descriptiveTypeName(nullptr)
141
    , owner(nullptr)
142
0
  { }
143
144
private:
145
  DeserializedNode(const DeserializedNode&) = delete;
146
  DeserializedNode& operator=(const DeserializedNode&) = delete;
147
};
148
149
static inline js::HashNumber
150
hashIdDerivedFromPtr(uint64_t id)
151
0
{
152
0
    return mozilla::HashGeneric(id);
153
0
}
Unexecuted instantiation: UnifiedBindings2.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: UnifiedBindings4.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: UnifiedBindings8.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: DeserializedNode.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: DominatorTree.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: HeapSnapshot.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: HeapSnapshotTempFileHelperParent.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:mozilla::devtools::hashIdDerivedFromPtr(unsigned long)
154
155
struct DeserializedNode::HashPolicy
156
{
157
  using Lookup = NodeId;
158
159
0
  static js::HashNumber hash(const Lookup& lookup) {
160
0
    return hashIdDerivedFromPtr(lookup);
161
0
  }
162
163
0
  static bool match(const DeserializedNode& existing, const Lookup& lookup) {
164
0
    return existing.id == lookup;
165
0
  }
166
};
167
168
// A `DeserializedStackFrame` is a stack frame referred to by a thing in the
169
// heap graph that we deserialized from a core dump.
170
struct DeserializedStackFrame {
171
  StackFrameId        id;
172
  Maybe<StackFrameId> parent;
173
  uint32_t            line;
174
  uint32_t            column;
175
  // Borrowed references to strings owned by this DeserializedStackFrame's
176
  // owning HeapSnapshot.
177
  const char16_t*     source;
178
  const char16_t*     functionDisplayName;
179
  bool                isSystem;
180
  bool                isSelfHosted;
181
  // A weak pointer to this frame's owning `HeapSnapshot`. Safe without
182
  // AddRef'ing because this frame's lifetime is equal to that of its owner.
183
  HeapSnapshot*       owner;
184
185
  explicit DeserializedStackFrame(StackFrameId id,
186
                                  const Maybe<StackFrameId>& parent,
187
                                  uint32_t line,
188
                                  uint32_t column,
189
                                  const char16_t* source,
190
                                  const char16_t* functionDisplayName,
191
                                  bool isSystem,
192
                                  bool isSelfHosted,
193
                                  HeapSnapshot& owner)
194
    : id(id)
195
    , parent(parent)
196
    , line(line)
197
    , column(column)
198
    , source(source)
199
    , functionDisplayName(functionDisplayName)
200
    , isSystem(isSystem)
201
    , isSelfHosted(isSelfHosted)
202
    , owner(&owner)
203
0
  {
204
0
    MOZ_ASSERT(source);
205
0
  }
206
207
  JS::ubi::StackFrame getParentStackFrame() const;
208
209
  struct HashPolicy;
210
211
protected:
212
  // This is exposed only for MockDeserializedStackFrame in the gtests.
213
  explicit DeserializedStackFrame()
214
    : id(0)
215
    , parent(Nothing())
216
    , line(0)
217
    , column(0)
218
    , source(nullptr)
219
    , functionDisplayName(nullptr)
220
    , isSystem(false)
221
    , isSelfHosted(false)
222
    , owner(nullptr)
223
0
  { };
224
};
225
226
struct DeserializedStackFrame::HashPolicy {
227
  using Lookup = StackFrameId;
228
229
0
  static js::HashNumber hash(const Lookup& lookup) {
230
0
    return hashIdDerivedFromPtr(lookup);
231
0
  }
232
233
0
  static bool match(const DeserializedStackFrame& existing, const Lookup& lookup) {
234
0
    return existing.id == lookup;
235
0
  }
236
};
237
238
} // namespace devtools
239
} // namespace mozilla
240
241
namespace JS {
242
namespace ubi {
243
244
using mozilla::devtools::DeserializedNode;
245
using mozilla::devtools::DeserializedStackFrame;
246
247
template<>
248
class Concrete<DeserializedNode> : public Base
249
{
250
protected:
251
0
  explicit Concrete(DeserializedNode* ptr) : Base(ptr) { }
252
0
  DeserializedNode& get() const {
253
0
    return *static_cast<DeserializedNode*>(ptr);
254
0
  }
255
256
public:
257
0
  static void construct(void* storage, DeserializedNode* ptr) {
258
0
    new (storage) Concrete(ptr);
259
0
  }
260
261
0
  CoarseType coarseType() const final { return get().coarseType; }
262
0
  Id identifier() const override { return get().id; }
263
0
  bool isLive() const override { return false; }
264
  const char16_t* typeName() const override;
265
  Node::Size size(mozilla::MallocSizeOf mallocSizeof) const override;
266
0
  const char* jsObjectClassName() const override { return get().jsObjectClassName; }
267
0
  const char* scriptFilename() const final { return get().scriptFilename; }
268
0
  const char16_t* descriptiveTypeName() const override { return get().descriptiveTypeName; }
269
270
0
  bool hasAllocationStack() const override { return get().allocationStack.isSome(); }
271
  StackFrame allocationStack() const override;
272
273
  // We ignore the `bool wantNames` parameter because we can't control whether
274
  // the core dump was serialized with edge names or not.
275
  js::UniquePtr<EdgeRange> edges(JSContext* cx, bool) const override;
276
277
  static const char16_t concreteTypeName[];
278
};
279
280
template<>
281
class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame
282
{
283
protected:
284
  explicit ConcreteStackFrame(DeserializedStackFrame* ptr)
285
    : BaseStackFrame(ptr)
286
0
  { }
287
288
0
  DeserializedStackFrame& get() const {
289
0
    return *static_cast<DeserializedStackFrame*>(ptr);
290
0
  }
291
292
public:
293
0
  static void construct(void* storage, DeserializedStackFrame* ptr) {
294
0
    new (storage) ConcreteStackFrame(ptr);
295
0
  }
296
297
0
  uint64_t identifier() const override { return get().id; }
298
0
  uint32_t line() const override { return get().line; }
299
0
  uint32_t column() const override { return get().column; }
300
0
  bool isSystem() const override { return get().isSystem; }
301
0
  bool isSelfHosted(JSContext* cx) const override { return get().isSelfHosted; }
302
0
  void trace(JSTracer* trc) override { }
303
0
  AtomOrTwoByteChars source() const override {
304
0
    return AtomOrTwoByteChars(get().source);
305
0
  }
306
0
  AtomOrTwoByteChars functionDisplayName() const override {
307
0
    return AtomOrTwoByteChars(get().functionDisplayName);
308
0
  }
309
310
  StackFrame parent() const override;
311
  bool constructSavedFrameStack(JSContext* cx,
312
                                MutableHandleObject outSavedFrameStack)
313
    const override;
314
};
315
316
} // namespace ubi
317
} // namespace JS
318
319
#endif // mozilla_devtools_DeserializedNode__