From cd9660f77c185d905444d3406d8e0e46158e7dba Mon Sep 17 00:00:00 2001 From: "yurys@chromium.org" Date: Tue, 10 Nov 2009 16:13:21 +0000 Subject: [PATCH] All hidden properties of an object are stored in a value of a regular property with empty name. This property may confuse user if returned among regular properties. It should not be exposed directly by ObjectMirror. Should we want an access to these properties from debugger we need to implement an explicit method for that. Current patch filters the hidden_symbol from property names returned to ObjectMirror. See http://crbug.com/26491 Review URL: http://codereview.chromium.org/390001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/runtime.cc | 19 +++++++++++++ test/cctest/test-debug.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/runtime.cc b/src/runtime.cc index 46d641a..0658c44 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -6002,14 +6002,33 @@ static Object* Runtime_DebugLocalPropertyNames(Arguments args) { // Get the property names. jsproto = obj; + int proto_with_hidden_properties = 0; for (int i = 0; i < length; i++) { jsproto->GetLocalPropertyNames(*names, i == 0 ? 0 : local_property_count[i - 1]); + if (!GetHiddenProperties(jsproto, false)->IsUndefined()) { + proto_with_hidden_properties++; + } if (i < length - 1) { jsproto = Handle(JSObject::cast(jsproto->GetPrototype())); } } + // Filter out name of hidden propeties object. + if (proto_with_hidden_properties > 0) { + Handle old_names = names; + names = Factory::NewFixedArray( + names->length() - proto_with_hidden_properties); + int dest_pos = 0; + for (int i = 0; i < total_property_count; i++) { + Object* name = old_names->get(i); + if (name == Heap::hidden_symbol()) { + continue; + } + names->set(dest_pos++, name); + } + } + DeleteArray(local_property_count); return *Factory::NewJSArrayWithElements(names); } diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 7b2b91d..14f3974 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -3439,6 +3439,75 @@ TEST(NativeGetterThrowingErrorPropertyMirror) { } +// Test that hidden properties object is not returned as an unnamed property +// among regular properties. +// See http://crbug.com/26491 +TEST(NoHiddenProperties) { + // Create a V8 environment with debug access. + v8::HandleScope scope; + DebugLocalContext env; + env.ExposeDebug(); + + // Create an object in the global scope. + const char* source = "var obj = {a: 1};"; + v8::Script::Compile(v8::String::New(source))->Run(); + v8::Local obj = v8::Local::Cast( + env->Global()->Get(v8::String::New("obj"))); + // Set a hidden property on the object. + obj->SetHiddenValue(v8::String::New("v8::test-debug::a"), + v8::Int32::New(11)); + + // Get mirror for the object with property getter. + CompileRun("var obj_mirror = debug.MakeMirror(obj);"); + CHECK(CompileRun( + "obj_mirror instanceof debug.ObjectMirror")->BooleanValue()); + CompileRun("var named_names = obj_mirror.propertyNames();"); + // There should be exactly one property. But there is also an unnamed + // property whose value is hidden properties dictionary. The latter + // property should not be in the list of reguar properties. + CHECK_EQ(1, CompileRun("named_names.length")->Int32Value()); + CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue()); + CHECK(CompileRun( + "obj_mirror.property('a').value().value() == 1")->BooleanValue()); + + // Object created by t0 will become hidden prototype of object 'obj'. + v8::Handle t0 = v8::FunctionTemplate::New(); + t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2)); + t0->SetHiddenPrototype(true); + v8::Handle t1 = v8::FunctionTemplate::New(); + t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3)); + + // Create proto objects, add hidden properties to them and set them on + // the global object. + v8::Handle protoObj = t0->GetFunction()->NewInstance(); + protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"), + v8::Int32::New(12)); + env->Global()->Set(v8::String::New("protoObj"), protoObj); + v8::Handle grandProtoObj = t1->GetFunction()->NewInstance(); + grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"), + v8::Int32::New(13)); + env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj); + + // Setting prototypes: obj->protoObj->grandProtoObj + protoObj->Set(v8::String::New("__proto__"), grandProtoObj); + obj->Set(v8::String::New("__proto__"), protoObj); + + // Get mirror for the object with property getter. + CompileRun("var obj_mirror = debug.MakeMirror(obj);"); + CHECK(CompileRun( + "obj_mirror instanceof debug.ObjectMirror")->BooleanValue()); + CompileRun("var named_names = obj_mirror.propertyNames();"); + // There should be exactly two properties - one from the object itself and + // another from its hidden prototype. + CHECK_EQ(2, CompileRun("named_names.length")->Int32Value()); + CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&" + "named_names[1] == 'b'")->BooleanValue()); + CHECK(CompileRun( + "obj_mirror.property('a').value().value() == 1")->BooleanValue()); + CHECK(CompileRun( + "obj_mirror.property('b').value().value() == 2")->BooleanValue()); +} + // Multithreaded tests of JSON debugger protocol -- 2.7.4