Bug 161111 - toString called on proxies returns incorrect tag
Summary: toString called on proxies returns incorrect tag
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: WebKit Nightly Build
Hardware: Macintosh OS X 10.11
: P2 Normal
Assignee: Keith Miller
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-08-23 15:40 PDT by Alexey Shvayka
Modified: 2019-06-23 15:38 PDT (History)
8 users (show)

See Also:


Attachments
Patch (14.19 KB, patch)
2016-08-25 15:55 PDT, Keith Miller
no flags Details | Formatted Diff | Diff
Patch (13.90 KB, patch)
2016-08-25 16:28 PDT, Keith Miller
benjamin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alexey Shvayka 2016-08-23 15:40:50 PDT
When `Object.prototype.toString` is called on proxy objects with target that has no `@@toStringTag` defined,
it returns `ProxyObject` instead of correct tag:

```js
toString.call(new Proxy(new Map, {})) // [object Map], correct
toString.call(new Proxy(Math, {})) // [object Math], correct
toString.call(new Proxy({ [Symbol.toStringTag]: "Hello" }, {})) // [object Hello], correct

toString.call(new Proxy(new String, {})) // [object ProxyObject], incorrect
// should report [object Object], because proxy is not String exotic object

toString.call(new Proxy(/(?:)/, {})) // [object ProxyObject], incorrect
// should report [object Object], because proxy object does not have [[RegExpMatcher]]

toString.call(new Proxy([], {})) // [object ProxyObject], incorrect
// should report [object Array], because isArray when called on proxy, checks
// its target for arrayness (internal methods)

toString.call(new Proxy(() => {}, {})) // [object ProxyObject], incorrect
// should report [object Function], because toString checks for [[Call]] and
// Proxy constructor creates [[Call]] on proxy if it is present on target

toString.call(new Proxy({}, {})) // [object ProxyObject], incorrect
// should report [object Object]
```
Comment 1 Keith Miller 2016-08-24 09:53:47 PDT
Interesting, this happens because the className for Proxies is ProxyObject rather than Object. Joe, does the WebInspector use the className of Proxy objects for inspectoring?
Comment 2 Joseph Pecoraro 2016-08-24 10:54:57 PDT
(In reply to comment #1)
> Interesting, this happens because the className for Proxies is ProxyObject
> rather than Object. Joe, does the WebInspector use the className of Proxy
> objects for inspectoring?

No, Web Inspector doesn't rely on it for anything.

Currently, Web Inspector just internally checks if an object is a ProxyObject in JSInjectedScriptHost so that we can add internal properties [[Target]], [[Handler]].

It just so happens that we expose ProxyObject when logging an object that is a proxy:

  > new Proxy({}, {})
  < ProxyObject {target: {}, handler: {}}

but again, we don't rely on that. We could easily denote proxies in some explicit way.
Comment 3 Keith Miller 2016-08-25 15:55:35 PDT
Created attachment 287037 [details]
Patch
Comment 4 Keith Miller 2016-08-25 16:28:58 PDT
Created attachment 287041 [details]
Patch
Comment 5 Joseph Pecoraro 2016-08-25 17:11:36 PDT
Comment on attachment 287041 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=287041&action=review

Looks good to me!

> Source/JavaScriptCore/ChangeLog:11
> +        In future patchs I plan to make it work for other classes of objects as

Typo: "patchs" => "patches"
Comment 6 Keith Miller 2016-08-26 10:07:11 PDT
Committed r205023: <http://trac.webkit.org/changeset/205023>
Comment 7 Alexey Shvayka 2016-08-30 05:35:28 PDT
I am testing in r205172, everything works per spec except for `toString` called on proxy with function target: `ProxyCreate` (https://tc39.github.io/ecma262/#sec-proxycreate) checks for `[[Call]]` on target (step 7a) and sets the method on proxy object if it exists. `toString` (https://tc39.github.io/ecma262/#sec-object.prototype.tostring) checks for `[[Call]]` in step 8 and should return `"[object Function]"` unless `@@toStringTag` is specified. Test cases:

```js
toString.call(new Proxy(() => {}, {})) // should return [object Function], not [object Object]
toString.call(new Proxy(function () {}, {})) // should return [object Function], not [object Object]
toString.call(new Proxy(function*() {}, {})) // [object GeneratorFunction], correct
```