Skip to content

Performance Regression: stringArrayWrappersType: 'variable' causes repeated self-modification and cache loss since v2.15.4 #1330

@koala1113

Description

@koala1113

Expected Behavior

When using stringArrayWrappersType: 'variable', the string array wrapper variable should reference the self-modified function after its first modification. The self-modifying function should only modify itself once on the first call, and subsequent calls through the wrapper variable should use the pre-modified version with proper caching.

Current Behavior

Since version 2.15.4, when using stringArrayWrappersType: 'variable', the wrapper variables capture the original function reference before any self-modification occurs. This causes:

  1. The self-modifying function re-modifies itself on every call through the wrapper
  2. Internal caching mechanisms are lost due to repeated re-initialization
  3. Significant performance degradation as the self-modification logic runs repeatedly

Root Cause

In commit 5683e75, the original direct function in StringArrayCallsWrapperTemplate was changed to a self-modifying function, but when using stringArrayWrappersType: 'variable', the wrapper variables are assigned before the function self-modification occurs, causing subsequent calls to reference the unmodified function version instead of the optimized one.

Steps to Reproduce

  1. Import javascript-obfuscator in version 4.1.1
  2. Obfuscate code below using the below config

Your Environment

  • Obfuscator version used: 4.1.1 (issue exists since 2.15.4)
  • Node version used: Any

Minimal working example that will help to reproduce issue

Source code:

const foo = 'foo';
const bar = 'bar';
        
function test () {
    const baz = 'baz';
    const bark = 'bark';
    const hawk = 'hawk';
}

const eagle = 'eagle';

Obfuscating options:

{
    optionsPreset: "default",
    stringArrayWrappersType: "variable",
    stringArrayRotate: false,
    stringArrayShuffle: false,
    seed: 42,
    compact: false,
    simplify: false
}

Obfuscated code:

const _0xebd97a = _0x2add; // Problem: captures original _0x2add before modification
function _0x390b() {
    const _0x3cc902 = [
        'foo',
        'bar',
        'bark',
        'hawk',
        'eagle'
    ];
    _0x390b = function () {
        return _0x3cc902;
    };
    return _0x390b();
}
const foo = _0xebd97a(0x1ad); // First call: modifies _0x2add, but _0xebd97a still points to original
function _0x2add(_0x1dd818, _0x390bb0) {
    const _0x2add11 = _0x390b();
    _0x2add = function (_0x1a9378, _0x4f5905) { // Self-modification occurs here
        _0x1a9378 = _0x1a9378 - 0x1ad;
        let _0x2592ec = _0x2add11[_0x1a9378];
        return _0x2592ec;
    };
    return _0x2add(_0x1dd818, _0x390bb0);
}
const bar = _0xebd97a(0x1ae); // Second call: re-triggers the same self-modification
function test() {
    const _0x246f42 = _0xebd97a;
    const _0x26aee5 = 'baz';
    const _0x2cd328 = _0x246f42(0x1af);
    const _0x5c4455 = _0x246f42(0x1b0);
}
const eagle = _0xebd97a(0x1b1);

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions