Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need best practices guides for performance and memory usage #101

Open
ClearScriptLib opened this issue Feb 5, 2019 · 2 comments
Open

Need best practices guides for performance and memory usage #101

ClearScriptLib opened this issue Feb 5, 2019 · 2 comments
Assignees

Comments

@ClearScriptLib
Copy link
Collaborator

No description provided.

@danbopes
Copy link

danbopes commented May 7, 2020

I can't stress this enough. I'm trying to integrate this into my project, and I'd like to safely add usage and resource limits. What areas I'm struggling with:

  • How the V8RuntimeConstraints worked, and some sample documentation on how to properly set reasonable size limits for user run code.
  • How do I limit execution time? With jint, I can specify a cancellation token to cancel the currently running script.
  • How to kill processes that hog the CPU:
engine.Execute(@"
    while (true) {}
");
  • How the engine works with asynchronous code:
public class TestApi
{
    private delegate void Executor(dynamic resolve, dynamic reject);
    private static async Task<string> Delay(string msg)
    {
        await Task.Delay(2000);

        return msg;
    }
    public static object delay(string msg)
    {
        var task = Delay(msg);
        var ctor = (ScriptObject)ScriptEngine.Current.Script.Promise;
        return ctor.Invoke(true, new Executor((resolve, reject) => {
            task.ContinueWith(t => {
                if (t.IsCompleted)
                {
                    resolve(t.Result);
                }
                else
                {
                    reject(t.Exception);
                }
            });
        }));
    }
}
engine.AddHostType("Console", typeof(Console));
engine.AddHostType("api", typeof(TestApi));
engine.Execute(@"
    Console.WriteLine('start');

    const main = async () => {
      Console.WriteLine('main');
      var res = await api.delay('end');
      Console.WriteLine(res);
    }
    main();
");

If I wrap this in a using block, it will output:

start
main

and then dispose of the engine

If I execute this, and add a Console.ReadKey(); before the engine gets disposed, after 2 seconds it correctly outputs end. There's no documentation on how to wait until execution of all callbacks is completed.

@ClearScriptLib
Copy link
Collaborator Author

Hi @danbopes,

  • How the V8RuntimeConstraints worked, and some sample documentation on how to properly set reasonable size limits for user run code.

We generally recommend that applications stay away from V8RuntimeConstraints.

Originally this API was somewhat suitable for sandboxing, but the V8 team decided years ago that constrained script execution isn't a goal for V8. Today, exceeding any of the specified limits causes V8 to crash instantly, and that's by design.

The API might still be useful for expanding V8's default limits, but we've found that V8 can then hit other limits that are inaccessible and vary unpredictably from version to version.

ClearScript does offer support for "soft limits" (see MaxRuntimeHeapSize, MaxRuntimeStackUsage), but as they require external monitoring via periodic timers, we can't guarantee their effectiveness in all cases.

The bottom line is that, unfortunately, if you must run untrusted script code with 100% safety, you'll need a Chromium-like multi-process architecture. The V8 team equates executing untrusted script code with invoking a function in an untrusted DLL.

V8's API is constantly changing though, and we'll continue to watch for new developments.

  • How do I limit execution time? With jint, I can specify a cancellation token to cancel the currently running script.
  • How to kill processes that hog the CPU

For these purposes you can use ScriptEngine.Interrupt.

There's no documentation on how to wait until execution of all callbacks is completed.

There's no special API for that, but you can always wait for a pre-arranged completion signal:

engine.AddHostType("Console", typeof(Console));
engine.AddHostType("api", typeof(TestApi));
engine.Script.done = new ManualResetEventSlim();
engine.Execute(@"
    Console.WriteLine('start');
    const main = async () => {
      Console.WriteLine('main');
      var res = await api.delay('end');
      Console.WriteLine(res);
      done.Set();
    }
    main();
");
engine.Script.done.Wait();

Please send any additional questions or comments our way.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants