I'm trying to build a scripting sandbox using Janino so that I can safely execute user functions by limiting the imports, CPU time and allocated bytes.
In Rhino (for javascript code) I have a function available named observeInstructionCount(Context ctx, int instructionCount) that is called every X instructions where X can be defined by the user when building the environment.
In this function I can do something like this:
/**
* This method is called every {@code instructionsBeforeObserve} and it is
* used to check if the current execution has exceded the {@code maxCpuTime}
* or the {maxMemory}. If so, an {@link java.lang.Error} is thrown.
*
*/
@Override
protected void observeInstructionCount(Context cx, int instructionCount) {
SafeContext sctx = (SafeContext) cx;
//Check CPU Time
if (getMaxCpuTime() > 0) {
long currentTime = System.currentTimeMillis();
if (currentTime - sctx.getStartTime() > getMaxCpuTime()) {
throw new Error("Max CPU Time limit of " + getMaxCpuTime() + " was exceeded");
}
}
//Check Memory Consumption
if (getMaxMemory() > 0 && threadMonitor != null) {
if (sctx.getStartMemory() <= 0) {
sctx.setStartMemory(threadMonitor.getThreadAllocatedBytes(sctx.getThreadId()));
} else {
long currentAllocatedBytes = threadMonitor.getThreadAllocatedBytes(sctx.getThreadId());
if ((currentAllocatedBytes - sctx.getStartMemory()) >= getMaxMemory()) {
throw new Error("Max Memory limit of " + getMaxMemory() + " was exceeded");
}
}
}
}
to monitor the execution time and allocated bytes.
Even if the user creates a loop (e.g. while(true) {} ) this function will eventually be called and if the perviously defined execution time was exceeded it will throw an error and the script execution will stop.
I'm trying to replicate this behaviour using Janino but I don't have a similar mechanism to monitor the scripts execution. If a user calls a blocking function I have no way to stop the script other then to abruptly call thread.stop() on the thread that is executing the script, which can be problematic. Any other calls like thread.interrupt() (as far as I know) won't interrupt blocking calls.
Any Ideas on how can I solve this problem?