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

Writing to deleted global variable references has been classified as a spec bug #427

Closed
bakkot opened this issue Aug 27, 2015 · 8 comments
Closed

Comments

@leobalter leobalter self-assigned this Mar 13, 2017
@leobalter
Copy link
Member

I need to investigate these cases, currently assigning this to myself.

@leobalter leobalter removed their assignment Jul 14, 2020
@leobalter
Copy link
Member

This definitely needs follow up. I shouldn't hold this one for too long.

@leobalter
Copy link
Member

I'm having trouble with this piece of code:

Object.defineProperty(this, "x", {
  configurable: true,
  get: function() {
    delete this.x;
    return 2;
  }
});

(function() {
  "use strict";
  ++x;
})();

Here comes the evaluation:

  Runtime Semantics: Evaluation

  UpdateExpression : ++ UnaryExpression

    Let expr be the result of evaluating UnaryExpression.
    Let oldValue be ? ToNumeric(? GetValue(expr)).
    Let newValue be ! Type(oldValue)::add(oldValue, Type(oldValue)::unit).
    Perform ? PutValue(expr, newValue).
    Return newValue.

  PutValue ( V, W )

    ...
    Let base be GetBase(V).
    If IsUnresolvableReference(V) is true, then
    ...

  IsUnresolvableReference ( V )

    Assert: Type(V) is Reference.
    If the base value component of V is undefined, return true; otherwise return false.

expr is the Reference for x in the base value of the Global Env Record, right?.

IIUC, the base value of expr is the Global Env Record.

The delete happens in the GetValue(expr), PutValue is then called with the expr Reference, and here comes a trick: IsUnresovableReference returns true becase the base value component of V is still the Global Env Record. Is that correct so far?


back to PutValue

  PutValue ( V, W )

    ...
    Let base be GetBase(V).
    If IsUnresolvableReference(V) is true, then
    ...
    Else if IsPropertyReference(V) is true, then
    ...
    Else,
      Assert: base is an Environment Record.
      Return ? base.SetMutableBinding(GetReferencedName(V), W, IsStrictReference(V)) (see 8.1).

So we reach the SetMutableBinding for global Env Records. (8.1.1.4.5)

SetMutableBinding ( N, V, S )

The concrete Environment Record method SetMutableBinding for global Environment Records attempts to change the bound value of the current binding of the identifier whose name is the value of the argument N to the value of argument V. If the binding is an immutable binding, a TypeError is thrown if S is true. A property named N normally already exists but if it does not or is not currently writable, error handling is determined by the value of the Boolean argument S.

    Let envRec be the global Environment Record for which the method was invoked.
    Let DclRec be envRec.[[DeclarativeRecord]].
    If DclRec.HasBinding(N) is true, then
        Return DclRec.SetMutableBinding(N, V, S).
    Let ObjRec be envRec.[[ObjectRecord]].
    Return ? ObjRec.SetMutableBinding(N, V, S).

Now the DeclarativeRecord wont have a binding X. So we would roll to ObjRec.SetMutableBinding.

SetMutableBinding ( N, V, S )

The concrete Environment Record method SetMutableBinding for object Environment Records attempts to set the value of the Environment Record's associated binding object's property whose name is the value of the argument N to the value of argument V. A property named N normally already exists but if it does not or is not currently writable, error handling is determined by the value of the Boolean argument S.

    Let envRec be the object Environment Record for which the method was invoked.
    Let bindings be the binding object for envRec.
    Return ? Set(bindings, N, V, S).

Set ( O, P, V, Throw )

    ...
    Let success be ? O.[[Set]](P, V, O).
    If success is false and Throw is true, throw a TypeError exception.
    Return success.

This would give me no path to get a ReferenceError for the ++x and x being deleted mid process.

Although, the engines seem to not agree with anything:

➜  eshost -tsx 'Object.defineProperty(this, "x", {
  configurable: true,
  get: function() {
    delete this.x;
    return 2;
  }
});

