Skip to content

Self-interrupting scripts don't interrupt cleanly. #324

Description

@SomebodyOdd

Hello!

Suppose I have a script, that makes a call to host that results in a call to V8ScriptEngine.Interrupt method (reason is arbitrary, but I can see how this could be used by script to interrupt itself through host call if something is really wrong).

Consider this code:

public class ScriptContext 
{
  private V8ScriptEngine _engine;

  public ScriptContext(V8ScriptEngine engine) => _engine = engine;

  public void Interrupt() => _engine.Interrupt();
  public void Ping() => Console.WriteLine("Ping!");
}

static void Main(string[] args) 
{
  var runtime = new V8Runtime();

  var engine = runtime.CreateScriptEngine();
  var context = new ScriptContext(engine);

  engine.AddRestrictedHostObject("context", context);

  var script = @ "<some script code I'll show in a bit>";

  try 
  {
    var evaluated = engine.Evaluate(script);
    Console.WriteLine($"Clean shutdown. Evaluated: {evaluated}");
  } 
  catch (ScriptInterruptedException) 
  {
    Console.WriteLine("Interrupted exception");
  } 
  catch (ScriptEngineException exc) 
  {
    Console.WriteLine($"Script exception: {exc.Message}");
  }
}

There are multiple problems which can occur here, depending on script. Here are some script examples:

1. Script appears to ignore the interruption request.

context.Interrupt();

Output: Clean shutdown. Evaluated: Microsoft.ClearScript.VoidResult

2. Sneaky script result.

context.Interrupt();
2 + 2;

Output: Clean shutdown. Evaluated: 4

3. Sneaky script error.

context.Interrupt();
throw new Error('Gotcha!')

Output: Script exception: Error: Gotcha!

4. Host calls after interruption makes it right...

context.Interrupt();
context.Ping();

Output: Interrupted exception

5. ...until it's not =)

context.Interrupt();
try {
context.Ping();
}
catch(e) { }

Output: Clean shutdown. Evaluated: [undefined]

6. Some work without host calls is interrupted eventually

context.Interrupt(); 
while(true) {}

Output: Interrupted exception

Can this be fixed somehow?
Ideally, script should be stopped immediately, never returning from context.Interrupt method, even with an script-catchable exception, and Evaluate method should throw ScriptInterruptedException, in all of the above cases. This leaves script runtime is somewhat known state.
Alternatively, if instant stopping of script is not possible, results and script errors should be ignored in favor of throwing ScriptInterruptedException, because that's what happened - script was interrupted by the script itself. This leaves script variables in an undefined state, meaning that further Evaluate and Execute (as well as accessing global variable with Script property) could observe some changes, that script made between interruption request and interruption, but at least host gets to know that there was an interruption at all.

Activity

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

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions