我正在编写一个用于赋值的静态分析工具,它使用ASM库分析Java字节码.我们使用的ASM的一个部分需要(或者至少似乎要求)从ClassLoader加载该类.
我们希望该工具能够分析.class文件,而不需要它们在类路径上.我们已经在运行时从指定目录加载.classes并使用InputStream读取它们.在大多数情况下,这对于ASM是可接受的.有些类,例如SimpleVerifier,尝试加载类.
在这种情况下,是否可以注册要加载的.class文件,以便调用Class.forName()将加载它们?或者是否有一种简单的方法来扩展ClassLoader以允许它?
编辑:URLClassLoader有用的信息.不幸的是,使用Thread.currentThread().setContextClassLoader()它的实例在这种情况下不起作用.我正在调用的库代码使用它在实例初始化时检索的加载器getClass().getClassLoader().
当我设置URLClassLoader时,该类尚未初始化,所以我猜contextClassLoader不加载该类.
我是否正确理解了答案?是否可以使用URLClassLoader加载第三方类?
使用类似ASMor 的库cglib,有没有办法在每次设置类字段的值时将字节码指令添加到类中以执行代码?
例如,假设我有这个类:
public class Person
{
bool dirty;
public String name;
public Date birthDate;
public double salary;
}
Run Code Online (Sandbox Code Playgroud)
假设一段代码包含以下行:
person.name = "Joe";
我希望拦截此指令,以便将dirty标志设置为true.我知道这对于setter方法是可行的person.setName (“Joe”)- 因为类方法可以通过字节码操作来修改,但我想对字段做同样的事情.
这是可能的,如果是的话,怎么样?
编辑
我想避免修改访问类的代码部分,我正在寻找一种方法来将拦截代码作为Person类的一部分.是否存在用于字段访问的伪方法,类似于Python类中的属性?
如果我想使用字节码检测实现分析器,我应该使用JVMTI编写本机代理还是应该使用该包编写java代理?java.lang.instrument
如果我想使用像ASM这样的库- 如果你想创建一个严肃的探查器似乎是强制性的 - 我必须使用java代理.这使我感到困惑,因为我认为本机代理可以完成Java代理可以做的所有事情.但对我来说,编写java代理似乎更容易.
还有替代品吗?是否应该使用java代理和本地代理组合?
我正在使用ASM来监视Java中的对象创建.目前,我将调用init作为创建新对象的指示器并从中调整程序
invoke XXX.init
Run Code Online (Sandbox Code Playgroud)
至
dup;
invoke XXX.init;
call_my_method(Object)
Run Code Online (Sandbox Code Playgroud)
我的想法是复制newObjectReference的副本,并且在此对象的init之后,我调用我的方法来保留此对象.
但是,在运行时期间,有一个例外:
java.lang.VerifyError, Expecting to find unitialized object on stack.
Run Code Online (Sandbox Code Playgroud)
当我使用"-noverify"选项时,在运行时,如果有一个线程实例,则抛出第二个异常:
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at test.ThreadTest.test
Run Code Online (Sandbox Code Playgroud)
对于第二种情况,我确信除了原始程序之外,没有调用线程的start().
有没有更好的方法来监控新对象的创建?
非常感谢.
我在使用Guava库运行一个简单的主程序时遇到了一些麻烦.
我已经使用我的代码从类中检测了类以获取方法参数:ASM中的Java方法参数值
问题是,虽然代码适用于小型项目(也就是河内之塔),但是使用Guava我有错误和例外.
特别是,在测试Joiner.join方法时,我有这个错误:
Exception in thread "Jalen Agent" java.lang.VerifyError: (class: com/google/common/base/Joiner, method: withKeyValueSeparator signature: (Ljava/lang/String;)Lcom/google/common/base/Joiner$MapJoiner;) Incompatible argument to function
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)
Run Code Online (Sandbox Code Playgroud)
当使用-noverify运行示例时,我有一个例外:
Exception in thread "Jalen Agent" java.lang.ArrayIndexOutOfBoundsException: 1
at com.google.common.base.Joiner.<init>(Joiner.java)
at com.google.common.base.Joiner.on(Joiner.java:71)
at Main.joinBench(Main.java:42)
at Main.main(Main.java:20)
Run Code Online (Sandbox Code Playgroud)
该方法的字节码是一致的:
public static com.google.common.base.Joiner on(java.lang.String);
Code:
0: bipush 1
2: anewarray #4 // class java/lang/Object
5: astore_1
6: aload_1
7: bipush 0
9: aload_0
10: aastore
11: ldc #20 // int 369
13: ldc #21 // String com/google/common/base/Joiner
15: …Run Code Online (Sandbox Code Playgroud) java bytecode bytecode-manipulation verifyerror java-bytecode-asm
是否可以在编译时使用像ASM这样的字节码操作库?
具体来说,我想使用Java的注释处理API在带注释的类上实现样板重的方法.实现注释处理器很简单,但运行时似乎.class文件尚不存在Processor.还有另外一种方法吗?
[TL; DR:以下JVM字节码指令似乎不起作用:
iconst_0
istore 6
...sequential
iinc 6 1
jsr L42
...
; L42
iload 6
ifeq L53 ; Always branches!!!
astore 8
iinc 6 -1
; L53
LDC 100
ISUB ; ERROR, returnAddress is at the top of the stack
Run Code Online (Sandbox Code Playgroud)
可以在此处找到测试.class (具有稍微复杂的逻辑)。如果您想进一步了解为什么我会看到这些说明,请继续阅读。]
我正在编写针对JVM字节码的Whitespace编译器。尽管是一种深奥的语言,但是Whitespace向堆栈计算机描述了一组有趣的汇编指令,该堆栈计算机很好地映射到了JVM。
空格具有标签,它们都是跳转(goto / jump-if-zero / jump-if-negative)和函数调用的目标。相关说明(由我给定的名称,在规范中以空格,制表符和换行符的组合形式给出)为:
mark <label>:为以下说明设置标签jump[-if-neg|-if-zero] <label>:无条件或有条件地跳转到给定标签call <label>:调用标签所指向的函数end <label>:结束功能,返回到调用方。我的编译器以类的main方法输出整个Whitespace程序。实现call和的最简单方法end是使用JSR和RET操作码,用于实现子例程。JSR操作完成后,堆栈将包含一个returnAddress引用,该引用应存储在变量中,以供以后在中使用end。
但是,mark …
目前可以使用代理运行JVM:
-javaagent:somejar.jar
Run Code Online (Sandbox Code Playgroud)
这种方式为了运行我写的Java代理,我必须将它放入jar中.因此它在调试方面受到限制.是否有一种在IDE中调试Java代理并将其附加到JVM的技术?
defineClass(className, byte[], offset, length)。new CustomClassLoader(Thread.currentThread().getContextClassLoader())。因此,CustomClassLoader的父级是当前线程中的ClassLoader。Thread.currentThread().setContextClassLoader()用CustomClassLoader 设置了。Class.forName(String, true, the CustomClassLoader)。我怎么了?如果您需要更多信息,请在我的GitHub上找到详细的主题。
该JVMS在第4.7.26规定的是:
ModulePackages属性指示Module属性导出或打开的模块的所有包,以及Module属性中记录的服务实现的所有包.ModulePackages属性还可以指示模块中既不导出也不打开也不包含服务实现的包.
何时在未导出或打开时添加此类包是否有意义?我看不出Java编译器是这样添加包的.
我偶然发现了这一点,因为ASM也提供了一种ModuleVisitor::visitPackage方法.
java ×8
bytecode ×4
jvm ×3
classloader ×2
classpath ×1
compilation ×1
javaagents ×1
jvmti ×1
superclass ×1
verifyerror ×1