Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/Console.h
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
#ifndef mozilla_dom_Console_h
8
#define mozilla_dom_Console_h
9
10
#include "mozilla/dom/ConsoleBinding.h"
11
#include "mozilla/JSObjectHolder.h"
12
#include "mozilla/TimeStamp.h"
13
#include "nsCycleCollectionParticipant.h"
14
#include "nsDataHashtable.h"
15
#include "nsHashKeys.h"
16
#include "nsIObserver.h"
17
#include "nsWeakReference.h"
18
#include "nsDOMNavigationTiming.h"
19
#include "nsPIDOMWindow.h"
20
21
class nsIConsoleAPIStorage;
22
class nsIPrincipal;
23
class nsIStackFrame;
24
25
namespace mozilla {
26
namespace dom {
27
28
class AnyCallback;
29
class ConsoleCallData;
30
class ConsoleInstance;
31
class ConsoleInstanceDumpCallback;
32
class ConsoleRunnable;
33
class ConsoleCallDataRunnable;
34
class ConsoleProfileRunnable;
35
36
class Console final : public nsIObserver
37
                    , public nsSupportsWeakReference
38
{
39
public:
40
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
41
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Console, nsIObserver)
42
  NS_DECL_NSIOBSERVER
43
44
  static already_AddRefed<Console>
45
  Create(JSContext* aCx, nsPIDOMWindowInner* aWindow, ErrorResult& aRv);
46
47
  static already_AddRefed<Console>
48
  CreateForWorklet(JSContext* aCx, uint64_t aOuterWindowID,
49
                   uint64_t aInnerWindowID, ErrorResult& aRv);
50
51
  // WebIDL methods
52
  nsPIDOMWindowInner* GetParentObject() const
53
0
  {
54
0
    return mWindow;
55
0
  }
56
57
  static void
58
  Log(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
59
60
  static void
61
  Info(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
62
63
  static void
64
  Warn(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
65
66
  static void
67
  Error(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
68
69
  static void
70
  Exception(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
71
72
  static void
73
  Debug(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
74
75
  static void
76
  Table(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
77
78
  static void
79
  Trace(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
80
81
  static void
82
  Dir(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
83
84
  static void
85
  Dirxml(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
86
87
  static void
88
  Group(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
89
90
  static void
91
  GroupCollapsed(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
92
93
  static void
94
  GroupEnd(const GlobalObject& aGlobal);
95
96
  static void
97
  Time(const GlobalObject& aGlobal, const nsAString& aLabel);
98
99
  static void
100
  TimeLog(const GlobalObject& aGlobal, const nsAString& aLabel,
101
          const Sequence<JS::Value>& aData);
102
103
  static void
104
  TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel);
105
106
  static void
107
  TimeStamp(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aData);
108
109
  static void
110
  Profile(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
111
112
  static void
113
  ProfileEnd(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
114
115
  static void
116
  Assert(const GlobalObject& aGlobal, bool aCondition,
117
         const Sequence<JS::Value>& aData);
118
119
  static void
120
  Count(const GlobalObject& aGlobal, const nsAString& aLabel);
121
122
  static void
123
  CountReset(const GlobalObject& aGlobal, const nsAString& aLabel);
124
125
  static void
126
  Clear(const GlobalObject& aGlobal);
127
128
  static already_AddRefed<ConsoleInstance>
129
  CreateInstance(const GlobalObject& aGlobal,
130
                 const ConsoleInstanceOptions& aOptions);
131
132
  void
133
  ClearStorage();
134
135
  void
136
  RetrieveConsoleEvents(JSContext* aCx, nsTArray<JS::Value>& aEvents,
137
                        ErrorResult& aRv);
138
139
  void
140
  SetConsoleEventHandler(AnyCallback* aHandler);
141
142
private:
143
  Console(JSContext* aCx, nsPIDOMWindowInner* aWindow,
144
          uint64_t aOuterWindowID, uint64_t aInnerWIndowID);
145
  ~Console();
146
147
  void
148
  Initialize(ErrorResult& aRv);
149
150
  void
151
  Shutdown();
152
153
  enum MethodName
154
  {
155
    MethodLog,
156
    MethodInfo,
157
    MethodWarn,
158
    MethodError,
159
    MethodException,
160
    MethodDebug,
161
    MethodTable,
162
    MethodTrace,
163
    MethodDir,
164
    MethodDirxml,
165
    MethodGroup,
166
    MethodGroupCollapsed,
167
    MethodGroupEnd,
168
    MethodTime,
169
    MethodTimeLog,
170
    MethodTimeEnd,
171
    MethodTimeStamp,
172
    MethodAssert,
173
    MethodCount,
174
    MethodCountReset,
175
    MethodClear,
176
    MethodProfile,
177
    MethodProfileEnd,
178
  };
179
180
  static already_AddRefed<Console>
181
  GetConsole(const GlobalObject& aGlobal);
182
183
  static already_AddRefed<Console>
184
  GetConsoleInternal(const GlobalObject& aGlobal, ErrorResult &aRv);
185
186
  static void
187
  ProfileMethod(const GlobalObject& aGlobal, MethodName aName,
188
                const nsAString& aAction, const Sequence<JS::Value>& aData);
189
190
  void
191
  ProfileMethodInternal(JSContext* aCx, MethodName aName,
192
                        const nsAString& aAction,
193
                        const Sequence<JS::Value>& aData);
194
195
  static void
196
  Method(const GlobalObject& aGlobal, MethodName aName,
197
         const nsAString& aString, const Sequence<JS::Value>& aData);
198
199
  void
200
  MethodInternal(JSContext* aCx, MethodName aName,
201
                 const nsAString& aString, const Sequence<JS::Value>& aData);
202
203
  static void
204
  StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
205
               const Sequence<JS::Value>& aData, MethodName aMethodName,
206
               const nsAString& aMethodString);
207
208
  void
209
  StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
210
                       const Sequence<JS::Value>& aData,
211
                       MethodName aMethodName, const nsAString& aMethodString);
212
213
  // This method must receive aCx and aArguments in the same JS::Compartment.
214
  void
215
  ProcessCallData(JSContext* aCx,
216
                  ConsoleCallData* aData,
217
                  const Sequence<JS::Value>& aArguments);
218
219
  void
220
  StoreCallData(ConsoleCallData* aData);
221
222
  void
223
  UnstoreCallData(ConsoleCallData* aData);
224
225
  // Read in Console.cpp how this method is used.
226
  void
227
  ReleaseCallData(ConsoleCallData* aCallData);
228
229
  // aCx and aArguments must be in the same JS compartment.
230
  void
231
  NotifyHandler(JSContext* aCx,
232
                const Sequence<JS::Value>& aArguments,
233
                ConsoleCallData* aData);
234
235
  // PopulateConsoleNotificationInTheTargetScope receives aCx and aArguments in
236
  // the same JS compartment and populates the ConsoleEvent object (aValue) in
237
  // the aTargetScope.
238
  // aTargetScope can be:
239
  // - the system-principal scope when we want to dispatch the ConsoleEvent to
240
  //   nsIConsoleAPIStorage (See the comment in Console.cpp about the use of
241
  //   xpc::PrivilegedJunkScope()
242
  // - the mConsoleEventNotifier->CallableGlobal() when we want to notify this
243
  //   handler about a new ConsoleEvent.
244
  // - It can be the global from the JSContext when RetrieveConsoleEvents is
245
  //   called.
246
  bool
247
  PopulateConsoleNotificationInTheTargetScope(JSContext* aCx,
248
                                              const Sequence<JS::Value>& aArguments,
249
                                              JS::Handle<JSObject*> aTargetScope,
250
                                              JS::MutableHandle<JS::Value> aValue,
251
                                              ConsoleCallData* aData);
252
253
  // If the first JS::Value of the array is a string, this method uses it to
254
  // format a string. The supported sequences are:
255
  //   %s    - string
256
  //   %d,%i - integer
257
  //   %f    - double
258
  //   %o,%O - a JS object.
259
  //   %c    - style string.
260
  // The output is an array where any object is a separated item, the rest is
261
  // unified in a format string.
262
  // Example if the input is:
263
  //   "string: %s, integer: %d, object: %o, double: %d", 's', 1, window, 0.9
264
  // The output will be:
265
  //   [ "string: s, integer: 1, object: ", window, ", double: 0.9" ]
266
  //
267
  // The aStyles array is populated with the style strings that the function
268
  // finds based the format string. The index of the styles matches the indexes
269
  // of elements that need the custom styling from aSequence. For elements with
270
  // no custom styling the array is padded with null elements.
271
  bool
272
  ProcessArguments(JSContext* aCx, const Sequence<JS::Value>& aData,
273
                   Sequence<JS::Value>& aSequence,
274
                   Sequence<nsString>& aStyles) const;
275
276
  void
277
  MakeFormatString(nsCString& aFormat, int32_t aInteger, int32_t aMantissa,
278
                   char aCh) const;
279
280
  // Stringify and Concat all the JS::Value in a single string using ' ' as
281
  // separator. The new group name will be stored in mGroupStack array.
282
  void
283
  ComposeAndStoreGroupName(JSContext* aCx, const Sequence<JS::Value>& aData,
284
                           nsAString& aName);
285
286
  // Remove the last group name and return that name. It returns false if
287
  // mGroupStack is empty.
288
  bool
289
  UnstoreGroupName(nsAString& aName);
290
291
  enum TimerStatus {
292
    eTimerUnknown,
293
    eTimerDone,
294
    eTimerAlreadyExists,
295
    eTimerDoesntExist,
296
    eTimerJSException,
297
    eTimerMaxReached,
298
  };
299
300
  JS::Value
301
  CreateTimerError(JSContext* aCx, const nsAString& aTimerLabel,
302
                   TimerStatus aStatus) const;
303
304
  // StartTimer is called on the owning thread and populates aTimerLabel and
305
  // aTimerValue.
306
  // * aCx - the JSContext rooting aName.
307
  // * aName - this is (should be) the name of the timer as JS::Value.
308
  // * aTimestamp - the monotonicTimer for this context taken from
309
  //                performance.now().
310
  // * aTimerLabel - This label will be populated with the aName converted to a
311
  //                 string.
312
  // * aTimerValue - the StartTimer value stored into (or taken from)
313
  //                 mTimerRegistry.
314
  TimerStatus
315
  StartTimer(JSContext* aCx, const JS::Value& aName,
316
             DOMHighResTimeStamp aTimestamp,
317
             nsAString& aTimerLabel,
318
             DOMHighResTimeStamp* aTimerValue);
319
320
  // CreateStartTimerValue generates a ConsoleTimerStart dictionary exposed as
321
  // JS::Value. If aTimerStatus is false, it generates a ConsoleTimerError
322
  // instead. It's called only after the execution StartTimer on the owning
323
  // thread.
324
  // * aCx - this is the context that will root the returned value.
325
  // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
326
  // * aTimerStatus - the return value of StartTimer.
327
  JS::Value
328
  CreateStartTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
329
                        TimerStatus aTimerStatus) const;
330
331
  // LogTimer follows the same pattern as StartTimer: it runs on the
332
  // owning thread and populates aTimerLabel and aTimerDuration, used by
333
  // CreateLogOrEndTimerValue.
334
  // * aCx - the JSContext rooting aName.
335
  // * aName - this is (should be) the name of the timer as JS::Value.
336
  // * aTimestamp - the monotonicTimer for this context taken from
337
  //                performance.now().
338
  // * aTimerLabel - This label will be populated with the aName converted to a
339
  //                 string.
340
  // * aTimerDuration - the difference between aTimestamp and when the timer
341
  //                    started (see StartTimer).
342
  // * aCancelTimer - if true, the timer is removed from the table.
343
  TimerStatus
344
  LogTimer(JSContext* aCx, const JS::Value& aName,
345
           DOMHighResTimeStamp aTimestamp,
346
           nsAString& aTimerLabel,
347
           double* aTimerDuration,
348
           bool aCancelTimer);
349
350
  // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
351
  // a ConsoleTimerError dictionary if aTimerStatus is false. See LogTimer.
352
  // * aCx - this is the context that will root the returned value.
353
  // * aTimerLabel - this label must be what LogTimer received as aTimerLabel.
354
  // * aTimerDuration - this is what LogTimer received as aTimerDuration
355
  // * aTimerStatus - the return value of LogTimer.
356
  JS::Value
357
  CreateLogOrEndTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
358
                           double aTimerDuration,
359
                           TimerStatus aTimerStatus) const;
360
361
  // The method populates a Sequence from an array of JS::Value.
362
  bool
363
  ArgumentsToValueList(const Sequence<JS::Value>& aData,
364
                       Sequence<JS::Value>& aSequence) const;
365
366
  // This method follows the same pattern as StartTimer: its runs on the owning
367
  // thread and populate aCountLabel, used by CreateCounterOrResetCounterValue.
368
  // Returns 3 possible values:
369
  // * MAX_PAGE_COUNTERS in case of error that has to be reported;
370
  // * 0 in case of a CX exception. The operation cannot continue;
371
  // * the incremented counter value.
372
  // Params:
373
  // * aCx - the JSContext rooting aData.
374
  // * aData - the arguments received by the console.count() method.
375
  // * aCountLabel - the label that will be populated by this method.
376
  uint32_t
377
  IncreaseCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
378
                  nsAString& aCountLabel);
379
380
  // This method follows the same pattern as StartTimer: its runs on the owning
381
  // thread and populate aCountLabel, used by CreateCounterResetValue. Returns
382
  // 3 possible values:
383
  // * MAX_PAGE_COUNTERS in case of error that has to be reported;
384
  // * 0 elsewhere. In case of a CX exception, aCountLabel will be an empty
385
  // string.
386
  // Params:
387
  // * aCx - the JSContext rooting aData.
388
  // * aData - the arguments received by the console.count() method.
389
  // * aCountLabel - the label that will be populated by this method.
390
  uint32_t
391
  ResetCounter(JSContext* aCx, const Sequence<JS::Value>& aData,
392
               nsAString& aCountLabel);
393
394
  // This method generates a ConsoleCounter dictionary as JS::Value. If
395
  // aCountValue is == MAX_PAGE_COUNTERS it generates a ConsoleCounterError
396
  // instead. See IncreaseCounter.
397
  // * aCx - this is the context that will root the returned value.
398
  // * aCountLabel - this label must be what IncreaseCounter received as
399
  //                 aTimerLabel.
400
  // * aCountValue - the return value of IncreaseCounter.
401
  JS::Value
402
  CreateCounterOrResetCounterValue(JSContext* aCx, const nsAString& aCountLabel,
403
                                   uint32_t aCountValue) const;
404
405
  bool
406
  ShouldIncludeStackTrace(MethodName aMethodName) const;
407
408
  JSObject*
409
  GetOrCreateSandbox(JSContext* aCx, nsIPrincipal* aPrincipal);
410
411
  void
412
  AssertIsOnOwningThread() const;
413
414
  bool
415
  IsShuttingDown() const;
416
417
  bool
418
  MonotonicTimer(JSContext* aCx, MethodName aMethodName,
419
                 const Sequence<JS::Value>& aData,
420
                 DOMHighResTimeStamp* aTimeStamp);
421
422
  void
423
  MaybeExecuteDumpFunction(JSContext* aCx, const nsAString& aMethodName,
424
                           const Sequence<JS::Value>& aData,
425
                           nsIStackFrame* aStack);
426
427
  void
428
  MaybeExecuteDumpFunctionForTime(JSContext* aCx, MethodName aMethodName,
429
                                  const nsAString& aMethodString,
430
                                  uint64_t aMonotonicTimer,
431
                                  const JS::Value& aData);
432
433
  void
434
  ExecuteDumpFunction(const nsAString& aMessage);
435
436
  bool
437
  IsEnabled(JSContext* aCx) const;
438
439
  bool
440
  ShouldProceed(MethodName aName) const;
441
442
  uint32_t
443
  WebIDLLogLevelToInteger(ConsoleLogLevel aLevel) const;
444
445
  uint32_t
446
  InternalLogLevelToInteger(MethodName aName) const;
447
448
  // All these nsCOMPtr are touched on main thread only.
449
  nsCOMPtr<nsPIDOMWindowInner> mWindow;
450
  nsCOMPtr<nsIConsoleAPIStorage> mStorage;
451
  RefPtr<JSObjectHolder> mSandbox;
452
453
  // Touched on the owner thread.
454
  nsDataHashtable<nsStringHashKey, DOMHighResTimeStamp> mTimerRegistry;
455
  nsDataHashtable<nsStringHashKey, uint32_t> mCounterRegistry;
456
457
  nsTArray<RefPtr<ConsoleCallData>> mCallDataStorage;
458
459
  // This array is used in a particular corner-case where:
460
  // 1. we are in a worker thread
461
  // 2. we have more than STORAGE_MAX_EVENTS
462
  // 3. but the main-thread ConsoleCallDataRunnable of the first one is still
463
  // running (this means that something very bad is happening on the
464
  // main-thread).
465
  // When this happens we want to keep the ConsoleCallData alive for traceing
466
  // its JSValues also if 'officially' this ConsoleCallData must be removed from
467
  // the storage.
468
  nsTArray<RefPtr<ConsoleCallData>> mCallDataStoragePending;
469
470
  RefPtr<AnyCallback> mConsoleEventNotifier;
471
472
  // This is the stack for groupping.
473
  nsTArray<nsString> mGroupStack;
474
475
  uint64_t mOuterID;
476
  uint64_t mInnerID;
477
478
  // Set only by ConsoleInstance:
479
  nsString mConsoleID;
480
  nsString mPassedInnerID;
481
  RefPtr<ConsoleInstanceDumpCallback> mDumpFunction;
482
  bool mDumpToStdout;
483
  nsString mPrefix;
484
  bool mChromeInstance;
485
  ConsoleLogLevel mMaxLogLevel;
486
487
  enum {
488
    eUnknown,
489
    eInitialized,
490
    eShuttingDown
491
  } mStatus;
492
493
  // This is used when Console is created and it's used only for JSM custom
494
  // console instance.
495
  mozilla::TimeStamp mCreationTimeStamp;
496
497
  friend class ConsoleCallData;
498
  friend class ConsoleCallDataWorkletRunnable;
499
  friend class ConsoleInstance;
500
  friend class ConsoleProfileWorkerRunnable;
501
  friend class ConsoleProfileWorkletRunnable;
502
  friend class ConsoleRunnable;
503
  friend class ConsoleWorkerRunnable;
504
};
505
506
} // namespace dom
507
} // namespace mozilla
508
509
#endif /* mozilla_dom_Console_h */