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 detail.