Store i18n meta data in hidden symbols instead of js accessible properties

There were some tests that are supposed to protect against js messing
with the meta data, however, they just didn't try hard enough.

BUG=354967
R=dcarney@chromium.org
LOG=y

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20375 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jochen@chromium.org 2014-04-01 07:21:05 +00:00
parent a403144159
commit 0d04cba759
8 changed files with 99 additions and 233 deletions

View File

@ -376,7 +376,9 @@ namespace internal {
V(next_string, "next") \
V(byte_length_string, "byteLength") \
V(byte_offset_string, "byteOffset") \
V(buffer_string, "buffer")
V(buffer_string, "buffer") \
V(intl_initialized_marker_string, "v8::intl_initialized_marker") \
V(intl_impl_object_string, "v8::intl_object")
// Forward declarations.
class GCTracer;

View File

@ -232,8 +232,7 @@ var ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR =
*/
function addBoundMethod(obj, methodName, implementation, length) {
function getter() {
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject === undefined) {
if (!%IsInitializedIntlObject(this)) {
throw new $TypeError('Method ' + methodName + ' called on a ' +
'non-object or on a wrong type of object.');
}
@ -896,7 +895,7 @@ function BuildLanguageTagREs() {
* Useful for subclassing.
*/
function initializeCollator(collator, locales, options) {
if (collator.hasOwnProperty('__initializedIntlObject')) {
if (%IsInitializedIntlObject(collator)) {
throw new $TypeError('Trying to re-initialize Collator object.');
}
@ -967,9 +966,7 @@ function initializeCollator(collator, locales, options) {
resolved);
// Writable, configurable and enumerable are set to false by default.
$Object.defineProperty(collator, 'collator', {value: internalCollator});
$Object.defineProperty(collator, '__initializedIntlObject',
{value: 'collator'});
%MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
$Object.defineProperty(collator, 'resolved', {value: resolved});
return collator;
@ -1005,8 +1002,7 @@ function initializeCollator(collator, locales, options) {
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'collator') {
if (!%IsInitializedIntlObjectOfType(this, 'collator')) {
throw new $TypeError('resolvedOptions method called on a non-object ' +
'or on a object that is not Intl.Collator.');
}
@ -1063,7 +1059,8 @@ function initializeCollator(collator, locales, options) {
* the sort order, or x comes after y in the sort order, respectively.
*/
function compare(collator, x, y) {
return %InternalCompare(collator.collator, $String(x), $String(y));
return %InternalCompare(%GetImplFromInitializedIntlObject(collator),
$String(x), $String(y));
};
@ -1104,7 +1101,7 @@ function getNumberOption(options, property, min, max, fallback) {
* Useful for subclassing.
*/
function initializeNumberFormat(numberFormat, locales, options) {
if (numberFormat.hasOwnProperty('__initializedIntlObject')) {
if (%IsInitializedIntlObject(numberFormat)) {
throw new $TypeError('Trying to re-initialize NumberFormat object.');
}
@ -1196,10 +1193,8 @@ function initializeNumberFormat(numberFormat, locales, options) {
writable: true});
}
$Object.defineProperty(numberFormat, 'formatter', {value: formatter});
%MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
$Object.defineProperty(numberFormat, 'resolved', {value: resolved});
$Object.defineProperty(numberFormat, '__initializedIntlObject',
{value: 'numberformat'});
return numberFormat;
}
@ -1234,8 +1229,7 @@ function initializeNumberFormat(numberFormat, locales, options) {
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'numberformat') {
if (!%IsInitializedIntlObjectOfType(this, 'numberformat')) {
throw new $TypeError('resolvedOptions method called on a non-object' +
' or on a object that is not Intl.NumberFormat.');
}
@ -1309,7 +1303,8 @@ function formatNumber(formatter, value) {
// Spec treats -0 and +0 as 0.
var number = $Number(value) + 0;
return %InternalNumberFormat(formatter.formatter, number);
return %InternalNumberFormat(%GetImplFromInitializedIntlObject(formatter),
number);
}
@ -1317,7 +1312,8 @@ function formatNumber(formatter, value) {
* Returns a Number that represents string value that was passed in.
*/
function parseNumber(formatter, value) {
return %InternalNumberParse(formatter.formatter, $String(value));
return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter),
$String(value));
}
@ -1530,7 +1526,7 @@ function toDateTimeOptions(options, required, defaults) {
*/
function initializeDateTimeFormat(dateFormat, locales, options) {
if (dateFormat.hasOwnProperty('__initializedIntlObject')) {
if (%IsInitializedIntlObject(dateFormat)) {
throw new $TypeError('Trying to re-initialize DateTimeFormat object.');
}
@ -1592,10 +1588,8 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
throw new $RangeError('Unsupported time zone specified ' + tz);
}
$Object.defineProperty(dateFormat, 'formatter', {value: formatter});
%MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
$Object.defineProperty(dateFormat, 'resolved', {value: resolved});
$Object.defineProperty(dateFormat, '__initializedIntlObject',
{value: 'dateformat'});
return dateFormat;
}
@ -1630,8 +1624,7 @@ function initializeDateTimeFormat(dateFormat, locales, options) {
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'dateformat') {
if (!%IsInitializedIntlObjectOfType(this, 'dateformat')) {
throw new $TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.DateTimeFormat.');
}
@ -1713,7 +1706,8 @@ function formatDate(formatter, dateValue) {
throw new $RangeError('Provided date is not in valid range.');
}
return %InternalDateFormat(formatter.formatter, new $Date(dateMs));
return %InternalDateFormat(%GetImplFromInitializedIntlObject(formatter),
new $Date(dateMs));
}
@ -1724,7 +1718,8 @@ function formatDate(formatter, dateValue) {
* Returns undefined if date string cannot be parsed.
*/
function parseDate(formatter, value) {
return %InternalDateParse(formatter.formatter, $String(value));
return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter),
$String(value));
}
@ -1772,7 +1767,7 @@ function canonicalizeTimeZoneID(tzID) {
* Useful for subclassing.
*/
function initializeBreakIterator(iterator, locales, options) {
if (iterator.hasOwnProperty('__initializedIntlObject')) {
if (%IsInitializedIntlObject(iterator)) {
throw new $TypeError('Trying to re-initialize v8BreakIterator object.');
}
@ -1798,10 +1793,9 @@ function initializeBreakIterator(iterator, locales, options) {
internalOptions,
resolved);
$Object.defineProperty(iterator, 'iterator', {value: internalIterator});
%MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
internalIterator);
$Object.defineProperty(iterator, 'resolved', {value: resolved});
$Object.defineProperty(iterator, '__initializedIntlObject',
{value: 'breakiterator'});
return iterator;
}
@ -1836,8 +1830,7 @@ function initializeBreakIterator(iterator, locales, options) {
throw new $TypeError(ORDINARY_FUNCTION_CALLED_AS_CONSTRUCTOR);
}
if (!this || typeof this !== 'object' ||
this.__initializedIntlObject !== 'breakiterator') {
if (!%IsInitializedIntlObjectOfType(this, 'breakiterator')) {
throw new $TypeError('resolvedOptions method called on a non-object or ' +
'on a object that is not Intl.v8BreakIterator.');
}
@ -1884,7 +1877,8 @@ function initializeBreakIterator(iterator, locales, options) {
* gets discarded.
*/
function adoptText(iterator, text) {
%BreakIteratorAdoptText(iterator.iterator, $String(text));
%BreakIteratorAdoptText(%GetImplFromInitializedIntlObject(iterator),
$String(text));
}
@ -1892,7 +1886,7 @@ function adoptText(iterator, text) {
* Returns index of the first break in the string and moves current pointer.
*/
function first(iterator) {
return %BreakIteratorFirst(iterator.iterator);
return %BreakIteratorFirst(%GetImplFromInitializedIntlObject(iterator));
}
@ -1900,7 +1894,7 @@ function first(iterator) {
* Returns the index of the next break and moves the pointer.
*/
function next(iterator) {
return %BreakIteratorNext(iterator.iterator);
return %BreakIteratorNext(%GetImplFromInitializedIntlObject(iterator));
}
@ -1908,7 +1902,7 @@ function next(iterator) {
* Returns index of the current break.
*/
function current(iterator) {
return %BreakIteratorCurrent(iterator.iterator);
return %BreakIteratorCurrent(%GetImplFromInitializedIntlObject(iterator));
}
@ -1916,7 +1910,7 @@ function current(iterator) {
* Returns type of the current break.
*/
function breakType(iterator) {
return %BreakIteratorBreakType(iterator.iterator);
return %BreakIteratorBreakType(%GetImplFromInitializedIntlObject(iterator));
}

View File

@ -13899,6 +13899,68 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLanguageTagVariants) {
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInitializedIntlObject) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
Handle<Object> tag(input->GetHiddenProperty(*marker), isolate);
return isolate->heap()->ToBoolean(!tag->IsTheHole());
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInitializedIntlObjectOfType) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
CONVERT_ARG_HANDLE_CHECKED(String, expected_type, 1);
Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
Handle<Object> tag(input->GetHiddenProperty(*marker), isolate);
return isolate->heap()->ToBoolean(
tag->IsString() && String::cast(*tag)->Equals(*expected_type));
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_MarkAsInitializedIntlObjectOfType) {
HandleScope scope(isolate);
ASSERT(args.length() == 3);
CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, impl, 2);
Handle<String> marker = isolate->factory()->intl_initialized_marker_string();
JSObject::SetHiddenProperty(input, marker, type);
marker = isolate->factory()->intl_impl_object_string();
JSObject::SetHiddenProperty(input, marker, impl);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetImplFromInitializedIntlObject) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, input, 0);
Handle<String> marker = isolate->factory()->intl_impl_object_string();
Handle<Object> impl(input->GetHiddenProperty(*marker), isolate);
if (impl->IsTheHole()) return isolate->heap()->undefined_value();
return *impl;
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateDateTimeFormat) {
HandleScope scope(isolate);

View File

@ -491,6 +491,10 @@ namespace internal {
F(AvailableLocalesOf, 1, 1) \
F(GetDefaultICULocale, 0, 1) \
F(GetLanguageTagVariants, 1, 1) \
F(IsInitializedIntlObject, 1, 1) \
F(IsInitializedIntlObjectOfType, 2, 1) \
F(MarkAsInitializedIntlObjectOfType, 3, 1) \
F(GetImplFromInitializedIntlObject, 1, 1) \
\
/* Date format and parse. */ \
F(CreateDateTimeFormat, 3, 1) \

View File

@ -1,49 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Internal object we got from native code should not be writable,
// configurable or enumerable. One can still change its public properties, but
// we don't use them to do actual work.
var iterator = new Intl.v8BreakIterator([]);
// Direct write should fail.
iterator.iterator = {'zzz':'some random object'};
assertFalse(iterator.iterator.hasOwnProperty('zzz'));
// Try redefining the property.
var didThrow = false;
try {
Object.defineProperty(iterator, 'iterator', {value: undefined});
} catch(e) {
didThrow = true;
}
assertTrue(didThrow);
// Try deleting the property.
assertFalse(delete iterator.iterator);

View File

@ -1,49 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Internal object we got from native code should not be writable,
// configurable or enumerable. One can still change its public properties, but
// we don't use them to do actual work.
var collator = new Intl.Collator([]);
// Direct write should fail.
collator.collator = {'zzz':'some random object'};
assertFalse(collator.collator.hasOwnProperty('zzz'));
// Try redefining the property.
var didThrow = false;
try {
Object.defineProperty(collator, 'collator', {value: undefined});
} catch(e) {
didThrow = true;
}
assertTrue(didThrow);
// Try deleting the property.
assertFalse(delete collator.collator);

View File

@ -1,49 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Internal object we got from native code should not be writable,
// configurable or enumerable. One can still change its public properties, but
// we don't use them to do actual work.
var format = new Intl.DateTimeFormat([]);
// Direct write should fail.
format.formatter = {'zzz':'some random object'};
assertFalse(format.formatter.hasOwnProperty('zzz'));
// Try redefining the property.
var didThrow = false;
try {
Object.defineProperty(format, 'formatter', {value: undefined});
} catch(e) {
didThrow = true;
}
assertTrue(didThrow);
// Try deleting the property.
assertFalse(delete format.formatter);

View File

@ -1,49 +0,0 @@
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Internal object we got from native code should not be writable,
// configurable or enumerable. One can still change its public properties, but
// we don't use them to do actual work.
var format = new Intl.NumberFormat([]);
// Direct write should fail.
format.formatter = {'zzz':'some random object'};
assertFalse(format.formatter.hasOwnProperty('zzz'));
// Try redefining the property.
var didThrow = false;
try {
Object.defineProperty(format, 'formatter', {value: undefined});
} catch(e) {
didThrow = true;
}
assertTrue(didThrow);
// Try deleting the property.
assertFalse(delete format.formatter);