Fixed deadCodeInjection causing SyntaxError when arguments from collected block statements was injected into class field initializers or static initialization blocks (#1377)

This commit is contained in:
Timofey Kachalov
2026-01-27 23:34:22 +04:00
committed by GitHub
parent ccece3fef1
commit 05aacd9dfe
5 changed files with 124 additions and 1 deletions
+1
View File
@@ -4,6 +4,7 @@ v5.2.1
---
* Fixed `transformObjectKeys` incorrectly hoisting object literal outside of loop when loop body is a single statement without braces, causing all iterations to share the same object reference. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1300
* Fixed parsing error when `await` is used as an identifier in non-async context. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1127
* Fixed `deadCodeInjection` causing SyntaxError when `arguments` from collected block statements was injected into class field initializers or static initialization blocks. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1166
v5.2.0
---
@@ -101,6 +101,7 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
* @param {Node} targetNode
* @returns {boolean}
*/
// eslint-disable-next-line complexity
private static isProhibitedNodeInsideCollectedBlockStatement(targetNode: ESTree.Node): boolean {
return (
NodeGuards.isFunctionDeclarationNode(targetNode) || // can break code on strict mode
@@ -110,7 +111,9 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
NodeGuards.isYieldExpressionNode(targetNode) ||
NodeGuards.isSuperNode(targetNode) ||
(NodeGuards.isForOfStatementNode(targetNode) && targetNode.await) ||
NodeGuards.isPrivateIdentifierNode(targetNode)
NodeGuards.isPrivateIdentifierNode(targetNode) ||
// `arguments` is not allowed in class field initializers or static initialization blocks
(NodeGuards.isIdentifierNode(targetNode) && targetNode.name === 'arguments')
);
}
@@ -0,0 +1,33 @@
// Function that uses `arguments` - this block can be collected for dead code injection
function logArgs() {
console.log(arguments);
console.log(arguments.length);
}
function foo() {
console.log(arguments[0]);
}
function bar() {
var args = arguments;
return args;
}
// Class with static initialization block - dead code should NOT be injected here with `arguments`
class MyClass {
static value;
static {
console.log('static block');
MyClass.value = 42;
}
method() {
console.log('method');
}
}
console.log(MyClass.value);
logArgs(1, 2, 3);
foo('test');
bar('a', 'b');
@@ -0,0 +1,33 @@
// Function that uses `arguments` - this block can be collected for dead code injection
function logArgs() {
console.log(arguments);
console.log(arguments.length);
}
function foo() {
console.log(arguments[0]);
}
function bar() {
var args = arguments;
return args;
}
// Class with field initializers - dead code should NOT be injected here with `arguments`
class MyClass {
field1 = (() => {
console.log('initializer');
return 1;
})();
field2 = 2;
method() {
console.log('method');
}
}
new MyClass();
logArgs(1, 2, 3);
foo('test');
bar('a', 'b');
@@ -0,0 +1,53 @@
import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../src/options/presets/NoCustomNodes';
import { readFileAsString } from '../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscatorFacade';
//
// https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1166
//
describe('Issue #1166', () => {
describe('`arguments` in collected block statement should not be injected into class field initializer', () => {
let testFunc: () => string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/issue1166.js');
testFunc = () =>
JavaScriptObfuscator.obfuscate(code, {
...NO_ADDITIONAL_NODES_PRESET,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1
}).getObfuscatedCode();
});
it('does not crash on obfuscating', () => {
// Run multiple times to increase chance of triggering the bug
for (let i = 0; i < 50; i++) {
assert.doesNotThrow(testFunc);
}
});
});
describe('`arguments` in collected block statement should not be injected into static block', () => {
let testFunc: () => string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/issue1166-static-block.js');
testFunc = () =>
JavaScriptObfuscator.obfuscate(code, {
...NO_ADDITIONAL_NODES_PRESET,
deadCodeInjection: true,
deadCodeInjectionThreshold: 1
}).getObfuscatedCode();
});
it('does not crash on obfuscating', () => {
// Run multiple times to increase chance of triggering the bug
for (let i = 0; i < 50; i++) {
assert.doesNotThrow(testFunc);
}
});
});
});