Track visited parents and null out cycles
authorKevin Sawicki <kevinsawicki@gmail.com>
Wed, 4 Jan 2017 22:50:05 +0000 (14:50 -0800)
committerKevin Sawicki <kevinsawicki@gmail.com>
Fri, 6 Jan 2017 17:58:40 +0000 (09:58 -0800)
lib/browser/guest-window-manager.js
spec/chromium-spec.js
spec/static/main.js

index 8212e50..c0a5efb 100644 (file)
@@ -7,19 +7,25 @@ const hasProp = {}.hasOwnProperty
 const frameToGuest = {}
 
 // Copy attribute of |parent| to |child| if it is not defined in |child|.
-const mergeOptions = function (child, parent) {
-  let key, value
-  for (key in parent) {
+const mergeOptions = function (child, parent, visited) {
+  // Check for circular reference.
+  if (visited == null) visited = new Set()
+  if (visited.has(parent)) return
+
+  visited.add(parent)
+  for (const key in parent) {
     if (!hasProp.call(parent, key)) continue
-    value = parent[key]
-    if (!(key in child)) {
-      if (typeof value === 'object') {
-        child[key] = mergeOptions({}, value)
-      } else {
-        child[key] = value
-      }
+    if (key in child) continue
+
+    const value = parent[key]
+    if (typeof value === 'object') {
+      child[key] = mergeOptions({}, value, visited)
+    } else {
+      child[key] = value
     }
   }
+  visited.delete(parent)
+
   return child
 }
 
index 039fc1e..e663dcc 100644 (file)
@@ -270,10 +270,13 @@ describe('chromium feature', function () {
       w = BrowserWindow.fromId(ipcRenderer.sendSync('create-window-with-options-cycle'))
       w.loadURL('file://' + fixtures + '/pages/window-open.html')
       w.webContents.once('new-window',  (event, url, frameName, disposition, options) => {
-        assert.deepEqual(options, {
-          show: false,
-          foo: {
-            bar: null
+        assert.equal(options.show, false)
+        assert.deepEqual(options.foo, {
+          bar: null,
+          baz: {
+            hello: {
+              world: true
+            }
           }
         })
         done()
index aad8a64..9b9f6c0 100644 (file)
@@ -237,6 +237,11 @@ ipcMain.on('create-window-with-options-cycle', (event) => {
   // nulled out at the IPC layer
   const foo = {}
   foo.bar  = foo
+  foo.baz = {
+    hello: {
+      world: true
+    }
+  }
   const window = new BrowserWindow({show: false, foo: foo})
   event.returnValue = window.id
 })