The Invariants of the Essential Methods are false in case of reentrancy

Tom Van Cutsem at
Thu Aug 11 11:14:59 UTC 2016

I don't think it's too worrisome because of the following reasoning:

Any code prior to the first invocation of obj.x (let's call this the "outer
code") will have observed the property as configurable & writable, so
having obj.x evaluate to 1 is a valid outcome.

Any code that runs synchronously between the call to Object.defineProperty
and the `return 1` statement (let's call this the "inner code"), will
consistently observe obj.x as non-configurable,non-writable and will always
read 2.

A worrisome scenario would be when the inner code computes results based on
the new value of x that are also accessible to the outer code, and the
outer code somehow expects that value to be consistent with the old value
of x. However, it's unclear that this bug is really due to the violation of
an ES invariant.

I'm not sure if proxies would amplify the problem. Actually, the invariant
assertions in the Proxy internal methods were designed precisely to avoid
such bugs, which is why all the assertions trigger when the trap has
finished executing and the proxy can no longer influence the outcome of the
intercepted operation. The bug described above would be avoided if the
internal methods of Ordinary ES objects would apply the same kind of
invariant checks as proxies do, checking the result of the [[Get]]
operation with the property's current attribute state. However, I suspect
that would probably be a bridge too far in terms of cost vs payoff.


2016-08-10 17:51 GMT+02:00 Claude Pache <claude.pache at>:

> Test case:
> ```js
> var results = []
> var observe = function (method, object, ...args) {
>     results.push({
>         method: method
>       , object: object
>       , args: args
>       , output: Reflect[method](object, ...args)
>     })
> }
> var obj = { get x() {
>     Object.defineProperty(this, 'x', { value: 2, configurable: false,
> writable: false })
>     observe('getOwnPropertyDescriptor', this, 'x')
>     return 1
> } }
> observe('get', obj, 'x')
> results[0]
> // { method: "getOwnPropertyDescriptor", object: obj, args: [ "x" ],
> output: { value: 2, writable: false, enumerable: true, configurable: false
> } }
> // `obj` is observed to have a nonconfigurable, nonwritable property "x"
> with value `2`.
> results[1] // { method: "get", object: obj, args: [ "x" ], output: 1 }
> // Then, `obj.[[Get]]("x") is observed to return `1`.
> ```
> Not sure if it is worrisome. What is sure, the situation could become
> worse with fanciful proxies.
> ―Claude
> _______________________________________________
> es-discuss mailing list
> es-discuss at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list