是否可以使用检测重新定义核心JDK类?

时间:2014-09-16 01:34:44

标签: java jvm stack-overflow bytecode instrumentation

我想重新定义StackOverflowError构造函数的字节码,以便在发生堆栈溢出时有一个“挂钩”。我想要做的就是在构造函数的开头插入一个方法调用到我选择的静态方法。有可能这样做吗?

3 个答案:

答案 0 :(得分:2)

您应该能够使用以下两种方式中的一种方式(除非在过去的1 - 2年内发生了变化,在这种情况下,我喜欢一些指向更改日志/文档的链接):

  1. 在评论中提到,我认为不太可行,修改你感兴趣的类,将它们放在一个jar中,然后使用-bootclasspath选项加载它们而不是默认的。如前所述,这可能会产生一些法律问题(一般来说都很痛苦)。

  2. 你应该能够(或者至少你曾经能够)instrument几乎所有的核心课程(iirc Class是我见过的唯一例外)。您可能遇到的许多问题之一是,在您提供的代理(或者他们的premain方法确切)被咨询之前,许多核心类正在初始化。为了解决这个问题,你必须将Can-Retransform-Classes属性添加到你的代理jar中,然后重新转换你感兴趣的类。请注意,重新转换的功能稍微强一点,并不能给你所有您通常使用仪器的选项,您可以在文档中阅读更多相关信息。

  3. 我假设你知道怎么做仪器?

答案 1 :(得分:1)

有几件事需要考虑。

  • 可以重新定义java.lang.StackOverflowError。我在1.7.0_40上成功尝试了。 isModifiableClass(java.lang.StackOverflowError.class)返回true并成功重新定义了将方法调用插入其所有构造函数中
  • 您应该知道,当您通过Instrumentation将方法调用插入类时,您仍然必须遵守ClassLoader关系强加的可见性。由于StackOverflowError由引导加载程序加载,因此它只能调用引导加载程序加载的类的方法。你必须add the target method’s class(es) to the bootstrap loader
  • 如果应用程序的代码throwStackOverflowError手动,则此方法有效。但是,当发生真正的堆栈溢出时,JVM最后要做的就是调用其他方法(记住错误说的是,堆栈已满)。因此,它创建StackOverflowError的实例而不调用其构造函数(JVM可以这样做)。所以在这种情况下你的仪器毫无意义。
  • 正如其他人已经指出的那样,“纯Java应用程序”不能依赖于修改后的JRE类。仅将Instrumentation用作附件(即开发或JVM管理工具)才有效。您应该记住,Oracle的JVM 1.7.0_40支持重新定义StackOverflowError的事实并不意味着其他版本或其他JVM也可以这样做。

答案 2 :(得分:0)

您无法在java。*中重新定义任何内容,否则您将获得SecurityException。您可以通过修改环境(安全策略和自定义运行时类)在某种程度上解决这个问题,但我建议不要搞乱它。

话虽如此,如果堆栈已被溢出/删除,您如何调用您的方法?你将不得不使用一些JNI伏都教来获得你想要的东西。另外,为什么只是抓住它不适合你?你究竟想要从抛出/传播后无法得到的异常中“获得”什么?