Bugfix: internationalization routines fail on monkeypatching.
authormvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Apr 2014 07:36:12 +0000 (07:36 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Apr 2014 07:36:12 +0000 (07:36 +0000)
Calls to Object.defineProperty() and Object.apply() are not safe.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/253903003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21071 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/i18n.js
test/mjsunit/regress/regress-builtinbust-7.js [new file with mode: 0644]

index b251e29..5819d2c 100644 (file)
@@ -258,7 +258,7 @@ function addBoundMethod(obj, methodName, implementation, length) {
   %FunctionRemovePrototype(getter);
   %SetNativeFlag(getter);
 
-  $Object.defineProperty(obj.prototype, methodName, {
+  ObjectDefineProperty(obj.prototype, methodName, {
     get: getter,
     enumerable: false,
     configurable: true
@@ -593,15 +593,14 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
  */
 function freezeArray(array) {
   array.forEach(function(element, index) {
-    $Object.defineProperty(array, index, {value: element,
+    ObjectDefineProperty(array, index, {value: element,
                                           configurable: false,
                                           writable: false,
                                           enumerable: true});
   });
 
-  $Object.defineProperty(array, 'length', {value: array.length,
-                                           writable: false});
-
+  ObjectDefineProperty(array, 'length', {value: array.length,
+                                         writable: false});
   return array;
 }
 
@@ -662,8 +661,8 @@ function getAvailableLocalesOf(service) {
  * Configurable is false by default.
  */
 function defineWEProperty(object, property, value) {
-  $Object.defineProperty(object, property,
-                         {value: value, writable: true, enumerable: true});
+  ObjectDefineProperty(object, property,
+                       {value: value, writable: true, enumerable: true});
 }
 
 
@@ -682,11 +681,11 @@ function addWEPropertyIfDefined(object, property, value) {
  * Defines a property and sets writable, enumerable and configurable to true.
  */
 function defineWECProperty(object, property, value) {
-  $Object.defineProperty(object, property,
-                         {value: value,
-                          writable: true,
-                          enumerable: true,
-                          configurable: true});
+  ObjectDefineProperty(object, property,
+                       {value: value,
+                        writable: true,
+                        enumerable: true,
+                        configurable: true});
 }
 
 
@@ -925,8 +924,8 @@ function initializeCollator(collator, locales, options) {
   // We define all properties C++ code may produce, to prevent security
   // problems. If malicious user decides to redefine Object.prototype.locale
   // we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
-  // Object.defineProperties will either succeed defining or throw an error.
-  var resolved = $Object.defineProperties({}, {
+  // ObjectDefineProperties will either succeed defining or throw an error.
+  var resolved = ObjectDefineProperties({}, {
     caseFirst: {writable: true},
     collation: {value: internalOptions.collation, writable: true},
     ignorePunctuation: {writable: true},
@@ -944,7 +943,7 @@ function initializeCollator(collator, locales, options) {
 
   // Writable, configurable and enumerable are set to false by default.
   %MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
-  $Object.defineProperty(collator, 'resolved', {value: resolved});
+  ObjectDefineProperty(collator, 'resolved', {value: resolved});
 
   return collator;
 }
@@ -1141,7 +1140,7 @@ function initializeNumberFormat(numberFormat, locales, options) {
                              getOption, internalOptions);
 
   var requestedLocale = locale.locale + extension;
-  var resolved = $Object.defineProperties({}, {
+  var resolved = ObjectDefineProperties({}, {
     currency: {writable: true},
     currencyDisplay: {writable: true},
     locale: {writable: true},
@@ -1166,12 +1165,12 @@ function initializeNumberFormat(numberFormat, locales, options) {
   // We can't get information about number or currency style from ICU, so we
   // assume user request was fulfilled.
   if (internalOptions.style === 'currency') {
-    $Object.defineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
-                                                         writable: true});
+    ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
+                                                       writable: true});
   }
 
   %MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
-  $Object.defineProperty(numberFormat, 'resolved', {value: resolved});
+  ObjectDefineProperty(numberFormat, 'resolved', {value: resolved});
 
   return numberFormat;
 }
@@ -1443,13 +1442,11 @@ function appendToDateTimeObject(options, option, match, pairs) {
  */
 function toDateTimeOptions(options, required, defaults) {
   if (options === undefined) {
-    options = null;
+    options = {};
   } else {
-    options = toObject(options);
+    options = TO_OBJECT_INLINE(options);
   }
 
-  options = $Object.apply(this, [options]);
-
   var needsDefault = true;
   if ((required === 'date' || required === 'any') &&
       (options.weekday !== undefined || options.year !== undefined ||
@@ -1464,30 +1461,30 @@ function toDateTimeOptions(options, required, defaults) {
   }
 
   if (needsDefault && (defaults === 'date' || defaults === 'all')) {
-    $Object.defineProperty(options, 'year', {value: 'numeric',
-                                             writable: true,
-                                             enumerable: true,
-                                             configurable: true});
-    $Object.defineProperty(options, 'month', {value: 'numeric',
-                                              writable: true,
-                                              enumerable: true,
-                                              configurable: true});
-    $Object.defineProperty(options, 'day', {value: 'numeric',
+    ObjectDefineProperty(options, 'year', {value: 'numeric',
+                                           writable: true,
+                                           enumerable: true,
+                                           configurable: true});
+    ObjectDefineProperty(options, 'month', {value: 'numeric',
                                             writable: true,
                                             enumerable: true,
                                             configurable: true});
+    ObjectDefineProperty(options, 'day', {value: 'numeric',
+                                          writable: true,
+                                          enumerable: true,
+                                          configurable: true});
   }
 
   if (needsDefault && (defaults === 'time' || defaults === 'all')) {
-    $Object.defineProperty(options, 'hour', {value: 'numeric',
+    ObjectDefineProperty(options, 'hour', {value: 'numeric',
                                              writable: true,
                                              enumerable: true,
                                              configurable: true});
-    $Object.defineProperty(options, 'minute', {value: 'numeric',
+    ObjectDefineProperty(options, 'minute', {value: 'numeric',
                                                writable: true,
                                                enumerable: true,
                                                configurable: true});
-    $Object.defineProperty(options, 'second', {value: 'numeric',
+    ObjectDefineProperty(options, 'second', {value: 'numeric',
                                                writable: true,
                                                enumerable: true,
                                                configurable: true});
@@ -1538,7 +1535,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
                              getOption, internalOptions);
 
   var requestedLocale = locale.locale + extension;
-  var resolved = $Object.defineProperties({}, {
+  var resolved = ObjectDefineProperties({}, {
     calendar: {writable: true},
     day: {writable: true},
     era: {writable: true},
@@ -1566,7 +1563,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
   }
 
   %MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
-  $Object.defineProperty(dateFormat, 'resolved', {value: resolved});
+  ObjectDefineProperty(dateFormat, 'resolved', {value: resolved});
 
   return dateFormat;
 }
@@ -1760,7 +1757,7 @@ function initializeBreakIterator(iterator, locales, options) {
     'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
 
   var locale = resolveLocale('breakiterator', locales, options);
-  var resolved = $Object.defineProperties({}, {
+  var resolved = ObjectDefineProperties({}, {
     requestedLocale: {value: locale.locale, writable: true},
     type: {value: internalOptions.type, writable: true},
     locale: {writable: true}
@@ -1772,7 +1769,7 @@ function initializeBreakIterator(iterator, locales, options) {
 
   %MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
                                      internalIterator);
-  $Object.defineProperty(iterator, 'resolved', {value: resolved});
+  ObjectDefineProperty(iterator, 'resolved', {value: resolved});
 
   return iterator;
 }
@@ -1938,7 +1935,7 @@ function cachedOrNewService(service, locales, options, defaults) {
  * Compares this and that, and returns less than 0, 0 or greater than 0 value.
  * Overrides the built-in method.
  */
-$Object.defineProperty($String.prototype, 'localeCompare', {
+ObjectDefineProperty($String.prototype, 'localeCompare', {
   value: function(that) {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
@@ -1969,7 +1966,7 @@ $Object.defineProperty($String.prototype, 'localeCompare', {
  * If the form is not one of "NFC", "NFD", "NFKC", or "NFKD", then throw
  * a RangeError Exception.
  */
-$Object.defineProperty($String.prototype, 'normalize', {
+ObjectDefineProperty($String.prototype, 'normalize', {
   value: function(that) {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
@@ -2000,7 +1997,7 @@ $Object.defineProperty($String.prototype, 'normalize', {
  * Formats a Number object (this) using locale and options values.
  * If locale or options are omitted, defaults are used.
  */
-$Object.defineProperty($Number.prototype, 'toLocaleString', {
+ObjectDefineProperty($Number.prototype, 'toLocaleString', {
   value: function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
@@ -2050,7 +2047,7 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) {
  * If locale or options are omitted, defaults are used - both date and time are
  * present in the output.
  */
-$Object.defineProperty($Date.prototype, 'toLocaleString', {
+ObjectDefineProperty($Date.prototype, 'toLocaleString', {
   value: function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
@@ -2075,7 +2072,7 @@ $Object.defineProperty($Date.prototype, 'toLocaleString', {
  * If locale or options are omitted, defaults are used - only date is present
  * in the output.
  */
-$Object.defineProperty($Date.prototype, 'toLocaleDateString', {
+ObjectDefineProperty($Date.prototype, 'toLocaleDateString', {
   value: function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
@@ -2100,7 +2097,7 @@ $Object.defineProperty($Date.prototype, 'toLocaleDateString', {
  * If locale or options are omitted, defaults are used - only time is present
  * in the output.
  */
-$Object.defineProperty($Date.prototype, 'toLocaleTimeString', {
+ObjectDefineProperty($Date.prototype, 'toLocaleTimeString', {
   value: function() {
     if (%_IsConstructCall()) {
       throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
diff --git a/test/mjsunit/regress/regress-builtinbust-7.js b/test/mjsunit/regress/regress-builtinbust-7.js
new file mode 100644 (file)
index 0000000..7d883b8
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function overflow() {
+  return overflow() + 1;
+}
+Object.defineProperty = overflow;
+assertDoesNotThrow(function() { Intl.Collator.supportedLocalesOf("en"); });
+
+var date = new Date(Date.UTC(2004, 12, 25, 3, 0, 0));
+var options = {
+  weekday: "long",
+  year: "numeric",
+  month: "long",
+  day: "numeric"
+};
+
+Object.apply = overflow;
+assertDoesNotThrow(function() { date.toLocaleDateString("de-DE", options); });
+
+var options_incomplete = {};
+assertDoesNotThrow(function() {
+  date.toLocaleDateString("de-DE", options_incomplete);
+});
+assertTrue(options_incomplete.hasOwnProperty("year"));
+
+assertDoesNotThrow(function() { date.toLocaleDateString("de-DE", undefined); });
+assertDoesNotThrow(function() { date.toLocaleDateString("de-DE"); });
+assertThrows(function() { date.toLocaleDateString("de-DE", null); }, TypeError);