Commit f675db65 authored by ricow@chromium.org's avatar ricow@chromium.org

Change calls to undefined property setters to not throw (fixes issue 1355).

We currently throw when there is only a getter defined on the
property, but this should only be the case in strict mode.
Review URL: http://codereview.chromium.org/7064027

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8054 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2f36b163
...@@ -1771,7 +1771,8 @@ MaybeObject* JSObject::SetProperty(String* name, ...@@ -1771,7 +1771,8 @@ MaybeObject* JSObject::SetProperty(String* name,
MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
String* name, String* name,
Object* value, Object* value,
JSObject* holder) { JSObject* holder,
StrictModeFlag strict_mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -1819,6 +1820,9 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure, ...@@ -1819,6 +1820,9 @@ MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
if (setter->IsJSFunction()) { if (setter->IsJSFunction()) {
return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
} else { } else {
if (strict_mode == kNonStrictMode) {
return value;
}
Handle<String> key(name); Handle<String> key(name);
Handle<Object> holder_handle(holder, isolate); Handle<Object> holder_handle(holder, isolate);
Handle<Object> args[2] = { key, holder_handle }; Handle<Object> args[2] = { key, holder_handle };
...@@ -1876,9 +1880,11 @@ void JSObject::LookupCallbackSetterInPrototypes(String* name, ...@@ -1876,9 +1880,11 @@ void JSObject::LookupCallbackSetterInPrototypes(String* name,
} }
MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index, MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
Object* value, uint32_t index,
bool* found) { Object* value,
bool* found,
StrictModeFlag strict_mode) {
Heap* heap = GetHeap(); Heap* heap = GetHeap();
for (Object* pt = GetPrototype(); for (Object* pt = GetPrototype();
pt != heap->null_value(); pt != heap->null_value();
...@@ -1892,8 +1898,11 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index, ...@@ -1892,8 +1898,11 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
*found = true; *found = true;
return SetElementWithCallback( return SetElementWithCallback(dictionary->ValueAt(entry),
dictionary->ValueAt(entry), index, value, JSObject::cast(pt)); index,
value,
JSObject::cast(pt),
strict_mode);
} }
} }
} }
...@@ -2074,10 +2083,12 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name, ...@@ -2074,10 +2083,12 @@ void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
// We only need to deal with CALLBACKS and INTERCEPTORS // We only need to deal with CALLBACKS and INTERCEPTORS
MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
String* name, LookupResult* result,
Object* value, String* name,
bool check_prototype) { Object* value,
bool check_prototype,
StrictModeFlag strict_mode) {
if (check_prototype && !result->IsProperty()) { if (check_prototype && !result->IsProperty()) {
LookupCallbackSetterInPrototypes(name, result); LookupCallbackSetterInPrototypes(name, result);
} }
...@@ -2093,7 +2104,8 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, ...@@ -2093,7 +2104,8 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
return SetPropertyWithCallback(result->GetCallbackObject(), return SetPropertyWithCallback(result->GetCallbackObject(),
name, name,
value, value,
result->holder()); result->holder(),
strict_mode);
} }
} }
break; break;
...@@ -2104,8 +2116,11 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result, ...@@ -2104,8 +2116,11 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
LookupResult r; LookupResult r;
LookupRealNamedProperty(name, &r); LookupRealNamedProperty(name, &r);
if (r.IsProperty()) { if (r.IsProperty()) {
return SetPropertyWithFailedAccessCheck(&r, name, value, return SetPropertyWithFailedAccessCheck(&r,
check_prototype); name,
value,
check_prototype,
strict_mode);
} }
break; break;
} }
...@@ -2149,7 +2164,11 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, ...@@ -2149,7 +2164,11 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
// Check access rights if needed. // Check access rights if needed.
if (IsAccessCheckNeeded() if (IsAccessCheckNeeded()
&& !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(result, name, value, true); return SetPropertyWithFailedAccessCheck(result,
name,
value,
true,
strict_mode);
} }
if (IsJSGlobalProxy()) { if (IsJSGlobalProxy()) {
...@@ -2169,7 +2188,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, ...@@ -2169,7 +2188,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
return SetPropertyWithCallback(accessor_result.GetCallbackObject(), return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
name, name,
value, value,
accessor_result.holder()); accessor_result.holder(),
strict_mode);
} }
} }
if (!result->IsFound()) { if (!result->IsFound()) {
...@@ -2213,7 +2233,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result, ...@@ -2213,7 +2233,8 @@ MaybeObject* JSObject::SetProperty(LookupResult* result,
return SetPropertyWithCallback(result->GetCallbackObject(), return SetPropertyWithCallback(result->GetCallbackObject(),
name, name,
value, value,
result->holder()); result->holder(),
strict_mode);
case INTERCEPTOR: case INTERCEPTOR:
return SetPropertyWithInterceptor(name, value, attributes, strict_mode); return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
case CONSTANT_TRANSITION: { case CONSTANT_TRANSITION: {
...@@ -2266,7 +2287,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes( ...@@ -2266,7 +2287,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
if (IsAccessCheckNeeded()) { if (IsAccessCheckNeeded()) {
Heap* heap = GetHeap(); Heap* heap = GetHeap();
if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) { if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
return SetPropertyWithFailedAccessCheck(&result, name, value, false); return SetPropertyWithFailedAccessCheck(&result,
name,
value,
false,
kNonStrictMode);
} }
} }
...@@ -7406,7 +7431,8 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver, ...@@ -7406,7 +7431,8 @@ MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
MaybeObject* JSObject::SetElementWithCallback(Object* structure, MaybeObject* JSObject::SetElementWithCallback(Object* structure,
uint32_t index, uint32_t index,
Object* value, Object* value,
JSObject* holder) { JSObject* holder,
StrictModeFlag strict_mode) {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -7445,10 +7471,13 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure, ...@@ -7445,10 +7471,13 @@ MaybeObject* JSObject::SetElementWithCallback(Object* structure,
} }
if (structure->IsFixedArray()) { if (structure->IsFixedArray()) {
Object* setter = FixedArray::cast(structure)->get(kSetterIndex); Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
if (setter->IsJSFunction()) { if (setter->IsJSFunction()) {
return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
} else { } else {
if (strict_mode == kNonStrictMode) {
return value;
}
Handle<Object> holder_handle(holder, isolate); Handle<Object> holder_handle(holder, isolate);
Handle<Object> key(isolate->factory()->NewNumberFromUint(index)); Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Handle<Object> args[2] = { key, holder_handle }; Handle<Object> args[2] = { key, holder_handle };
...@@ -7482,8 +7511,10 @@ MaybeObject* JSObject::SetFastElement(uint32_t index, ...@@ -7482,8 +7511,10 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
if (check_prototype && if (check_prototype &&
(index >= elms_length || elms->get(index)->IsTheHole())) { (index >= elms_length || elms->get(index)->IsTheHole())) {
bool found; bool found;
MaybeObject* result = MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
SetElementWithCallbackSetterInPrototypes(index, value, &found); value,
&found,
strict_mode);
if (found) return result; if (found) return result;
} }
...@@ -7627,7 +7658,11 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, ...@@ -7627,7 +7658,11 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Object* element = dictionary->ValueAt(entry); Object* element = dictionary->ValueAt(entry);
PropertyDetails details = dictionary->DetailsAt(entry); PropertyDetails details = dictionary->DetailsAt(entry);
if (details.type() == CALLBACKS) { if (details.type() == CALLBACKS) {
return SetElementWithCallback(element, index, value, this); return SetElementWithCallback(element,
index,
value,
this,
strict_mode);
} else { } else {
dictionary->UpdateMaxNumberKey(index); dictionary->UpdateMaxNumberKey(index);
// If put fails instrict mode, throw exception. // If put fails instrict mode, throw exception.
...@@ -7647,7 +7682,10 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, ...@@ -7647,7 +7682,10 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
bool found; bool found;
MaybeObject* result = MaybeObject* result =
// Strict mode not needed. No-setter case already handled. // Strict mode not needed. No-setter case already handled.
SetElementWithCallbackSetterInPrototypes(index, value, &found); SetElementWithCallbackSetterInPrototypes(index,
value,
&found,
strict_mode);
if (found) return result; if (found) return result;
} }
// When we set the is_extensible flag to false we always force // When we set the is_extensible flag to false we always force
......
...@@ -1425,11 +1425,14 @@ class JSObject: public HeapObject { ...@@ -1425,11 +1425,14 @@ class JSObject: public HeapObject {
LookupResult* result, LookupResult* result,
String* name, String* name,
Object* value, Object* value,
bool check_prototype); bool check_prototype,
MUST_USE_RESULT MaybeObject* SetPropertyWithCallback(Object* structure, StrictModeFlag strict_mode);
String* name, MUST_USE_RESULT MaybeObject* SetPropertyWithCallback(
Object* value, Object* structure,
JSObject* holder); String* name,
Object* value,
JSObject* holder,
StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSFunction* setter, MUST_USE_RESULT MaybeObject* SetPropertyWithDefinedSetter(JSFunction* setter,
Object* value); Object* value);
MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor( MUST_USE_RESULT MaybeObject* SetPropertyWithInterceptor(
...@@ -1656,7 +1659,7 @@ class JSObject: public HeapObject { ...@@ -1656,7 +1659,7 @@ class JSObject: public HeapObject {
void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result); void LookupRealNamedPropertyInPrototypes(String* name, LookupResult* result);
void LookupCallbackSetterInPrototypes(String* name, LookupResult* result); void LookupCallbackSetterInPrototypes(String* name, LookupResult* result);
MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes( MUST_USE_RESULT MaybeObject* SetElementWithCallbackSetterInPrototypes(
uint32_t index, Object* value, bool* found); uint32_t index, Object* value, bool* found, StrictModeFlag strict_mode);
void LookupCallback(String* name, LookupResult* result); void LookupCallback(String* name, LookupResult* result);
// Returns the number of properties on this object filtering out properties // Returns the number of properties on this object filtering out properties
...@@ -1868,7 +1871,8 @@ class JSObject: public HeapObject { ...@@ -1868,7 +1871,8 @@ class JSObject: public HeapObject {
MaybeObject* SetElementWithCallback(Object* structure, MaybeObject* SetElementWithCallback(Object* structure,
uint32_t index, uint32_t index,
Object* value, Object* value,
JSObject* holder); JSObject* holder,
StrictModeFlag strict_mode);
MUST_USE_RESULT MaybeObject* SetElementWithInterceptor( MUST_USE_RESULT MaybeObject* SetElementWithInterceptor(
uint32_t index, uint32_t index,
Object* value, Object* value,
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Test that exceptions are thrown when setting properties on object // Test that exceptions are not thrown when setting properties on object
// that have only a getter in a prototype object. // that have only a getter in a prototype object, except when we are in strict
// mode where exceptsions should be thrown.
var o = {}; var o = {};
var p = {}; var p = {};
...@@ -34,25 +35,44 @@ p.__defineGetter__('x', function(){}); ...@@ -34,25 +35,44 @@ p.__defineGetter__('x', function(){});
p.__defineGetter__(0, function(){}); p.__defineGetter__(0, function(){});
o.__proto__ = p; o.__proto__ = p;
assertThrows("o.x = 42"); assertDoesNotThrow("o.x = 42");
assertThrows("o[0] = 42"); assertDoesNotThrow("o[0] = 42");
assertThrows(function() { 'use strict'; o.x = 42; });
assertThrows(function() { 'use strict'; o[0] = 42; });
function f() { function f() {
with(o) { with(o) {
x = 42; x = 42;
} }
} }
assertThrows("f()");
assertDoesNotThrow(f);
__proto__ = p; __proto__ = p;
function g() { function g() {
eval('1'); eval('1');
x = 42; x = 42;
} }
assertThrows("g()");
function g_strict() {
'use strict';
eval('1');
x = 42;
}
assertDoesNotThrow(g);
assertThrows(g_strict);
__proto__ = p; __proto__ = p;
function g2() { function g2() {
this[0] = 42; this[0] = 42;
} }
assertThrows("g2()");
function g2_strict() {
'use strict';
this[0] = 42;
}
assertDoesNotThrow(g2);
assertThrows(g2_strict);
...@@ -81,10 +81,11 @@ testArray(); ...@@ -81,10 +81,11 @@ testArray();
expected[0] = 111; expected[0] = 111;
testArray(); testArray();
// Using a setter where only a getter is defined throws an exception. // Using a setter where only a getter is defined does not throw an exception,
// unless we are in strict mode.
var q = {}; var q = {};
q.__defineGetter__('0', function() { return 42; }); q.__defineGetter__('0', function() { return 42; });
assertThrows('q[0] = 7'); assertDoesNotThrow('q[0] = 7');
// Using a getter where only a setter is defined returns undefined. // Using a getter where only a setter is defined returns undefined.
var q1 = {}; var q1 = {};
......
// Copyright 2011 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.
// Test that an exception is not thrown when trying to set a value for
// a property that has only a defined getter, except when in strict mode.
var foo = Object.defineProperty({}, "bar", {
get: function () {
return 10;
}
});
assertDoesNotThrow("foo.bar = 20");
function shouldThrow() {
'use strict';
foo.bar = 20;
}
assertThrows("shouldThrow()");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment