NeilFraser / JS-Interpreter

A sandboxed JavaScript interpreter in JavaScript.
Apache License 2.0
1.98k stars 355 forks source link

A named function, existing as a variable in its own local scope, shadows the global declaration #251

Closed malwarebin closed 1 year ago

malwarebin commented 1 year ago

When a named function is called in JS-Interpreter, that very function is introduced in its own local scope as a variable with the same name.

That shadows the actual function declaration in the parent scope and code, which works in NodeJS and in any browser (tested in Chromium, Firefox and Chrome), does not work in JS-Interpreter (see the end of this issue for the actual code).

Debugging the code in a browser shows that the function being called is not present in its local scope, unlike JS-Interpreter.

I skimmed the Function references at MDN but I could not find anything related to this function reassignment issue.

Problem code follows:

function funcArray() {
  var strArray = ['JFfff', 'nfnjsff', 'furhet', 'simmxqe', 'jfFJSDDDD', 'frknwf-fnfh', 'IgfwJ', 'SOMGRWHWND', 'flisJFfd', 'fsdEffhfD', 'fjshe', '16GxFGGwe', '7834fjiweJF', 'wfe', 'FJWEJFf', 'xewasd', '00$slkdjf', 'ggg', 'wednd', ' foiwnf', '2556594jfrwwFF', 'fwrFF', 'sfWfwfWwfw', '500llg', 'ferr-er-re', 'lkesjfsSerr', 'III', '1205955sdkjfSDF', '1 fwerf', 'w;oejf', 'wfffwefef', 'fwefww', 'cjwwwWdjdwWd', 'DDW', 'dwWEdw', ' sdafff:0;', 'nmfwer#0', '7|1|0', 'ionfF', '11Gjfwwje', 'Ejdnw', 'asd.frjier', '326pxFlew', 'sdwe:0. fjkw', 'oweirbddd', 'kwqulfj', 'fewwffwwf', 'y sddffw.iru', 'wef!fioewjw', 'jgirr', 'ssffwef', '2763927wpiejfFw', 'wieihf', '# lihwef:1', 'sdffD', 'eoO', 'fkwlhef', 'wlejf/wekfjwef', '2946fijwWJF', 'fwejEJ', 'lkwehfhf:100&', 'kwsejfw$0; f', 'srewf', 'WFWwwf', 'fwlejfweffff', 'UfwuwUw', 'OWfjfwJ', 'weihwEeewww', 'weFJwf', 'wekfhfwhx', 'wef-wef', '9314730JWfjwJ', '3503476pewfmNF', 'xoxo', 'WEJFnfWNNWF', 'WJXjxjw', 'weJFJFw', 'weejfjw', 'jjj:999999', '20=2fjf2', '4|5|2|3|6|', 'wlehfhflw', 'flweh-fwef', '7371wefWFw', '100...', 'wefWFwfwF', 'owefncC', 'WFwwEF', 'wfwef.wefr.rrr', 'werwerJ.w', 'wcmiweEErrr', 'weWRR', 'WERF', 'werr', 'weff.W>WE.', 'wefjJweff', 'weffweff', 'LWELFddw', 'weEEFff', 'weffwefff'];
  funcArray = function funcArray() {
    return strArray;
  };
  return funcArray();
}
function funcAccess(index) {
  var intrFuncArray = funcArray();
  return funcAccess = function funcAccess(intIndex) {
    intIndex = intIndex - 472;
    var tempResult = intrFuncArray[intIndex];
    return tempResult;
  }, funcAccess(index);
}
(function (myFuncArray, numberEnd) {
  var intFuncAccess = funcAccess,
    intFuncArray = myFuncArray();
  while (true) {
    try {
      var calcNumber = parseInt(intFuncAccess(487)) / 1 * (parseInt(intFuncAccess(557)) / 2) + parseInt(intFuncAccess(565)) / 3 + parseInt(intFuncAccess(517)) / 4 + -parseInt(intFuncAccess(472)) / 5 + -parseInt(intFuncAccess(503)) / 6 * (parseInt(intFuncAccess(528)) / 7) + parseInt(intFuncAccess(556)) / 8 * (-parseInt(intFuncAccess(496)) / 9) + -parseInt(intFuncAccess(516)) / 10 * (parseInt(intFuncAccess(484)) / 11);
      if (calcNumber === numberEnd) break;else {
        intFuncArray.push(intFuncArray.shift());
      }
    } catch (_0x76eba) {
      intFuncArray['push'](intFuncArray['shift']());
    }
  }
})(funcArray, 701116);
console.log('end');
NeilFraser commented 1 year ago

Thanks for this. I'm always excited to learn about JS-Interpreter bugs.

Here's a minimal testcase:

function myFunc() {
  myFunc = 42;
}
myFunc();
alert(myFunc);

Browser output: 42 JS-Interpreter output: [object Function]

This will be fixed immediately. Investigating...

cpcallen commented 1 year ago

There are two bugs here:

  1. With function declarations, per example given in the previous comment.
  2. With named function expressions:
    alert((function foo() { foo = 42; return foo; })())

    should return the function object in nonstrict mode, and throw TypeError: Assignment to constant variable in strict mode, but in fact returns 42.

    • The name of a named function expression is an immutable binding within the body of the function.)
    • N.B. however that it can be shadowed by a parameter or variable:
      alert((function foo(foo) { foo = 42; return foo;})())

      and

      alert((function foo() { var foo = 42; return foo;})())

      should both return 42 in either strict or nonstrict mode.

malwarebin commented 1 year ago

Tested the fix, it works perfectly. Thank you very much!

JS-Interpreter and Blockly are two great projects, your efforts are much appreciated.

If there is a way to send you both a beer or two, please let me know :)