From 4b36cd08d600af123afc733e425187c7fe95a32f Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Fri, 3 Dec 2010 12:15:06 -0600 Subject: [PATCH] Fix structured cloning deserialization bug that could create invalid Date objects. Bug 602806, r=gal. --- js/src/jsclone.cpp | 7 ++++- js/src/jsdate.cpp | 5 --- js/src/jsdate.h | 6 ++++ .../tests/js1_8_5/extensions/clone-forge.js | 31 +++++++++++++++++++ .../js1_8_5/extensions/clone-leaf-object.js | 7 ++++- js/src/tests/js1_8_5/extensions/jstests.list | 1 + 6 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 js/src/tests/js1_8_5/extensions/clone-forge.js diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index fdce3e16557..3b95404ec24 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -719,8 +719,13 @@ JSStructuredCloneReader::startRead(Value *vp) case SCTAG_DATE_OBJECT: { jsdouble d; - if (!in.readDouble(&d)) + if (!in.readDouble(&d) || !checkDouble(d)) return false; + if (d == d && d != TIMECLIP(d)) { + JS_ReportErrorNumber(context(), js_GetErrorMessage, NULL, JSMSG_SC_BAD_SERIALIZED_DATA, + "date"); + return false; + } JSObject *obj = js_NewDateObjectMsec(context(), d); if (!obj) return false; diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 3159cab1424..8b8b44449f6 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -152,7 +152,6 @@ using namespace js; * Supporting functions - ECMA 15.9.1.* */ -#define HalfTimeDomain 8.64e15 #define HoursPerDay 24.0 #define MinutesPerDay (HoursPerDay * MinutesPerHour) #define MinutesPerHour 60.0 @@ -482,10 +481,6 @@ msFromTime(jsdouble t) return result; } -#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ - && !((d < 0 ? -d : d) > HalfTimeDomain)) \ - ? js_DoubleToInteger(d + (+0.)) : js_NaN) - /** * end of ECMA 'support' functions */ diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 3c265b420cb..8dd7d783348 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -54,6 +54,12 @@ JSObject::isDate() const return getClass() == &js_DateClass; } +#define HalfTimeDomain 8.64e15 + +#define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ + && !((d < 0 ? -d : d) > HalfTimeDomain)) \ + ? js_DoubleToInteger(d + (+0.)) : js_NaN) + extern JSObject * js_InitDateClass(JSContext *cx, JSObject *obj); diff --git a/js/src/tests/js1_8_5/extensions/clone-forge.js b/js/src/tests/js1_8_5/extensions/clone-forge.js new file mode 100644 index 00000000000..a34501f1187 --- /dev/null +++ b/js/src/tests/js1_8_5/extensions/clone-forge.js @@ -0,0 +1,31 @@ +// -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/licenses/publicdomain/ + +function assertThrows(f) { + var ok = false; + try { + f(); + } catch (exc) { + ok = true; + } + if (!ok) + throw new TypeError("Assertion failed: " + f + " did not throw as expected"); +} + +// Don't allow forging bogus Date objects. +var buf = serialize(new Date(NaN)); +var a = [1/0, -1/0, + Number.MIN_VALUE, -Number.MIN_VALUE, + Math.PI, 1286523948674.5, + Number.MAX_VALUE, -Number.MAX_VALUE, + 8.64e15 + 1, -(8.64e15 + 1)]; +for (var i = 0; i < a.length; i++) { + var n = a[i]; + var nbuf = serialize(n); + for (var j = 0; j < 8; j++) + buf[j + 8] = nbuf[j]; + assertThrows(function () { deserialize(buf); }); +} + +reportCompare(0, 0); diff --git a/js/src/tests/js1_8_5/extensions/clone-leaf-object.js b/js/src/tests/js1_8_5/extensions/clone-leaf-object.js index 83a7bc4a080..9021b0d08a3 100644 --- a/js/src/tests/js1_8_5/extensions/clone-leaf-object.js +++ b/js/src/tests/js1_8_5/extensions/clone-leaf-object.js @@ -26,7 +26,6 @@ var a = [new Boolean(true), new String("\0123\u4567"), new Date(0), new Date(-0), - new Date(Math.PI), new Date(0x7fffffff), new Date(-0x7fffffff), new Date(0x80000000), @@ -40,9 +39,14 @@ var a = [new Boolean(true), new Date(-8.64e15), new Date(NaN)]; +function primitive(a) { + return a instanceof Date ? +a : a.constructor(a); +} + for (var i = 0; i < a.length; i++) { var x = a[i]; var expectedSource = x.toSource(); + var expectedPrimitive = primitive(x); var expectedProto = x.__proto__; var expectedString = Object.prototype.toString.call(x); x.expando = 1; @@ -50,6 +54,7 @@ for (var i = 0; i < a.length; i++) { var y = deserialize(serialize(x)); assertEq(y.toSource(), expectedSource); + assertEq(primitive(y), expectedPrimitive); assertEq(y.__proto__, expectedProto); assertEq(Object.prototype.toString.call(y), expectedString); assertEq("expando" in y, false); diff --git a/js/src/tests/js1_8_5/extensions/jstests.list b/js/src/tests/js1_8_5/extensions/jstests.list index 191c423cb7d..3cef2989f7e 100644 --- a/js/src/tests/js1_8_5/extensions/jstests.list +++ b/js/src/tests/js1_8_5/extensions/jstests.list @@ -22,4 +22,5 @@ skip-if(!xulRuntime.shell) script clone-leaf-object.js skip-if(!xulRuntime.shell) script clone-object.js skip-if(!xulRuntime.shell) script clone-typed-array.js skip-if(!xulRuntime.shell) script clone-errors.js +skip-if(!xulRuntime.shell) script clone-forge.js script set-property-non-extensible.js