Straighten out exception handling for CCE/NPE thrown by the eval loop and other exceptions thrown by eval itself
This commit is contained in:
@@ -5,7 +5,6 @@ import org.objectweb.asm.tree.analysis.Frame
|
|||||||
import org.objectweb.asm.tree.MethodNode
|
import org.objectweb.asm.tree.MethodNode
|
||||||
import org.objectweb.asm.Type
|
import org.objectweb.asm.Type
|
||||||
import org.objectweb.asm.Opcodes.*
|
import org.objectweb.asm.Opcodes.*
|
||||||
import org.objectweb.asm.tree.analysis.Interpreter
|
|
||||||
import org.objectweb.asm.tree.JumpInsnNode
|
import org.objectweb.asm.tree.JumpInsnNode
|
||||||
import org.objectweb.asm.tree.VarInsnNode
|
import org.objectweb.asm.tree.VarInsnNode
|
||||||
import org.objectweb.asm.util.Printer
|
import org.objectweb.asm.util.Printer
|
||||||
@@ -45,8 +44,12 @@ trait InterpretationEventHandler {
|
|||||||
fun exceptionCaught(currentState: Frame<Value>, currentInsn: AbstractInsnNode, exception: Value): InterpreterResult?
|
fun exceptionCaught(currentState: Frame<Value>, currentInsn: AbstractInsnNode, exception: Value): InterpreterResult?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThrownFromEvalException(val exception: Value): RuntimeException() {
|
class ThrownFromEvalException(cause: Throwable): RuntimeException(cause) {
|
||||||
fun toString(): String = "Thrown by evaluator: $exception"
|
fun toString(): String = "Thrown by evaluator: ${getCause()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThrownFromEvaluatedCodeException(val exception: Value): RuntimeException() {
|
||||||
|
fun toString(): String = "Thrown from evaluated code: $exception"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interpreterLoop(
|
fun interpreterLoop(
|
||||||
@@ -71,13 +74,13 @@ fun interpreterLoop(
|
|||||||
|
|
||||||
class ResultException(val result: InterpreterResult): RuntimeException()
|
class ResultException(val result: InterpreterResult): RuntimeException()
|
||||||
|
|
||||||
fun exceptionCaught(exceptionValue: Value): Boolean {
|
fun exceptionCaught(exceptionValue: Value, instanceOf: (Type) -> Boolean): Boolean {
|
||||||
val catchBlocks = handlers[m.instructions.indexOf(currentInsn)] ?: listOf()
|
val catchBlocks = handlers[m.instructions.indexOf(currentInsn)] ?: listOf()
|
||||||
for (catch in catchBlocks) {
|
for (catch in catchBlocks) {
|
||||||
val exceptionTypeInternalName = catch.`type`
|
val exceptionTypeInternalName = catch.`type`
|
||||||
if (exceptionTypeInternalName != null) {
|
if (exceptionTypeInternalName != null) {
|
||||||
val exceptionType = Type.getObjectType(exceptionTypeInternalName)
|
val exceptionType = Type.getObjectType(exceptionTypeInternalName)
|
||||||
if (eval.isInstanceOf(exceptionValue, exceptionType)) {
|
if (instanceOf(exceptionType)) {
|
||||||
val handled = handler.exceptionCaught(frame, currentInsn, exceptionValue)
|
val handled = handler.exceptionCaught(frame, currentInsn, exceptionValue)
|
||||||
if (handled != null) throw ResultException(handled)
|
if (handled != null) throw ResultException(handled)
|
||||||
frame.clearStack()
|
frame.clearStack()
|
||||||
@@ -90,6 +93,29 @@ fun interpreterLoop(
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun exceptionCaught(exceptionValue: Value): Boolean = exceptionCaught(exceptionValue) {
|
||||||
|
exceptionType -> eval.isInstanceOf(exceptionValue, exceptionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exceptionFromEvalCaught(exception: Throwable, exceptionValue: Value): Boolean {
|
||||||
|
return exceptionCaught(exceptionValue) {
|
||||||
|
exceptionType ->
|
||||||
|
try {
|
||||||
|
val exceptionClass = exception.javaClass
|
||||||
|
val _class = Class.forName(
|
||||||
|
exceptionType.getInternalName().replace('/', '.'),
|
||||||
|
true,
|
||||||
|
exceptionClass.getClassLoader()
|
||||||
|
)
|
||||||
|
_class.isAssignableFrom(exceptionClass)
|
||||||
|
}
|
||||||
|
catch (e: ClassNotFoundException) {
|
||||||
|
// If the class is not available in this VM, it can not be a superclass of an exception trown in it
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
val insnOpcode = currentInsn.getOpcode()
|
val insnOpcode = currentInsn.getOpcode()
|
||||||
@@ -175,6 +201,15 @@ fun interpreterLoop(
|
|||||||
frame.execute(currentInsn, interpreter)
|
frame.execute(currentInsn, interpreter)
|
||||||
}
|
}
|
||||||
catch (e: ThrownFromEvalException) {
|
catch (e: ThrownFromEvalException) {
|
||||||
|
val exception = e.getCause()!!
|
||||||
|
val exceptionValue = ObjectValue(exception, Type.getType(exception.javaClass))
|
||||||
|
val handled = handler.exceptionThrown(frame, currentInsn,
|
||||||
|
exceptionValue)
|
||||||
|
if (handled != null) return handled
|
||||||
|
if (exceptionFromEvalCaught(exception, exceptionValue)) continue
|
||||||
|
return ExceptionThrown(exceptionValue)
|
||||||
|
}
|
||||||
|
catch (e: ThrownFromEvaluatedCodeException) {
|
||||||
val handled = handler.exceptionThrown(frame, currentInsn, e.exception)
|
val handled = handler.exceptionThrown(frame, currentInsn, e.exception)
|
||||||
if (handled != null) return handled
|
if (handled != null) return handled
|
||||||
if (exceptionCaught(e.exception)) continue
|
if (exceptionCaught(e.exception)) continue
|
||||||
|
|||||||
@@ -208,6 +208,6 @@ fun <T> mayThrow(f: () -> T): T {
|
|||||||
return f()
|
return f()
|
||||||
}
|
}
|
||||||
catch (e: jdi.InvocationException) {
|
catch (e: jdi.InvocationException) {
|
||||||
throw ThrownFromEvalException(e.exception().asValue())
|
throw ThrownFromEvaluatedCodeException(e.exception().asValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,5 +107,5 @@ fun <T: Any> T?.checkNull(): T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun throwEvalException(e: Throwable): Nothing {
|
fun throwEvalException(e: Throwable): Nothing {
|
||||||
throw ThrownFromEvalException(ObjectValue(e, Type.getType(e.javaClass)))
|
throw ThrownFromEvalException(e)
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ object REFLECTION_EVAL : Eval {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: Throwable) {
|
catch (e: Throwable) {
|
||||||
throwEvalException(e)
|
throw ThrownFromEvaluatedCodeException(ObjectValue(e, Type.getType(e.javaClass)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user