diff --git a/modules/rhino/src/main/java/com/script/CompiledScript.kt b/modules/rhino/src/main/java/com/script/CompiledScript.kt index 81e9d87a0..1d3a9cf1e 100644 --- a/modules/rhino/src/main/java/com/script/CompiledScript.kt +++ b/modules/rhino/src/main/java/com/script/CompiledScript.kt @@ -13,10 +13,14 @@ abstract class CompiledScript { abstract fun getEngine(): ScriptEngine @Throws(ScriptException::class) - abstract fun eval(context: ScriptContext): Any? + fun eval(context: ScriptContext): Any? { + return eval(getEngine().getRuntimeScope(context)) + } @Throws(ScriptException::class) - abstract fun eval(scope: Scriptable): Any? + fun eval(scope: Scriptable): Any? { + return eval(scope, null) + } @Throws(ScriptException::class) abstract fun eval(scope: Scriptable, coroutineContext: CoroutineContext?): Any? diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt index 967b581f3..f3d52e364 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt @@ -25,12 +25,17 @@ package com.script.rhino import com.script.CompiledScript -import com.script.ScriptContext import com.script.ScriptEngine import com.script.ScriptException +import kotlinx.coroutines.Job import kotlinx.coroutines.asContextElement import kotlinx.coroutines.withContext -import org.mozilla.javascript.* +import org.mozilla.javascript.Context +import org.mozilla.javascript.ContinuationPending +import org.mozilla.javascript.JavaScriptException +import org.mozilla.javascript.RhinoException +import org.mozilla.javascript.Script +import org.mozilla.javascript.Scriptable import java.io.IOException import kotlin.coroutines.Continuation import kotlin.coroutines.CoroutineContext @@ -51,56 +56,15 @@ internal class RhinoCompiledScript( return engine } - @Throws(ScriptException::class) - override fun eval(context: ScriptContext): Any? { - val cx = Context.enter() - val result: Any? - try { - val scope = engine.getRuntimeScope(context) - val ret = script.exec(cx, scope) - result = engine.unwrapReturnValue(ret) - } catch (re: RhinoException) { - val line = if (re.lineNumber() == 0) -1 else re.lineNumber() - val msg: String = if (re is JavaScriptException) { - re.value.toString() - } else { - re.toString() - } - val se = ScriptException(msg, re.sourceName(), line) - se.initCause(re) - throw se - } finally { - Context.exit() - } - return result - } - - override fun eval(scope: Scriptable): Any? { - val cx = Context.enter() - val result: Any? - try { - val ret = script.exec(cx, scope) - result = engine.unwrapReturnValue(ret) - } catch (re: RhinoException) { - val line = if (re.lineNumber() == 0) -1 else re.lineNumber() - val msg: String = if (re is JavaScriptException) { - re.value.toString() - } else { - re.toString() - } - val se = ScriptException(msg, re.sourceName(), line) - se.initCause(re) - throw se - } finally { - Context.exit() - } - return result - } - override fun eval(scope: Scriptable, coroutineContext: CoroutineContext?): Any? { val cx = Context.enter() as RhinoContext + cx.checkRecursive() val previousCoroutineContext = cx.coroutineContext - cx.coroutineContext = coroutineContext + if (coroutineContext != null && coroutineContext[Job] != null) { + cx.coroutineContext = coroutineContext + } + cx.allowScriptRun = true + cx.recursiveCount++ val result: Any? try { val ret = script.exec(cx, scope) @@ -117,6 +81,8 @@ internal class RhinoCompiledScript( throw se } finally { cx.coroutineContext = previousCoroutineContext + cx.allowScriptRun = false + cx.recursiveCount-- Context.exit() } return result diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoContext.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoContext.kt index 52456f770..988321dab 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoContext.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoContext.kt @@ -10,6 +10,7 @@ class RhinoContext(factory: ContextFactory) : Context(factory) { var coroutineContext: CoroutineContext? = null var allowScriptRun = false + var recursiveCount = 0 @Throws(RhinoInterruptError::class) fun ensureActive() { @@ -20,4 +21,11 @@ class RhinoContext(factory: ContextFactory) : Context(factory) { } } + @Throws(RhinoRecursionError::class) + fun checkRecursive() { + if (recursiveCount >= 10) { + throw RhinoRecursionError() + } + } + } diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoInterruptedError.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoErrors.kt similarity index 56% rename from modules/rhino/src/main/java/com/script/rhino/RhinoInterruptedError.kt rename to modules/rhino/src/main/java/com/script/rhino/RhinoErrors.kt index d0532b337..b6dfbb24f 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoInterruptedError.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoErrors.kt @@ -1,3 +1,5 @@ package com.script.rhino class RhinoInterruptError(override val cause: Throwable) : Error() + +class RhinoRecursionError(): Error("Maximum recursion depth exceeded.") diff --git a/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt b/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt index 5ec250dec..bb0ab9f7d 100644 --- a/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt +++ b/modules/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt @@ -33,6 +33,7 @@ import com.script.ScriptBindings import com.script.ScriptContext import com.script.ScriptException import com.script.SimpleBindings +import kotlinx.coroutines.Job import kotlinx.coroutines.asContextElement import kotlinx.coroutines.withContext import org.mozilla.javascript.Callable @@ -92,11 +93,13 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { coroutineContext: CoroutineContext? ): Any? { val cx = Context.enter() as RhinoContext + cx.checkRecursive() val previousCoroutineContext = cx.coroutineContext - if (coroutineContext != null) { + if (coroutineContext != null && coroutineContext[Job] != null) { cx.coroutineContext = coroutineContext } cx.allowScriptRun = true + cx.recursiveCount++ val ret: Any? try { var filename = this["javax.script.filename"] as? String @@ -117,6 +120,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { } finally { cx.coroutineContext = previousCoroutineContext cx.allowScriptRun = false + cx.recursiveCount-- Context.exit() } return unwrapReturnValue(ret) @@ -125,9 +129,11 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { @Throws(ContinuationPending::class) override suspend fun evalSuspend(reader: Reader, scope: Scriptable): Any? { val cx = Context.enter() as RhinoContext + cx.checkRecursive() var ret: Any? withContext(VMBridgeReflect.contextLocal.asContextElement()) { cx.allowScriptRun = true + cx.recursiveCount++ try { var filename = this@RhinoScriptEngine["javax.script.filename"] as? String filename = filename ?: "" @@ -166,6 +172,7 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { throw ScriptException(var14) } finally { cx.allowScriptRun = false + cx.recursiveCount-- Context.exit() } }