Commit 6af8ca5e authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

Fix type conversions in JSStackFrame accessors

We cannot assume that the receiver is a JSObject, nor can we assume
ToObject() completes successfully.

TBR=yangguo@chromium.org

Bug: chromium:739954
Change-Id: Id55571131ef8755e86f15cd2acb918ff0f1b7788
Reviewed-on: https://chromium-review.googlesource.com/632376Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47611}
parent f152f832
...@@ -341,11 +341,11 @@ Handle<Object> JSStackFrame::GetFunctionName() { ...@@ -341,11 +341,11 @@ Handle<Object> JSStackFrame::GetFunctionName() {
namespace { namespace {
bool CheckMethodName(Isolate* isolate, Handle<JSObject> obj, Handle<Name> name, bool CheckMethodName(Isolate* isolate, Handle<JSReceiver> receiver,
Handle<JSFunction> fun, Handle<Name> name, Handle<JSFunction> fun,
LookupIterator::Configuration config) { LookupIterator::Configuration config) {
LookupIterator iter = LookupIterator iter =
LookupIterator::PropertyOrElement(isolate, obj, name, config); LookupIterator::PropertyOrElement(isolate, receiver, name, config);
if (iter.state() == LookupIterator::DATA) { if (iter.state() == LookupIterator::DATA) {
return iter.GetDataValue().is_identical_to(fun); return iter.GetDataValue().is_identical_to(fun);
} else if (iter.state() == LookupIterator::ACCESSOR) { } else if (iter.state() == LookupIterator::ACCESSOR) {
...@@ -376,13 +376,14 @@ Handle<Object> JSStackFrame::GetMethodName() { ...@@ -376,13 +376,14 @@ Handle<Object> JSStackFrame::GetMethodName() {
return isolate_->factory()->null_value(); return isolate_->factory()->null_value();
} }
Handle<JSReceiver> receiver = Handle<JSReceiver> receiver;
Object::ToObject(isolate_, receiver_).ToHandleChecked(); if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
if (!receiver->IsJSObject()) { DCHECK(isolate_->has_pending_exception());
isolate_->clear_pending_exception();
isolate_->set_external_caught_exception(false);
return isolate_->factory()->null_value(); return isolate_->factory()->null_value();
} }
Handle<JSObject> obj = Handle<JSObject>::cast(receiver);
Handle<String> name(function_->shared()->name(), isolate_); Handle<String> name(function_->shared()->name(), isolate_);
// ES2015 gives getters and setters name prefixes which must // ES2015 gives getters and setters name prefixes which must
// be stripped to find the property name. // be stripped to find the property name.
...@@ -390,15 +391,15 @@ Handle<Object> JSStackFrame::GetMethodName() { ...@@ -390,15 +391,15 @@ Handle<Object> JSStackFrame::GetMethodName() {
name->IsUtf8EqualTo(CStrVector("set "), true)) { name->IsUtf8EqualTo(CStrVector("set "), true)) {
name = isolate_->factory()->NewProperSubString(name, 4, name->length()); name = isolate_->factory()->NewProperSubString(name, 4, name->length());
} }
if (CheckMethodName(isolate_, obj, name, function_, if (CheckMethodName(isolate_, receiver, name, function_,
LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) { LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) {
return name; return name;
} }
HandleScope outer_scope(isolate_); HandleScope outer_scope(isolate_);
Handle<Object> result; Handle<Object> result;
for (PrototypeIterator iter(isolate_, obj, kStartAtReceiver); !iter.IsAtEnd(); for (PrototypeIterator iter(isolate_, receiver, kStartAtReceiver);
iter.Advance()) { !iter.IsAtEnd(); iter.Advance()) {
Handle<Object> current = PrototypeIterator::GetCurrent(iter); Handle<Object> current = PrototypeIterator::GetCurrent(iter);
if (!current->IsJSObject()) break; if (!current->IsJSObject()) break;
Handle<JSObject> current_obj = Handle<JSObject>::cast(current); Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
...@@ -426,14 +427,21 @@ Handle<Object> JSStackFrame::GetTypeName() { ...@@ -426,14 +427,21 @@ Handle<Object> JSStackFrame::GetTypeName() {
// TODO(jgruber): Check for strict/constructor here as in // TODO(jgruber): Check for strict/constructor here as in
// CallSitePrototypeGetThis. // CallSitePrototypeGetThis.
if (receiver_->IsNullOrUndefined(isolate_)) if (receiver_->IsNullOrUndefined(isolate_)) {
return isolate_->factory()->null_value(); return isolate_->factory()->null_value();
} else if (receiver_->IsJSProxy()) {
return isolate_->factory()->Proxy_string();
}
if (receiver_->IsJSProxy()) return isolate_->factory()->Proxy_string(); Handle<JSReceiver> receiver;
if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
DCHECK(isolate_->has_pending_exception());
isolate_->clear_pending_exception();
isolate_->set_external_caught_exception(false);
return isolate_->factory()->null_value();
}
Handle<JSReceiver> receiver_object = return JSReceiver::GetConstructorName(receiver);
Object::ToObject(isolate_, receiver_).ToHandleChecked();
return JSReceiver::GetConstructorName(receiver_object);
} }
int JSStackFrame::GetLineNumber() { int JSStackFrame::GetLineNumber() {
...@@ -570,8 +578,10 @@ void AppendMethodCall(Isolate* isolate, JSStackFrame* call_site, ...@@ -570,8 +578,10 @@ void AppendMethodCall(Isolate* isolate, JSStackFrame* call_site,
} }
} }
} else { } else {
builder->AppendString(Handle<String>::cast(type_name)); if (IsNonEmptyString(type_name)) {
builder->AppendCharacter('.'); builder->AppendString(Handle<String>::cast(type_name));
builder->AppendCharacter('.');
}
if (IsNonEmptyString(method_name)) { if (IsNonEmptyString(method_name)) {
builder->AppendString(Handle<String>::cast(method_name)); builder->AppendString(Handle<String>::cast(method_name));
} else { } else {
......
...@@ -18,4 +18,5 @@ assertEquals("String", getTypeName("")); ...@@ -18,4 +18,5 @@ assertEquals("String", getTypeName(""));
assertEquals("Boolean", getTypeName(false)); assertEquals("Boolean", getTypeName(false));
assertEquals("Object", getTypeName({})); assertEquals("Object", getTypeName({}));
assertEquals("Array", getTypeName([])); assertEquals("Array", getTypeName([]));
assertEquals("Proxy", getTypeName(new Proxy({},{})));
assertEquals("Custom", getTypeName(new (function Custom(){})())); assertEquals("Custom", getTypeName(new (function Custom(){})()));
...@@ -24,3 +24,28 @@ try { ...@@ -24,3 +24,28 @@ try {
assertEquals("k", frames[4].getMethodName()); assertEquals("k", frames[4].getMethodName());
assertEquals(null, frames[5].getMethodName()); assertEquals(null, frames[5].getMethodName());
} }
function testMethodName(f, frameNumber, expectedName) {
try {
Error.prepareStackTrace = function(e, frames) { return frames; }
f();
assertUnreachable();
} catch (e) {
const frame = e.stack[frameNumber];
assertEquals(expectedName, frame.getMethodName());
} finally {
Error.prepareStackTrace = undefined;
}
}
const thrower = { valueOf: () => { throw new Error(); }};
{
const str = "";
testMethodName(() => { str.indexOf(str, thrower); }, 1, "indexOf");
}
{
const nr = 42;
testMethodName(() => { nr.toString(thrower); }, 1, "toString");
}
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