2

Closed

InvalidProgramException when using 'continue' statement on some environments

description

We get System.InvalidProgramException on some environment when JS code contains 'continue' statement.

Sample program:
        static void Main(string[] args)
        {
            var engine = new Jurassic.ScriptEngine();
            var jsCode = @"function test() {
                          for (var i = 0; i < 2; i++) {
                            continue;
                          }
                        };
                        test();";

            engine.Evaluate(jsCode);
        }
This program will throw System.InvalidProgramException if built with target platform x64 and only on some environments. Unfortunately we were not able to identify any differences between environments where it fails and where it does not. We checked: Windows version and installed updates, .NET Framework version, VS version.

Please note that it looks like this exception is only thrown if there is 'continue' statement in 'for' loop, and not 'for..in' or 'while'. Also loop has to be within a function.

To fix the issue we tried: checking/unchecking "Optimize code". We also tried to verify Jurassic emitted IL code and do a PEVerify, but this tries where unsuccessful.

In the end we came up with workaround by rewriting code to avoid 'continue'. We only had it in library moment.js. I'm not much comfortable with changing external libraries locally.

Would be great to know if this is something that can be avoided and how to investigate it next time something similar happens.

Best Regards,
Andriy Buday
http://andriybuday.com
Closed Dec 14, 2015 at 3:36 AM by paulbartrum
I think I found the problem, and I have checked in a fix.

The problem only occurs if the continue statement is hit on the first loop iteration, which is how it escaped notice.

comments

paulbartrum wrote Dec 11, 2015 at 12:40 AM

Debugging the IL is mostly a matter of trial and error unfortunately. Hopefully I'll get some time to investigate over the weekend.

(My prediction is that the continue statement is generating a JMP instruction to a location outside of a containing fault block.)

By the way, you can grab the IL using this code:
public static string GetFunctionIL(string javascriptCode, string functionName)
{
  var scriptEngine = new ScriptEngine();
  scriptEngine.EnableILAnalysis = true;
  scriptEngine.Execute(javascriptCode);
  var function = (Jurassic.Library.UserDefinedFunction)scriptEngine.GetGlobalValue(functionName);
  if (function == null)
    throw new ArgumentException(string.Format("The function {0} was not found.", functionName));
  return function.DisassembledIL;
}