Skip to content

Comma operator in constructor can cause "out of order" property initialization #937

Closed

Description

@johnpyp

It seems that under some circumstances where property initialization in a constructor is done with chained comma operators (a common result of minified code), the obfuscator can cause out of order initialization, where later initializations in the chain don't have access to previous initializations.

Minimal working example that will help to reproduce issue

class BuggyClass {
  constructor(param1, param2) {
    (this.param1 = param1),
      (this.param2 = param2),
      (this.obj = {
        param1: this.param1,
        param2: this.param2,
      });
  }

  debug() {
    console.log("BUGGY CLASS");
    console.log({ obj: this.obj });
    console.log({ param1: this.param1, param2: this.param2 });
  }
}

class GoodClass {
  constructor(param1, param2) {
    (this.param1 = param1),
      (this.param2 = param2),
      (this.obj = {
        param1: this.param1,
        param2: param2,
      });
  }

  debug() {
    console.log("GOOD CLASS");
    console.log({ obj: this.obj });
    console.log({ param1: this.param1, param2: this.param2 });
  }
}

const buggyClass = new BuggyClass("param1", "param2");

buggyClass.debug();

const goodClass = new GoodClass("param1", "param2");

goodClass.debug();

And obfuscated with these options:

    target: "node",
    optionsPreset: "medium-obfuscation",
    disableConsoleOutput: false,

Expected Behavior

The expected console output (and what you get when you run the file without obfuscation) is:

BUGGY CLASS
{ obj: { param1: 'param1', param2: 'param2' } }
{ param1: 'param1', param2: 'param2' }
GOOD CLASS
{ obj: { param1: 'param1', param2: 'param2' } }
{ param1: 'param1', param2: 'param2' }

The object here has the values from the previously initialized properties.

Current Behavior

BUGGY CLASS
{ obj: { param1: undefined, param2: undefined } }
{ param1: 'param1', param2: 'param2' }
GOOD CLASS
{ obj: { param1: 'param1', param2: 'param2' } }
{ param1: 'param1', param2: 'param2' }

Here, the obj object, has the fields undefined, despite coming after the initialization of those properties. Unexpectedly, in the GoodClass, the parameters are set correctly. The only difference between the classes is that the GoodClass uses param2: param2, rather than param2: this.param2 when initializing obj. I'm not sure what's going on internally that makes this work propertly, but it might be helpful.

Steps to Reproduce

You can use the above setup. I've also made a proof of concept repo, where you can demonstrate the bug with:

yarn
node build.js && node done.js

Your Environment

  • Obfuscator version used: 2.15.1
  • Node version used: 14.17.0

Activity

  1. sanex3339 commented on Jun 13, 2021

    @sanex3339
    Member

    Can reproduce it, will check it today.
    As a temporal solution set transformObjectKeys: false

  2. sanex3339 commented on Jun 13, 2021

    @sanex3339
    Member

    PR will be ready in 20 minutes. Will release it in an hour or so.

  3. sanex3339 commented on Jun 13, 2021

    @sanex3339
    Member

    PR: #938

  4. sanex3339 commented on Jun 13, 2021

    @sanex3339
    Member

    Released as 2.15.2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions