Skip to content

CreateGlobalVarBinding performs redundant InitializeBinding, causing unintended side effects on Proxy global objects #3854

@alexey-alanreys

Description

@alexey-alanreys

In CreateGlobalVarBinding (§9.1.1.4.16), step 5 reads:

Step Operation
5a objectRecord.CreateMutableBinding(name, deletable)
5b objectRecord.InitializeBinding(name, undefined)

However, CreateMutableBinding for an Object Environment Record (§9.1.1.2.2) already calls DefinePropertyOrThrow with [[Value]]: undefined, which both creates and initializes the property. Step 5b therefore performs a redundant [[Set]] on a property already set to undefined.

The description of CreateGlobalVarBinding states: "It creates and initializes a mutable binding" — yet the current steps perform initialization twice.

Impact

Global object type Effect of step 5b
Ordinary object No observable effect — redundant no-op
Proxy object (permitted by §9.3.1 step 10) Unintended [[Set]] trap invocation after [[DefineOwnProperty]] — observable side effect not implied by the operation's stated semantics

The spec explicitly acknowledges in §16.1.7 Note 2 that a Proxy global object is a valid and known scenario:

"if the global object is defined using Proxy exotic objects then the runtime tests for conflicting declarations may be unreliable resulting in an abrupt completion and some global declarations not being instantiated."

This makes the unintended [[Set]] in step 5b a concrete risk, not a theoretical one.

By contrast, the sibling operation CreateGlobalFunctionBinding (§9.1.1.4.17) performs the same DefinePropertyOrThrow + Set pattern and explicitly documents it in a NOTE:

"Step 7 is equivalent to what calling the InitializeBinding concrete method would do and if globalObject is a Proxy will produce the same sequence of Proxy trap calls."

This NOTE is absent in CreateGlobalVarBinding, leaving it ambiguous whether the [[Set]] in step 5b is intentional or an oversight.

Possible resolutions

  1. Remove step 5b — CreateMutableBinding already fulfills the "creates and initializes" contract.
  2. Replace steps 5a–5b with a single DefinePropertyOrThrow call, making the intent explicit and eliminating the extra trap invocation for Proxy objects.
  3. Add a NOTE analogous to §9.1.1.4.17 clarifying that step 5b intentionally triggers [[Set]] for Proxy global objects — if this behaviour is by design.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions