侵入java.lang.Object:调用自定义外部类会使JVM崩溃
我正在为java运行时环境编辑java.lang.Object。我意识到可能有更好的方法来做我想做的事情,但这不是我的问题所在 基本上,我已经在java.lang.Object中添加了一个构造函数,每次创建对象时都会调用它。我正在等待某个类加载,如下所示:侵入java.lang.Object:调用自定义外部类会使JVM崩溃,jvm,java,Jvm,Java,我正在为java运行时环境编辑java.lang.Object。我意识到可能有更好的方法来做我想做的事情,但这不是我的问题所在 基本上,我已经在java.lang.Object中添加了一个构造函数,每次创建对象时都会调用它。我正在等待某个类加载,如下所示: public Object() { if (hookEnabled) { hookEnabled = false; objectCount++; if (objectCou
public Object() {
if (hookEnabled) {
hookEnabled = false;
objectCount++;
if (objectCount > objectStartCount) {
if (this.getClass() != null) {
String name = this.getClass().getName();
if ((!name.startsWith("java.")) && (!name.startsWith("javax.")) && (!name.startsWith("launcher.")) && (!name.startsWith("sunw.")) && (!name.startsWith("com.sun.")) && (!name.startsWith("sun.")) && (!name.startsWith("org.xml.")) && (!name.startsWith("org.w3c.")) && (!name.startsWith("org.omg.")) && (!name.startsWith("org.ietf."))) {
if (!hasHooked) {
hasHooked = true;
//startup beep
java.awt.Toolkit.getDefaultToolkit().beep();
//load interface
javax.swing.JFrame frame = new javax.swing.JFrame("");
frame.setBounds(0, 0, 400, 400);
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
}
}
}
hookEnabled = true;
}
}
这个很好用。它向JVM正在运行的任何应用程序添加一个窗口
但是,当通过将JFrame代码移动到单独的类中并调用该类进行简单更改时,JVM就会崩溃:
public Object() {
if (hookEnabled) {
hookEnabled = false;
objectCount++;
if (objectCount > objectStartCount) {
if (this.getClass() != null) {
String name = this.getClass().getName();
if ((!name.startsWith("java.")) && (!name.startsWith("javax.")) && (!name.startsWith("launcher.")) && (!name.startsWith("sunw.")) && (!name.startsWith("com.sun.")) && (!name.startsWith("sun.")) && (!name.startsWith("org.xml.")) && (!name.startsWith("org.w3c.")) && (!name.startsWith("org.omg.")) && (!name.startsWith("org.ietf."))) {
if (!hasHooked) {
hasHooked = true;
(new tvmh.DFVMH()).setup();
}
}
}
}
hookEnabled = true;
}
}
--
当我尝试创建java.util.Timer对象时也会发生同样的情况
非常有趣的是,如果我将DFVMH设置为java.lang.Object本身的内联类(内部类),上述方法确实有效
有人能告诉我为什么会发生这种行为吗?有没有办法安全地调用这样的自定义类?你说的“它崩溃”是什么意思 这不是StackOverflowException吗?您的
新的tvmh.DFVMH()
实际上也是一个构造函数。因此,它通过“重写”对象构造函数运行
如果您已经这样玩了,那么将
tvmh.DFVMH
添加到包/类的停止列表中如何?您所说的“it崩溃”是什么意思
这不是StackOverflowException吗?您的新的tvmh.DFVMH()
实际上也是一个构造函数。因此,它通过“重写”对象构造函数运行
如果您已经这样玩了,那么将
tvmh.DFVMH
添加到包/类的停止列表中如何?请快速思考:新建tvmh.DFVHM()
将成为一个新对象,它也派生自java.lang.object,这意味着您的自定义构造函数代码将在第一个完成之前再次运行。我猜“hasHooked”应该防止出现这种情况,但是这个变量是如何定义的呢?如果这个保护不起作用,这个序列将无限递归
如果将DFVMH设置为一个内联类,它的名称可能会以“java.lang[…]”开头(毕竟是在java.lang.Object中),因此不会使用所有的
名称.startsWith
快速思考:new tvmh.DFVHM()
成为一个新对象,它也派生自java.lang.Object,这意味着您的自定义构造函数代码将在第一个构造函数完成之前再次运行。我猜“hasHooked”应该防止出现这种情况,但是这个变量是如何定义的呢?如果这个保护不起作用,这个序列将无限递归
如果将DFVMH设为一个内联类,它的名称可能以“java.lang[…]”开头(毕竟是在java.lang.Object中),因此无法通过包含所有
name.startsWith
的长If语句对JVM的内部进行这样的修补是非常危险的。JVM的底层存在各种隐藏的依赖关系,这些依赖关系可能会中断。JVM引导是一个非常微妙的过程
例如,您看到崩溃而不是StackOverflowerError
的最可能原因是您的更改破坏了所有对象构造。。。包括错误对象的构造
我怀疑您的保护代码无效,因为this.getClass().getName()
可能导致创建字符串对象。所以致命的递归发生在你开始警惕之前
(顺便说一句,您的hasHooked
标志引入了竞争条件。)
我的建议是“不要这样做!”。像这样修补JVM的内部是非常危险的。JVM的底层存在各种隐藏的依赖关系,这些依赖关系可能会中断。JVM引导是一个非常微妙的过程 例如,您看到崩溃而不是
StackOverflowerError
的最可能原因是您的更改破坏了所有对象构造。。。包括错误对象的构造
我怀疑您的保护代码无效,因为this.getClass().getName()
可能导致创建字符串对象。所以致命的递归发生在你开始警惕之前
(顺便说一句,您的hasHooked
标志引入了竞争条件。)
我的建议是“不要这样做!”你为什么不用main(String[])方法编写一个新类来创建窗口,然后调用原来的窗口?@nhnb你能在回答中详细说明你的实际意思吗?对tvmh.DFVHM.someStaticMethod进行静态调用也会导致相同的行为。我很有兴趣学习如何做本主题中提到的事情。要了解这一点,我应该阅读哪些资源?为什么不使用main(String[])方法编写一个新类来创建窗口,然后调用原始窗口?@nhnb您能详细说明一下答案中的实际含义吗?对tvmh.DFVHM.someStaticMethod进行静态调用也会导致相同的行为。我很有兴趣学习如何做本主题中提到的事情。我应该阅读哪些资源来了解这一点?很有趣,但hasHooked怎么能不防范呢?这是一个静态变量。很有趣,但是hasHooked怎么能不防范呢?这是一个静态变量。我想我的静态hasHooked标志可以防止这种情况。我尝试添加tvmh。我想我的静态hasHooked标志可以防止这种情况。我尝试添加tvmh。这似乎没有效果。谢谢,我意识到这相当棘手。你能详细解释一下为什么它破坏了所有的对象结构吗?我已经稍微更新了我的代码(见原始帖子),以获得更好的防护机制,尽管同样的问题仍然存在。“你知道我能试试什么吗?”汤姆-我最好的建议是最后一句话。认真地不管你想在这里做什么。。。找到其他方法
package tvmh;
public class DFVMH {
public void setup() {
//startup beep
java.awt.Toolkit.getDefaultToolkit().beep();
//load interface
javax.swing.JFrame frame = new javax.swing.JFrame("");
frame.setBounds(0, 0, 400, 400);
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
}