Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automatic unwrapping #16

Closed
metamatt opened this issue Jun 25, 2013 · 5 comments · Fixed by #17
Closed

automatic unwrapping #16

metamatt opened this issue Jun 25, 2013 · 5 comments · Fixed by #17

Comments

@metamatt
Copy link
Contributor

I believe this behavior was introduced in harmony-reflect v0.0.5 while fixing #13.

The auto-unwrapping assumes Object.prototype.toString will only be called on objects. But lots of code calls it on other types to figure out what type they're dealing with.

Here's what one would normally expect for this behavior:

magi@ubuntu ~/s/d/foo> node --harmony
> ({}).toString.apply(1)
'[object Number]'
> ({}).toString.apply(true)
'[object Boolean]'
> ({}).toString.apply('asdf')
'[object String]'
> ({}).toString.apply(null)
'[object Null]'
> ({}).toString.apply(undefined)
'[object Undefined]'
> ({}).toString.apply([])
'[object Array]'
> ({}).toString.apply({})
'[object Object]'

Here's what you get with harmony-proxies v0.0.5:

magi@ubuntu ~/s/d/foo> node --harmony
> require('harmony-reflect')
{ snip }
> ({}).toString.apply(1)
TypeError: Invalid value used as weak map key
    at WeakMap.get (native)
    at Number.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
    at repl:1:16
> ({}).toString.apply(true)
TypeError: Invalid value used as weak map key
    at WeakMap.get (native)
    at Boolean.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
    at repl:1:16
> ({}).toString.apply('asdf')
TypeError: Invalid value used as weak map key
    at WeakMap.get (native)
    at String.builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
    at repl:1:16
> ({}).toString.apply(null)
TypeError: Invalid value used as weak map key
    at WeakMap.get (native)
    at builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
    at repl:1:16
> ({}).toString.apply(undefined)
TypeError: Invalid value used as weak map key
    at WeakMap.get (native)
    at builtin (/home/magi/node_modules/harmony-reflect/reflect.js:1500:34)
    at repl:1:16
> ({}).toString.apply([])
'[object Array]'
> ({}).toString.apply({})
'[object Object]'
@metamatt
Copy link
Contributor Author

The offending call to WeakMap.get is here

function makeUnwrapping0ArgMethod(primitive) {
  return function builtin() {
    var vHandler = directProxies.get(this);
    if (vHandler !== undefined) {
      return builtin.call(vHandler.target);
    } else {
      return primitive.call(this);
    }
  }
};

But there are a number of other identical var vHandler = directProxies.get(this); instances that are also reachable with this not being an object (Array.isArray, and Object.prototype.isPrototypeOf exposes makeUnwrapping1ArgMethod).

So I suggest a patch something like

-    var vHandler = directProxies.get(this);
+    var vHandler;
+    if (typeof this === 'object' && this !== null) {
+      vHandler = directProxies.get(this);
+    }

at each of those call sites, though perhaps you have a better way of specifying that test.

I'll send a PR which you are free to accept or improve upon.

@ghost
Copy link

ghost commented Jun 25, 2013

You'll need to account for functions, since this is also used on Function.prototype.toString. Something like:

function isObject(o){
  var type = typeof o;
  return type === 'object' ? o !== null : type === 'function';
}

@metamatt
Copy link
Contributor Author

Thank you -- that's right.

I don't have a super deep background in Javascript, so I'll ask: is there a known way of nesting these checks in the right order for best performance, or is it ok (from a performance perspective) to just call WeakMap.get and let it figure out what's an object and throw errors which we catch, like:

try {
   vHandler = directProxies.get(this);
} catch (err) {
   vHandler = undefined;
}

metamatt added a commit to metamatt/harmony-reflect that referenced this issue Jun 25, 2013
before invoking WeakMap.get().

Fixes tvcutsem#16.

Tests run (and passed) under node v0.10 with --harmony:
  test/testHandlers.js
  test/testReflect.js
  test/testRegression.js
tvcutsem pushed a commit that referenced this issue Jun 26, 2013
Fix #16: don't pass primitives to WeakMap.get
tvcutsem pushed a commit that referenced this issue Jun 26, 2013
tvcutsem pushed a commit that referenced this issue Jun 26, 2013
@tvcutsem
Copy link
Owner

@metamatt thanks for the PR. Couldn't have done it better myself. I merged it, added unit tests to testRegression.js and updated the NPM package.

@metamatt
Copy link
Contributor Author

Thanks Tom!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants