Skip to content

Commit

Permalink
catch all exceptions in unpickler
Browse files Browse the repository at this point in the history
  • Loading branch information
adpi2 committed Jul 10, 2023
1 parent bc58be6 commit eef3342
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Scala2Unpickler(
scalaVersion: ScalaVersion,
logger: Logger,
testMode: Boolean
) extends ScalaUnpickler(scalaVersion) {
) extends ScalaUnpickler(scalaVersion, testMode) {
override protected def skipScala(method: jdi.Method): Boolean = {
if (isLazyInitializer(method)) {
skipLazyInitializer(method)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import ch.epfl.scala.debugadapter.Java8
import ch.epfl.scala.debugadapter.Java9OrAbove
import scala.util.Try
import java.nio.file.Path
import scala.util.Success
import scala.util.Failure
import java.util.Optional
import ch.epfl.scala.debugadapter.ScalaVersion
import scala.jdk.OptionConverters._
Expand All @@ -20,8 +18,9 @@ class Scala3UnpicklerBridge(
scalaVersion: ScalaVersion,
bridge: Any,
skipMethod: Method,
formatMethod: Method
) extends ScalaUnpickler(scalaVersion) {
formatMethod: Method,
testMode: Boolean
) extends ScalaUnpickler(scalaVersion, testMode) {
override protected def skipScala(method: jdi.Method): Boolean = {
try skipMethod.invoke(bridge, method).asInstanceOf[Boolean]
catch {
Expand All @@ -47,7 +46,7 @@ object Scala3UnpicklerBridge {
logger: Logger,
testMode: Boolean
): Try[Scala3UnpicklerBridge] = {
try {
Try {
val className = "ch.epfl.scala.debugadapter.internal.stacktrace.Scala3Unpickler"
val cls = classLoader.loadClass(className)
val ctr = cls.getConstructor(classOf[Array[Path]], classOf[Consumer[String]], classOf[Boolean])
Expand All @@ -68,9 +67,7 @@ object Scala3UnpicklerBridge {
val skipMethod = cls.getMethods.find(m => m.getName == "skipMethod").get
val formatMethod = cls.getMethods.find(m => m.getName == "formatMethod").get

Success(new Scala3UnpicklerBridge(debuggee.scalaVersion, bridge, skipMethod, formatMethod))
} catch {
case cause: Throwable => Failure(cause)
new Scala3UnpicklerBridge(debuggee.scalaVersion, bridge, skipMethod, formatMethod, testMode)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ import com.sun.jdi.Method
import com.sun.jdi.ReferenceType

import scala.jdk.CollectionConverters.*
import scala.util.control.NonFatal

abstract class ScalaUnpickler(scalaVersion: ScalaVersion) extends StepFilter {
abstract class ScalaUnpickler(scalaVersion: ScalaVersion, testMode: Boolean) extends StepFilter {
protected def skipScala(method: Method): Boolean
protected def formatScala(method: Method): Option[String] = Some(formatJava(method))

private def throwOrWarn(exception: Throwable): Unit =
if (testMode) throw exception
else exception.getMessage

override def shouldSkipOver(method: Method): Boolean = {
if (method.isBridge) true
else if (isDynamicClass(method.declaringType)) true
Expand All @@ -31,7 +36,11 @@ abstract class ScalaUnpickler(scalaVersion: ScalaVersion) extends StepFilter {
else if (scalaVersion.isScala2 && isNestedClass(method.declaringType)) false
else if (isDefaultValue(method)) false
else if (isTraitInitializer(method)) skipTraitInitializer(method)
else skipScala(method)
else
try skipScala(method)
catch {
case NonFatal(e) => throwOrWarn(e); false
}
}

def format(method: Method): Option[String] = {
Expand All @@ -49,7 +58,11 @@ abstract class ScalaUnpickler(scalaVersion: ScalaVersion) extends StepFilter {
else if (isLocalClass(method.declaringType)) Some(formatJava(method))
else if (scalaVersion.isScala2 && isNestedClass(method.declaringType)) Some(formatJava(method))
else if (isDefaultValue(method)) Some(formatJava(method))
else formatScala(method)
else
try formatScala(method)
catch {
case NonFatal(e) => throwOrWarn(e); Some(formatJava(method))
}
}

private def formatJava(method: Method): String = {
Expand Down Expand Up @@ -150,10 +163,11 @@ object ScalaUnpickler {
.tryLoad(debuggee, classLoader, logger, testMode)
.warnFailure(logger, s"Cannot load step filter for Scala ${debuggee.scalaVersion}")
}
.getOrElse(fallback(debuggee.scalaVersion))
.getOrElse(fallback(debuggee.scalaVersion, testMode))
}

private def fallback(scalaVersion: ScalaVersion): ScalaUnpickler = new ScalaUnpickler(scalaVersion) {
override protected def skipScala(method: Method): Boolean = false
}
private def fallback(scalaVersion: ScalaVersion, testMode: Boolean): ScalaUnpickler =
new ScalaUnpickler(scalaVersion, testMode) {
override protected def skipScala(method: Method): Boolean = false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ final case class FakeJdiMethod(

override def compareTo(o: Method): Int = ???

override def returnTypeName(): String = ???
override def returnTypeName(): String = returnType.name

override def argumentTypeNames(): ju.List[String] = ???

override def argumentTypes(): ju.List[Type] = ???
override def argumentTypes(): ju.List[Type] = arguments.asScala.map(_.`type`).asJava

override def isAbstract(): Boolean = ???

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,23 @@ class Method(val obj: Any) extends JavaReflection(obj, "com.sun.jdi.Method"):
ReferenceType(invokeMethod("declaringType"))

def arguments: Seq[LocalVariable] =
invokeMethod[java.util.List[Object]]("arguments").asScala.toSeq
.map(LocalVariable.apply(_))
invokeMethod[java.util.List[Object]]("arguments").asScala.toSeq.map(LocalVariable.apply(_))

def argumentTypes: Seq[Type] =
invokeMethod[java.util.List[Object]]("argumentTypes").asScala.toSeq.map(Type.apply(_))

def returnType: Option[Type] =
try Some(Type(invokeMethod("returnType")))
catch
case e: InvocationTargetException if e.getCause.getClass.getName == "com.sun.jdi.ClassNotLoadedException" =>
None

def isExtensionMethod: Boolean =
name.endsWith("$extension")
def returnTypeName: String = invokeMethod("returnTypeName")

def isExtensionMethod: Boolean = name.endsWith("$extension")

def isTraitInitializer: Boolean =
name == "$init$"
def isTraitInitializer: Boolean = name == "$init$"

def isClassInitializer: Boolean =
name == "<init>"
def isClassInitializer: Boolean = name == "<init>"

override def toString: String = invokeMethod("toString")
Original file line number Diff line number Diff line change
Expand Up @@ -41,46 +41,33 @@ class Scala3Unpickler(
else exception.getMessage

def skipMethod(obj: Any): Boolean =
findSymbolImpl(obj) match
case Failure(exception) => throwOrWarn(exception); false
case Success(Some(symbol)) => skip(symbol)
case Success(None) => true
findSymbol(obj).forall(skip)

def formatMethod(obj: Any): Optional[String] =
val method = jdi.Method(obj)
findSymbol(obj).map { t =>
val notMethodType = t.declaredType match {
case _: MethodType => false
case _: PolyType => false
case _ => true
}
val optionalString = if (notMethodType) ": " else ""
s"${formatSymbol(t)}${optionalString}${formatType(t.declaredType)}"
}.asJava
findSymbol(obj) match
case None => Optional.empty
case Some(symbol) =>
val sep = if !symbol.declaredType.isInstanceOf[MethodicType] then ": " else ""
Optional.of(s"${formatSymbol(symbol)}$sep${formatType(symbol.declaredType)}")

private[stacktrace] def findSymbol(obj: Any): Option[TermSymbol] =
findSymbolImpl(obj).get

private def findSymbolImpl(obj: Any): Try[Option[TermSymbol]] =
val method = jdi.Method(obj)
val fqcn = method.declaringType.name
findDeclaringType(fqcn, method.isExtensionMethod) match
case None =>
Failure(Exception(s"Cannot find Scala symbol of $fqcn"))
throw new Exception(s"Cannot find Scala symbol of $fqcn")
case Some(declaringType) =>
val matchingSymbols =
declaringType.declarations
.collect { case sym: TermSymbol if sym.isTerm => sym }
.filter(matchSymbol(method, _))

if matchingSymbols.size > 1 then
val builder = new java.lang.StringBuilder
builder.append(
s"Found ${matchingSymbols.size} matching symbols for $method:"
)
matchingSymbols.foreach(sym => builder.append(s"\n$sym"))
Failure(Exception(builder.toString))
else Success(matchingSymbols.headOption)
val message =
s"Found ${matchingSymbols.size} matching symbols for $method:" +
matchingSymbols.mkString("\n")
throw new Exception(message)
else matchingSymbols.headOption

def formatType(t: Type): String =
t match
Expand Down

0 comments on commit eef3342

Please sign in to comment.