summaryrefslogtreecommitdiffstats
path: root/devtools/server/tests/xpcshell/test_unsafeDereference.js
blob: 53b70420c6c8f0592514b1be5dab89ddf208395e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/

/* eslint-disable strict */

// Test Debugger.Object.prototype.unsafeDereference in the presence of
// interesting cross-compartment wrappers.
//
// This is not really a devtools server test; it's more of a Debugger test.
// But we need xpcshell and Components.utils.Sandbox to get
// cross-compartment wrappers with interesting properties, and this is the
// xpcshell test directory most closely related to the JS Debugger API.

addDebuggerToGlobal(globalThis);

// Add a method to Debugger.Object for fetching value properties
// conveniently.
Debugger.Object.prototype.getProperty = function (name) {
  const desc = this.getOwnPropertyDescriptor(name);
  if (!desc) {
    return undefined;
  }
  if (!desc.value) {
    throw Error(
      "Debugger.Object.prototype.getProperty: " +
        "not a value property: " +
        name
    );
  }
  return desc.value;
};

function run_test() {
  // Create a low-privilege sandbox, and a chrome-privilege sandbox.
  const contentBox = Cu.Sandbox("http://www.example.com");
  const chromeBox = Cu.Sandbox(this);

  // Create an objects in this compartment, and one in each sandbox. We'll
  // refer to the objects as "mainObj", "contentObj", and "chromeObj", in
  // variable and property names.
  const mainObj = { name: "mainObj" };
  Cu.evalInSandbox('var contentObj = { name: "contentObj" };', contentBox);
  Cu.evalInSandbox('var chromeObj = { name: "chromeObj" };', chromeBox);

  // Give each global a pointer to all the other globals' objects.
  contentBox.mainObj = chromeBox.mainObj = mainObj;
  const contentObj = (chromeBox.contentObj = contentBox.contentObj);
  const chromeObj = (contentBox.chromeObj = chromeBox.chromeObj);

  // First, a whole bunch of basic sanity checks, to ensure that JavaScript
  // evaluated in various scopes really does see the world the way this
  // test expects it to.

  // The objects appear as global variables in the sandbox, and as
  // the sandbox object's properties in chrome.
  Assert.ok(Cu.evalInSandbox("mainObj", contentBox) === contentBox.mainObj);
  Assert.ok(
    Cu.evalInSandbox("contentObj", contentBox) === contentBox.contentObj
  );
  Assert.ok(Cu.evalInSandbox("chromeObj", contentBox) === contentBox.chromeObj);
  Assert.ok(Cu.evalInSandbox("mainObj", chromeBox) === chromeBox.mainObj);
  Assert.ok(Cu.evalInSandbox("contentObj", chromeBox) === chromeBox.contentObj);
  Assert.ok(Cu.evalInSandbox("chromeObj", chromeBox) === chromeBox.chromeObj);

  // We (the main global) can see properties of all objects in all globals.
  Assert.ok(contentBox.mainObj.name === "mainObj");
  Assert.ok(contentBox.contentObj.name === "contentObj");
  Assert.ok(contentBox.chromeObj.name === "chromeObj");

  // chromeBox can see properties of all objects in all globals.
  Assert.equal(Cu.evalInSandbox("mainObj.name", chromeBox), "mainObj");
  Assert.equal(Cu.evalInSandbox("contentObj.name", chromeBox), "contentObj");
  Assert.equal(Cu.evalInSandbox("chromeObj.name", chromeBox), "chromeObj");

  // contentBox can see properties of the content object, but not of either
  // chrome object, because by default, content -> chrome wrappers hide all
  // object properties.
  Assert.equal(Cu.evalInSandbox("mainObj.name", contentBox), undefined);
  Assert.equal(Cu.evalInSandbox("contentObj.name", contentBox), "contentObj");
  Assert.equal(Cu.evalInSandbox("chromeObj.name", contentBox), undefined);

  // When viewing an object in compartment A from the vantage point of
  // compartment B, Debugger should give the same results as debuggee code
  // would.

  // Create a debugger, debugging our two sandboxes.
  const dbg = new Debugger();

  // Create Debugger.Object instances referring to the two sandboxes, as
  // seen from their own compartments.
  const contentBoxDO = dbg.addDebuggee(contentBox);
  const chromeBoxDO = dbg.addDebuggee(chromeBox);

  // Use Debugger to view the objects from contentBox. We should get the
  // same D.O instance from both getProperty and makeDebuggeeValue, and the
  // same property visibility we checked for above.
  const mainFromContentDO = contentBoxDO.getProperty("mainObj");
  Assert.equal(mainFromContentDO, contentBoxDO.makeDebuggeeValue(mainObj));
  Assert.equal(mainFromContentDO.getProperty("name"), undefined);
  Assert.equal(mainFromContentDO.unsafeDereference(), mainObj);

  const contentFromContentDO = contentBoxDO.getProperty("contentObj");
  Assert.equal(
    contentFromContentDO,
    contentBoxDO.makeDebuggeeValue(contentObj)
  );
  Assert.equal(contentFromContentDO.getProperty("name"), "contentObj");
  Assert.equal(contentFromContentDO.unsafeDereference(), contentObj);

  const chromeFromContentDO = contentBoxDO.getProperty("chromeObj");
  Assert.equal(chromeFromContentDO, contentBoxDO.makeDebuggeeValue(chromeObj));
  Assert.equal(chromeFromContentDO.getProperty("name"), undefined);
  Assert.equal(chromeFromContentDO.unsafeDereference(), chromeObj);

  // Similarly, viewing from chromeBox.
  const mainFromChromeDO = chromeBoxDO.getProperty("mainObj");
  Assert.equal(mainFromChromeDO, chromeBoxDO.makeDebuggeeValue(mainObj));
  Assert.equal(mainFromChromeDO.getProperty("name"), "mainObj");
  Assert.equal(mainFromChromeDO.unsafeDereference(), mainObj);

  const contentFromChromeDO = chromeBoxDO.getProperty("contentObj");
  Assert.equal(contentFromChromeDO, chromeBoxDO.makeDebuggeeValue(contentObj));
  Assert.equal(contentFromChromeDO.getProperty("name"), "contentObj");
  Assert.equal(contentFromChromeDO.unsafeDereference(), contentObj);

  const chromeFromChromeDO = chromeBoxDO.getProperty("chromeObj");
  Assert.equal(chromeFromChromeDO, chromeBoxDO.makeDebuggeeValue(chromeObj));
  Assert.equal(chromeFromChromeDO.getProperty("name"), "chromeObj");
  Assert.equal(chromeFromChromeDO.unsafeDereference(), chromeObj);
}