ClassNode 上的 Java ASM CheckClassAdapter

问题描述

ASM CheckClassAdapter 对于获取有关在验证错误的情况下类为什么失败的有用日志输出非常有用,但是它不能在堆栈图帧无效的情况下使用。 CheckClassAdapter 不能用于这些情况,因为它接受 ClassReader,这意味着要使用它来检查我转换后的 ClassNode,我必须执行以下操作:

ClassWriter verifyWriter = new ClassWriter(ClassWriter.COmpuTE_MAXS | ClassWriter.COmpuTE_FRAMES);
classNode.accept(verifyWriter);
CheckClassAdapter.verify(new ClassReader(verifyWriter.toByteArray()),true,printDumpLogFile);

当 ClassWriter 由于我的 ClassNode 的字节码奇怪地无效而失败时,传递到 CheckClassAdapter 的输出是无效的,并且非常畸形,有许多空帧和 nop。有什么方法可以将 ClassNode 传递给 CheckClassAdapter,从而避免使用限制其实用性的 ClassWriter?

解决方法

如果你有办法获得输入类的字节码而不是 ClassNode,你可以使用这样的方法:

CheckClassAdapter.verify(
  bytes,true,new PrintWriter(System.out)
);

例如,如果字节码已经存储在类文件中,则可以这样做:

CheckClassAdapter.verify(
  new ClassReader(new FileInputStream(args[0])),new PrintWriter(System.out)
);

但实际上,如果堆栈图帧无效,CheckClassAdapter 可能不会报告任何内容。至少我有它没有的类文件。顺便说一下,这同样适用于 org.apache.bcel.verifier.Verifier。尽管如此,JVM 仍会抛出 VerifyError,即将类加载到实际 JVM 中是最终检查。

,

我找到了一个解决方案,创建一个扩展 CheckClassAdapter 的类并添加一个带有 ClassNode 参数的方法。阅读CheckClassAdapter的源码,我发现ClassReader无论如何都会访问一个类节点。

SELECT projectname,referenceid,SUM(quantity) quantity
FROM (
  SELECT projectname,quantity
  FROM Table1
  UNION ALL
  SELECT projectname,-quantity
  FROM Table2
) t
GROUP BY projectname,referenceid

如您所见,ASM 可以公开一个方法以仅在 ClassNode 中输入,但由于某些原因没有。

这是扩展 CheckClassAdapter 的类的代码,添加了此功能:

public static void verify(
  final ClassReader classReader,final ClassLoader loader,final boolean printResults,final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
    new CheckClassAdapter(/*latest*/ Opcodes.ASM10_EXPERIMENTAL,classNode,false) {},ClassReader.SKIP_DEBUG);

我可能会在 ASM 存储库上创建一个问题并添加一个拉取请求来添加它。