Reviewers: rossberg,

Message:
PTAL. Let me know if you'd like to see a helper for computing is_observed for
these cases which takes the object and key value.

Description:
Prevent changes to hidden properties from being observable via Object.observe

This addresses the leak that mstarzinger points out
(https://codereview.chromium.org/26390003/) and includes the test.

Note that this adds a test that observing changes to the empty-string property
remains possible.

BUG=

Please review this at https://codereview.chromium.org/26592012/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files (+46, -7 lines):
  M src/objects.cc
  M test/cctest/test-object-observe.cc
  M test/mjsunit/harmony/object-observe.js


Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 4aef8088860f275126fd9eb2ea7c5365635016fe..2f84975d6fa77d9ecf1e3f0aa9aaa9378027f24f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2137,7 +2137,9 @@ Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
     AddSlowProperty(object, name, value, attributes);
   }

-  if (FLAG_harmony_observation && object->map()->is_observed()) {
+  if (FLAG_harmony_observation &&
+      object->map()->is_observed() &&
+      *name != isolate->heap()->hidden_string()) {
     Handle<Object> old_value = isolate->factory()->the_hole_value();
     EnqueueChangeRecord(object, "new", name, old_value);
   }
@@ -4015,8 +4017,10 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
   }

   Handle<Object> old_value = isolate->factory()->the_hole_value();
-  if (FLAG_harmony_observation &&
-      object->map()->is_observed() && lookup->IsDataProperty()) {
+  bool is_observed = FLAG_harmony_observation &&
+                     object->map()->is_observed() &&
+                     *name != isolate->heap()->hidden_string();
+  if (is_observed && lookup->IsDataProperty()) {
     old_value = Object::GetProperty(object, name);
   }

@@ -4055,7 +4059,7 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,

   RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());

-  if (FLAG_harmony_observation && object->map()->is_observed()) {
+  if (is_observed) {
     if (lookup->IsTransition()) {
       EnqueueChangeRecord(object, "new", name, old_value);
     } else {
@@ -4156,7 +4160,9 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(

   Handle<Object> old_value = isolate->factory()->the_hole_value();
   PropertyAttributes old_attributes = ABSENT;
- bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
+  bool is_observed = FLAG_harmony_observation &&
+                     object->map()->is_observed() &&
+                     *name != isolate->heap()->hidden_string();
   if (is_observed && lookup.IsProperty()) {
     if (lookup.IsDataProperty()) old_value =
         Object::GetProperty(object, name);
@@ -5220,7 +5226,9 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
   }

   Handle<Object> old_value = isolate->factory()->the_hole_value();
- bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
+  bool is_observed = FLAG_harmony_observation &&
+                     object->map()->is_observed() &&
+                     *name != isolate->heap()->hidden_string();
   if (is_observed && lookup.IsDataProperty()) {
     old_value = Object::GetProperty(object, name);
   }
@@ -6292,7 +6300,9 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
   bool is_element = name->AsArrayIndex(&index);

   Handle<Object> old_value = isolate->factory()->the_hole_value();
- bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
+  bool is_observed = FLAG_harmony_observation &&
+                     object->map()->is_observed() &&
+                     *name != isolate->heap()->hidden_string();
   bool preexists = false;
   if (is_observed) {
     if (is_element) {
Index: test/cctest/test-object-observe.cc
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc index a9f840e7adc7f0d0b48ed3a600baed1698ce64b2..b4488a603a981a9e420abda0fc00f66e28c4b4de 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -720,3 +720,18 @@ TEST(AccessCheckDisallowApiModifications) {
   }
   CHECK(CompileRun("records")->IsNull());
 }
+
+
+TEST(HiddenPropertiesLeakage) {
+  HarmonyIsolate isolate;
+  HandleScope scope(isolate.GetIsolate());
+  LocalContext context(isolate.GetIsolate());
+  CompileRun("var obj = {};"
+             "var records = null;"
+             "var observer = function(r) { records = r };"
+             "Object.observe(obj, observer);");
+  Handle<Value> obj = context->Global()->Get(String::New("obj"));
+  Handle<Object>::Cast(obj)->SetHiddenValue(String::New("foo"), Null());
+  CompileRun("");  // trigger delivery
+  CHECK(CompileRun("records")->IsNull());
+}
Index: test/mjsunit/harmony/object-observe.js
diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js index f982a66bc428227d2aaf3fb2ae24dc30fc0bcfaf..f94ab75e9a84d2cf0d819510782b23a660057bcc 100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -286,6 +286,20 @@ observer.assertCallbackRecords([
   { object: obj, type: 'new', name: 'id' },
 ]);

+// The empty-string property is observable
+reset();
+var obj = {};
+Object.observe(obj, observer.callback);
+obj[''] = '';
+obj[''] = ' ';
+delete obj[''];
+Object.deliverChangeRecords(observer.callback);
+observer.assertCallbackRecords([
+  { object: obj, type: 'new', name: '' },
+  { object: obj, type: 'updated', name: '', oldValue: '' },
+  { object: obj, type: 'deleted', name: '', oldValue: ' ' },
+]);
+
// Observing a continuous stream of changes, while itermittantly unobserving.
 reset();
 Object.observe(obj, observer.callback);


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to