Termination#

Terminating scripts that run out of control is quite important in terms of protecting the applications from being attacked by malicious scripts. In Javet, there are 2 typical ways of terminating scripts.

Automatic Termination with Pool and Engine#

IJavetEngineGuard is the built-in support for terminating a script which runs out of control.

// Get an engine from the pool as usual.
try (IJavetEngine iJavetEngine = iJavetEnginePool.getEngine()) {
    V8Runtime v8Runtime = iJavetEngine.getV8Runtime();
    // Get a guard from the engine and apply try-with-resource pattern.
    try (IJavetEngineGuard iJavetEngineGuard = iJavetEngine.getGuard(10000)) {
        v8Runtime.getExecutor("while (true) {}").executeVoid();
        // That infinite loop will be terminated in 10 seconds by the guard.
    } catch (JavetTerminatedException e) {
        // JavetTerminatedException will be thrown to mark that.
        assertFalse(e.isContinuable());
    }
    assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger(),
            "The V8 runtime is not dead and is still able to execute code afterwards.");
}

Does IJavetEngineGuard hang normal scripts till timeout is hit? No, it doesn't cause any overhead. If the script completes, IJavetEngineGuard.close() will be called via try-with-resource pattern and cancel the daemon thread immediately.

Please refer to the source code for more detail.

Manual Termination#

Manual termination gives applications complete control. In return, the coding effort is considerable.

V8Host v8Host = V8Host.getV8Instance();
try (V8Runtime v8Runtime = v8Host.createV8Runtime()) {
    // Create a daemon thread monitoring the V8 runtime status.
    Thread daemonThread = new Thread(() -> {
        // V8 runtime isInUse() does not require lock.
        while (!v8Runtime.isInUse()) {
            try {
                TimeUnit.MILLISECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // V8 runtime terminateExecution() does not require lock.
        v8Runtime.terminateExecution();
    });
    daemonThread.start();
    try {
        v8Runtime.getExecutor(
                "var count = 0; while (true) { ++count; }")
                .executeVoid();
        fail("Failed to throw exception when execution is terminated.");
    } catch (JavetTerminatedException e) {
        assertFalse(e.isContinuable());
    }
    final int count = v8Runtime.getGlobalObject().getInteger("count");
    assertTrue(count > 0, "Count should be greater than 0.");
    assertEquals(2, v8Runtime.getExecutor("1 + 1").executeInteger(),
            "V8 runtime should still be able to execute script after being terminated.");
}

How about Debug Mode?#

Usually, when application is being debugged, JavetEngineGuard may easily interrupt the debug. No worry, JavetEngineGuard is by default disabled in debug mode. Please refer to disableInDebugMode() and enableInDebugMode() for details.