From 51c7e3a4858ebf5e3508c8aa23c4aa0ac245e893 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 10 Mar 2014 17:38:14 -0400 Subject: [PATCH] Bug 980965. Stop using DOM constructors as functions in chrome code. r=bholley --- addon-sdk/source/lib/sdk/io/buffer.js | 10 ++++---- .../source/test/fixtures/chrome-worker/xhr.js | 2 +- browser/base/content/test/newtab/head.js | 2 +- content/base/test/chrome/test_bug780199.xul | 2 +- content/media/test/crashtests/868504.html | 2 +- content/media/test/crashtests/876024-2.html | 2 +- content/media/test/crashtests/876834.html | 2 +- content/media/test/crashtests/894104.html | 2 +- .../chrome/test_sandbox_bindings.xul | 8 +++--- .../chrome/test_xray_event_constructor.xul | 2 +- dom/xbl/test/file_bug821850.xhtml | 2 ++ .../specialpowers/content/specialpowersAPI.js | 25 ++++++------------- toolkit/content/aboutTelemetry.js | 2 +- toolkit/devtools/server/actors/highlighter.js | 2 +- toolkit/devtools/server/actors/inspector.js | 2 +- webapprt/Startup.jsm | 2 +- 16 files changed, 30 insertions(+), 39 deletions(-) diff --git a/addon-sdk/source/lib/sdk/io/buffer.js b/addon-sdk/source/lib/sdk/io/buffer.js index 838a66afea75..3f4e5dde949a 100644 --- a/addon-sdk/source/lib/sdk/io/buffer.js +++ b/addon-sdk/source/lib/sdk/io/buffer.js @@ -58,7 +58,7 @@ function Buffer(subject, encoding /*, bufferLength */) { // If string encode it and use buffer for the returned Uint8Array // to create a local patched version that acts like node buffer. encoding = encoding || 'utf8'; - return Uint8Array(TextEncoder(encoding).encode(subject).buffer); + return Uint8Array(new TextEncoder(encoding).encode(subject).buffer); case 'object': // This form of the constructor uses the form of // Uint8Array(buffer, offset, length); @@ -84,7 +84,7 @@ Buffer.isBuffer = value => value instanceof Buffer Buffer.isEncoding = function (encoding) { if (!encoding) return false; try { - TextDecoder(encoding); + new TextDecoder(encoding); } catch(e) { return false; } @@ -95,7 +95,7 @@ Buffer.isEncoding = function (encoding) { // This is not the same as String.prototype.length since that returns the // number of characters in a string. Buffer.byteLength = (value, encoding = 'utf8') => - TextEncoder(encoding).encode(value).byteLength + new TextEncoder(encoding).encode(value).byteLength // Direct copy of the nodejs's buffer implementation: // https://github.com/joyent/node/blob/b255f4c10a80343f9ce1cee56d0288361429e214/lib/buffer.js#L146-L177 @@ -156,7 +156,7 @@ Object.defineProperties(Buffer.prototype, { encoding = !!encoding ? (encoding + '').toLowerCase() : 'utf8'; start = Math.max(0, ~~start); end = Math.min(this.length, end === void(0) ? this.length : ~~end); - return TextDecoder(encoding).decode(this.subarray(start, end)); + return new TextDecoder(encoding).decode(this.subarray(start, end)); } }, toJSON: { @@ -262,7 +262,7 @@ Object.defineProperties(Buffer.prototype, { if (length == null || length + offset > this.length) length = this.length - offset; - let buffer = TextEncoder(encoding).encode(string); + let buffer = new TextEncoder(encoding).encode(string); let result = Math.min(buffer.length, length); if (buffer.length !== length) buffer = buffer.subarray(0, length); diff --git a/addon-sdk/source/test/fixtures/chrome-worker/xhr.js b/addon-sdk/source/test/fixtures/chrome-worker/xhr.js index 87de51583ee8..05d6a406efc5 100644 --- a/addon-sdk/source/test/fixtures/chrome-worker/xhr.js +++ b/addon-sdk/source/test/fixtures/chrome-worker/xhr.js @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 'use strict'; -let xhr = XMLHttpRequest(); +let xhr = new XMLHttpRequest(); xhr.open("GET", "data:text/plain,ok", true); xhr.onload = function () { postMessage(xhr.responseText); diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js index cdcc38379caa..6df4bff9c620 100644 --- a/browser/base/content/test/newtab/head.js +++ b/browser/base/content/test/newtab/head.js @@ -492,7 +492,7 @@ function sendDragEvent(aEventType, aTarget, aData) { * @return The drag event. */ function createDragEvent(aEventType, aData) { - let dataTransfer = new getContentWindow().DataTransfer("dragstart", false); + let dataTransfer = new (getContentWindow()).DataTransfer("dragstart", false); dataTransfer.mozSetDataAt("text/x-moz-url", aData, 0); let event = getContentDocument().createEvent("DragEvents"); event.initDragEvent(aEventType, true, true, getContentWindow(), 0, 0, 0, 0, 0, diff --git a/content/base/test/chrome/test_bug780199.xul b/content/base/test/chrome/test_bug780199.xul index 1445f98dc7c0..649538becd45 100644 --- a/content/base/test/chrome/test_bug780199.xul +++ b/content/base/test/chrome/test_bug780199.xul @@ -39,7 +39,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=780199 function test() { b = document.getElementById("b"); - var m = MutationObserver(callback); + var m = new MutationObserver(callback); m.observe(b, { attributes: true, attributeOldValue: true }); b.contentDocument.documentElement.textContent = "testvalue"; b.setAttribute("src", b.getAttribute("src")); diff --git a/content/media/test/crashtests/868504.html b/content/media/test/crashtests/868504.html index 637b710ad42e..94090c1c09a8 100644 --- a/content/media/test/crashtests/868504.html +++ b/content/media/test/crashtests/868504.html @@ -5,7 +5,7 @@ function boom() { - AudioContext().createBufferSource().playbackRate.linearRampToValueAtTime(0, -1); + new AudioContext().createBufferSource().playbackRate.linearRampToValueAtTime(0, -1); } diff --git a/content/media/test/crashtests/876024-2.html b/content/media/test/crashtests/876024-2.html index 616ed7e97af0..4b9beb74532a 100644 --- a/content/media/test/crashtests/876024-2.html +++ b/content/media/test/crashtests/876024-2.html @@ -6,7 +6,7 @@ function boom() { - var bufferSource = AudioContext().createScriptProcessor().context.createBufferSource(); + var bufferSource = new AudioContext().createScriptProcessor().context.createBufferSource(); bufferSource.start(0, 0, 0); bufferSource.stop(562949953421313); } diff --git a/content/media/test/crashtests/876834.html b/content/media/test/crashtests/876834.html index cf8d35b7ad3d..f4ca6ee558ad 100644 --- a/content/media/test/crashtests/876834.html +++ b/content/media/test/crashtests/876834.html @@ -1,4 +1,4 @@ diff --git a/content/media/test/crashtests/894104.html b/content/media/test/crashtests/894104.html index cb2429ae26a4..d021994e745f 100644 --- a/content/media/test/crashtests/894104.html +++ b/content/media/test/crashtests/894104.html @@ -10,7 +10,7 @@ function boom() var frameWin = frame.contentWindow; frameWin.VTTCue; document.body.removeChild(frame); - frameWin.VTTCue(0, 1, "Bug 894104").getCueAsHTML(); + new frameWin.VTTCue(0, 1, "Bug 894104").getCueAsHTML(); } diff --git a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul index a77a43281b34..04989e99b68e 100644 --- a/dom/tests/mochitest/chrome/test_sandbox_bindings.xul +++ b/dom/tests/mochitest/chrome/test_sandbox_bindings.xul @@ -108,13 +108,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267 } try { var xhr = Components.utils.evalInSandbox("new XMLHttpRequest()", sandbox); - is("" + xhr, "[object XrayWrapper " + XMLHttpRequest() + "]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object"); + is("" + xhr, "[object XrayWrapper " + new XMLHttpRequest() + "]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object"); } catch (e) { ok(false, "'new XMLHttpRequest()' shouldn't throw in a sandbox (1)"); } try { var xhr = Components.utils.evalInSandbox("XMLHttpRequest.prototype.toString = function () { return 'Failed'; }; new XMLHttpRequest();", sandbox); - is(xhr.toString(), "[object XrayWrapper " + XMLHttpRequest() + "]", "XMLHttpRequest.prototype.toString in the sandbox should not override the native toString behaviour"); + is(xhr.toString(), "[object XrayWrapper " + new XMLHttpRequest() + "]", "XMLHttpRequest.prototype.toString in the sandbox should not override the native toString behaviour"); } catch (e) { ok(false, "'new XMLHttpRequest()' shouldn't throw in a sandbox (2)"); } @@ -139,8 +139,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=741267 try { Components.utils.evalInSandbox("document.defaultView.XMLHttpRequest = function() {};", sandbox); var win = Components.utils.evalInSandbox("document.defaultView", sandbox); - var xhr = win.XMLHttpRequest(); - is("" + xhr, "[object XrayWrapper " + XMLHttpRequest() + "]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object"); + var xhr = new win.XMLHttpRequest(); + is("" + xhr, "[object XrayWrapper " + new XMLHttpRequest() + "]", "'XMLHttpRequest()' in a sandbox should create an XMLHttpRequest object"); } catch (e) { ok(false, "'XMLHttpRequest()' shouldn't throw in a sandbox"); } diff --git a/dom/tests/mochitest/chrome/test_xray_event_constructor.xul b/dom/tests/mochitest/chrome/test_xray_event_constructor.xul index f60dc3be95a6..9e18374eee59 100644 --- a/dom/tests/mochitest/chrome/test_xray_event_constructor.xul +++ b/dom/tests/mochitest/chrome/test_xray_event_constructor.xul @@ -25,7 +25,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=861493 addLoadEvent(function() { ok(Components.utils.isXrayWrapper($("t").contentWindow), "Should have xray"); - var e = new $("t").contentWindow.Event("test", { bubbles: true }); + var e = new ($("t").contentWindow).Event("test", { bubbles: true }); is(e.bubbles, true, "Dictionary should have worked"); SimpleTest.finish(); }) diff --git a/dom/xbl/test/file_bug821850.xhtml b/dom/xbl/test/file_bug821850.xhtml index 52e6bfbe0435..08440b7ab9b6 100644 --- a/dom/xbl/test/file_bug821850.xhtml +++ b/dom/xbl/test/file_bug821850.xhtml @@ -224,10 +224,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=821850 window.triggeredTrustedHandler = false; var untrustedEvent = new CustomEvent('testtrusted'); ok(!untrustedEvent.isTrusted, "Created an untrusted event"); + is(untrustedEvent.type, 'testtrusted', "Constructor should see type"); bound.dispatchEvent(untrustedEvent); ok(!window.triggeredTrustedHandler, "untrusted events should not trigger trusted handler"); var trustedEvent = new chromeWin.CustomEvent('testtrusted'); ok(trustedEvent.isTrusted, "Created a trusted event"); + is(trustedEvent.type, 'testtrusted', "Wrapped constructor should see type"); SpecialPowers.wrap(bound).dispatchEvent(trustedEvent); ok(window.triggeredTrustedHandler, "trusted events should trigger trusted handler"); diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 8ddc88e49d3a..7050a436118e 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -126,24 +126,13 @@ function wrapPrivileged(obj) { // The arguments may or may not be wrappers. Unwrap them if necessary. var unwrappedArgs = Array.prototype.slice.call(arguments).map(unwrapIfWrapped); - // Constructors are tricky, because we can't easily call apply on them. - // As a workaround, we create a wrapper constructor with the same - // |prototype| property. ES semantics dictate that the return value from - // |new| is the return value of the |new|-ed function i.f.f. the returned - // value is an object. We can thus mimic the behavior of |new|-ing the - // underlying constructor just be passing along its return value in our - // constructor. - var FakeConstructor = function() { - try { - return doApply(obj, this, unwrappedArgs); - } catch (e) { - // Wrap exceptions and re-throw them. - throw wrapIfUnwrapped(e); - } - }; - FakeConstructor.prototype = obj.prototype; - - return wrapPrivileged(new FakeConstructor()); + // We want to invoke "obj" as a constructor, but using unwrappedArgs as + // the arguments. Make sure to wrap and re-throw exceptions! + try { + return wrapPrivileged(new obj(...unwrappedArgs)); + } catch (e) { + throw wrapIfUnwrapped(e); + } }; return Proxy.createFunction(handler, callTrap, constructTrap); diff --git a/toolkit/content/aboutTelemetry.js b/toolkit/content/aboutTelemetry.js index 3bbe29873eae..20c0b001a34d 100644 --- a/toolkit/content/aboutTelemetry.js +++ b/toolkit/content/aboutTelemetry.js @@ -378,7 +378,7 @@ function SymbolicationRequest_fetchSymbols() { "version" : 3}; let requestJSON = JSON.stringify(request); - this.symbolRequest = XMLHttpRequest(); + this.symbolRequest = new XMLHttpRequest(); this.symbolRequest.open("POST", symbolServerURI, true); this.symbolRequest.setRequestHeader("Content-type", "application/json"); this.symbolRequest.setRequestHeader("Content-length", diff --git a/toolkit/devtools/server/actors/highlighter.js b/toolkit/devtools/server/actors/highlighter.js index aa326a65c11d..b28b1561c3d7 100644 --- a/toolkit/devtools/server/actors/highlighter.js +++ b/toolkit/devtools/server/actors/highlighter.js @@ -411,7 +411,7 @@ BoxModelHighlighter.prototype = { _trackMutations: function() { if (this.currentNode) { let win = this.currentNode.ownerDocument.defaultView; - this.currentNodeObserver = win.MutationObserver(this._update); + this.currentNodeObserver = new win.MutationObserver(this._update); this.currentNodeObserver.observe(this.currentNode, {attributes: true}); } }, diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js index 01628e6a44b5..bfc8f42ddb69 100644 --- a/toolkit/devtools/server/actors/inspector.js +++ b/toolkit/devtools/server/actors/inspector.js @@ -983,7 +983,7 @@ var WalkerActor = protocol.ActorClass({ let node = actor.rawNode; // Create the observer on the node's actor. The node will make sure // the observer is cleaned up when the actor is released. - actor.observer = actor.rawNode.defaultView.MutationObserver(this.onMutations); + actor.observer = new actor.rawNode.defaultView.MutationObserver(this.onMutations); actor.observer.observe(node, { attributes: true, characterData: true, diff --git a/webapprt/Startup.jsm b/webapprt/Startup.jsm index 345f57e0d00f..384165804ec9 100644 --- a/webapprt/Startup.jsm +++ b/webapprt/Startup.jsm @@ -47,7 +47,7 @@ function isFirstRunOrUpdate() { function writeFile(aPath, aData) { return Task.spawn(function() { - let data = TextEncoder().encode(aData); + let data = new TextEncoder().encode(aData); yield OS.File.writeAtomic(aPath, data, { tmpPath: aPath + ".tmp" }); }); }