(function() {
  "use strict";
  ++x;
})();
'
┌────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ChakraCore     │                                                                                                                             │
│                │ ReferenceError: Variable undefined in strict mode                                                                           │
├────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ engine262      │                                                                                                                             │
│ Moddable XS    │                                                                                                                             │
├────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Hermes         │                                                                                                                             │
│                │ ReferenceError: Property 'x' doesn't exist                                                                                  │
├────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ JavaScriptCore │ /var/folders/_s/v0bdf8sd237bfp_kw4cyx8100000gp/T/9nVbA2j8YmPietLJklnz/f-1594694938814-48385-yr5nrk.8osm.js:11:5             │
│                │ global code@/var/folders/_s/v0bdf8sd237bfp_kw4cyx8100000gp/T/9nVbA2j8YmPietLJklnz/f-1594694938814-48385-yr5nrk.8osm.js:12:3 │
│                │ ReferenceError: Can't find variable: x                                                                                      │
├────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ SpiderMonkey   │                                                                                                                             │
│                │ ReferenceError: assignment to undeclared variable x                                                                         │
├────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ V8             │                                                                                                                             │
│                │ ReferenceError: x is not defined                                                                                            │
└────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

I'm not sure where is ReferenceError... let me try this again...

@leobalter
Copy link
Member

@allenwb @anba, can you help me here, please?

@leobalter
Copy link
Member

I wonder if the IsUnresolvableReference should be explicit about the base value component of V being dynamic as in: the current base value component of V.

The engine results throwing a RefError make me think this is the case.

In my brain, the base value component is not changed within the current spec text. Somehow it persists when we fetched that Reference (before the delete).

cc @tc39/ecma262-editors.

@bakkot
Copy link
Contributor Author

bakkot commented Jul 14, 2020

@leobalter I believe your reading of the spec is correct: that is, in the current spec, there is no reference error. Per that esdiscuss thread, this is a bug in the specification. I (apparently) opened a bugzilla issue to track this, and it never got fixed. But engines still don't pass the tests (e.g. v8 xfails them) and we should fix it upstream. Opened tc39/ecma262#2093 to track.

@leobalter
Copy link
Member

I have a tentative PR Draft in tc39/ecma262#2094 but I need to follow up investigating usage of PutValue to confirm it works.

ljharb pushed a commit to leobalter/ecma262 that referenced this issue Jul 30, 2020
…tc39#2094)

Verify binding existence in the object's SetMutableBinding on Strict Mode.

Closes tc39#2093
Ref tc39#467
Ref tc39/test262#427
@devsnek
Copy link
Member

devsnek commented Aug 8, 2020

More invalid tests:

language/expressions/compound-assignment/S11.13.2_A5.1_T4.js
language/expressions/compound-assignment/S11.13.2_A5.4_T4.js
language/expressions/compound-assignment/S11.13.2_A5.7_T4.js
language/expressions/compound-assignment/S11.13.2_A5.10_T4.js
language/expressions/compound-assignment/S11.13.2_A5.11_T4.js
language/expressions/compound-assignment/S11.13.2_A5.2_T4.js
language/expressions/compound-assignment/S11.13.2_A5.3_T4.js
language/expressions/compound-assignment/S11.13.2_A5.5_T4.js
language/expressions/compound-assignment/S11.13.2_A5.6_T4.js
language/expressions/compound-assignment/S11.13.2_A5.9_T4.js
language/expressions/compound-assignment/S11.13.2_A5.8_T4.js
language/expressions/assignment/S11.13.1_A5_T4.js
language/expressions/prefix-increment/S11.4.4_A5_T4.js
language/expressions/postfix-increment/S11.3.1_A5_T4.js
language/expressions/prefix-decrement/S11.4.5_A5_T4.js
language/expressions/postfix-decrement/S11.3.2_A5_T4.js

rwaldron added a commit that referenced this issue Sep 11, 2020
rwaldron added a commit that referenced this issue Sep 14, 2020
…ow a ReferenceError exception in strict mode code. Fixes gh-427
rwaldron added a commit that referenced this issue Sep 14, 2020
…ow a ReferenceError exception in strict mode code. Fixes gh-427
rwaldron added a commit that referenced this issue Sep 14, 2020
…ow a ReferenceError exception in strict mode code. Fixes gh-427
rwaldron added a commit that referenced this issue Sep 14, 2020
…ow a ReferenceError exception in strict mode code. Fixes gh-427
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants