paulbartrum / jurassic

A .NET library to parse and execute JavaScript code.
MIT License
868 stars 121 forks source link

How to catch CLR Exception? #206

Closed yiszza closed 3 years ago

yiszza commented 3 years ago

hi, i want catch ClrException but the jurassic doesn't seem to support it

paulbartrum commented 3 years ago

Can you elaborate? AFAIK there's no class called ClrException, in either Jurassic or .NET in general.

yiszza commented 3 years ago

sorry, I mean, the exception thrown in clr class

like this

        static void Main(string[] args)
        {
            ScriptEngine engine = new ScriptEngine();
            engine.EnableExposedClrTypes = true; 
            engine.SetGlobalValue("console", new Jurassic.Library.FirebugConsole(engine));
            engine.SetGlobalFunction("importClass", new Action<string>(value =>
            {
                var temp = GetType(value);
                if (temp != null)
                {
                    string name = value[(value.LastIndexOf('.') + 1)..];
                    engine.SetGlobalValue(name, temp);
                }
            }));

            try
            {
                engine.Execute(@"
                    try{
                        importClass('System.IO.FileStream');
                        new FileStream('D:\\notexist.txt', 3);
                    }catch(ex){
                        console.log(ex);
                    }

                ");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }

        public static Type GetType(string value)
        {
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (asm.GetType(value) != null)
                {
                    return asm.GetType(value);
                }
            }
            return null;
        }
eaglemc commented 3 years ago

As far as I know you have to throw a Jurassic.JavaScriptException for it to show up in the executing script. I don't use EnableExposedClrTypes so I don't know if you can get that to wrap thrown exceptions automatically.

yiszza commented 3 years ago

As far as I know you have to throw a Jurassic.JavaScriptException for it to show up in the executing script. I don't use EnableExposedClrTypes so I don't know if you can get that to wrap thrown exceptions automatically.

you are right. so I'm trying Find a solution

yiszza commented 3 years ago

@paulbartrum hi , I changed some codes in Jurassic.Library.FunctionInstance , I'm not sure if it has a potential bug , do you think?

 public object CallWithStackTrace(string path, string function, int line, object thisObject, object[] argumentValues)
        {
            this.Engine.PushStackFrame(path, function, line, ScriptEngine.CallType.MethodCall);
            try
            {
                return CallLateBound(thisObject, argumentValues);
            }
            catch (JavaScriptException ex)
            {
                if (ex.FunctionName == null && ex.SourcePath == null && ex.LineNumber == 0)
                {
                    ex.FunctionName = this.Name;
                    ex.SourcePath = "native";
                    ex.GetErrorObject(Engine);
                }
                throw;
            }
            catch (Exception ex)
            {
                var wrapper = new JavaScriptException(ErrorType.Error, ex.ToString())
                {
                    FunctionName = this.Name,
                    SourcePath = "native"
                };
                wrapper.GetErrorObject(Engine);
                throw wrapper;
            }
            finally
            {
                this.Engine.PopStackFrame();
            }
        }
paulbartrum commented 3 years ago

Hmm okay I see what you're trying to do: you're trying to catch a non-JavaScriptException from JS code. There's no supported way to do this, unfortunately, but if you're willing to modify the code then your modification should work.

There's an alternate way if you don't want to change the wrap and rethrow the exception: 1) Change ScriptEngine.CanCatchException() to return true for the exception type you want to catch. 2) In TryCatchFinallyStatement.GenerateCode() change this code:

// Store the error object in the variable provided.
generator.ReinterpretCast(typeof(JavaScriptException));
EmitHelpers.LoadScriptEngine(generator);
generator.Call(ReflectionHelpers.JavaScriptException_GetErrorObject);

This code is the equivalent of: [catchVariable] = ((JavaScriptException)ex).GetErrorObject(); Obviously this won't work for anything but JavaScriptException. You'll need to change this to convert the .NET exception into a JS object somehow, to store in the catch variable.

yiszza commented 3 years ago

Hmm okay I see what you're trying to do: you're trying to catch a non-JavaScriptException from JS code. There's no supported way to do this, unfortunately, but if you're willing to modify the code then your modification should work.

There's an alternate way if you don't want to change the wrap and rethrow the exception:

  1. Change ScriptEngine.CanCatchException() to return true for the exception type you want to catch.
  2. In TryCatchFinallyStatement.GenerateCode() change this code:
// Store the error object in the variable provided.
generator.ReinterpretCast(typeof(JavaScriptException));
EmitHelpers.LoadScriptEngine(generator);
generator.Call(ReflectionHelpers.JavaScriptException_GetErrorObject);

This code is the equivalent of: [catchVariable] = ((JavaScriptException)ex).GetErrorObject(); Obviously this won't work for anything but JavaScriptException. You'll need to change this to convert the .NET exception into a JS object somehow, to store in the catch variable.

thank you!