2014-09-16 2 views
2

Я хочу переопределить байт-код конструктора StackOverflowError, поэтому у меня есть «крючок», когда происходит переполнение стека. Все, что я хочу сделать, это вставить один вызов метода статическому методу, выбранному мной в начале конструктора. Можно ли сделать это?Можно ли переопределить основные классы JDK с помощью инструментария?

+1

Возможно использование флага [-Xbootclasspath] (http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html), но лицензия говорит, что вы не можете распространять приложение, которое использует это для переопределения класса JRE. Так что пока вы не распространяете приложение ... – vanza

+0

@vanza, спасибо. Я определенно должен распространять его, хотя это не сработает. – 0xbe5077ed

ответ

2

Вы должны быть в состоянии сделать это, используя один из двух способов (если что-то изменилось в течение последних 1-2 лет, в этом случае я хотел бы некоторые ссылки на/DOCS списком изменений):

  1. Упомянутый в комментарии, не очень выполнимый, я думаю, измените интересующие вас классы, поместите их в банку, а затем используйте опцию -bootclasspath, чтобы загрузить их, а не по умолчанию. Как уже упоминалось, это может иметь некоторые юридические проблемы (и это боль вообще делать).

  2. Вы должны быть в состоянии (или, по крайней мере, быть в состоянии) instrument почти все основные классы (iirc Class - единственное исключение, которое я видел). Одна из многих проблем, которые могут возникнуть, заключается в том, что многие из основных классов инициализируются до того, как будут предоставлены агенты, которые вы предоставляете (или их методы premain). Чтобы преодолеть это, вам нужно добавить свойство Can-Retransform-Classes в ваш агент jar, а затем повторно преобразовать интересующие вас классы. Имейте в виду, что повторное преобразование немного менее мощное и не дает вам всех параметров, которые у вас есть. как правило, с помощью инструментария, вы можете больше узнать об этом в документе.

Я предполагаю, что вы знаете, как это сделать?

+0

Спасибо @Mateusz Dymczyk. У меня никогда не было инструментов. Я сделал генерацию байт-кода с ASM, поэтому я предполагаю, что это просто вопрос: получить байты класса, «эхо» их через ASM ClassReader/ClassVisitor, и когда вы нажмете на метод (ы), который хотите изменить, вставьте дополнительный метод звоните ... Я предполагаю, что можно модифицировать защищенные пакетом и частные методы таким образом? – 0xbe5077ed

+0

@ 0xbe5077ed: да, вы можете сделать это таким образом. – Holger

0

Вы не можете переопределить что-либо в java. *, Или вы получите SecurityException. Вы можете обойти это в некоторой степени, изменив среду (политика безопасности и пользовательские классы выполнения), но я бы посоветовал не вмешиваться в нее.

Как вы думаете, как вы думаете, может ли ваш метод вызываться, если стек уже переполнен/разбит? Вам нужно будет использовать некоторый вудский JNI, чтобы получить то, что вы хотите. Кроме того, почему просто ловить его не делает это для вас? Что именно вы пытаетесь «получить» от исключения, которое вы не можете получить после того, как оно будет выброшено/распространено?

+0

Я использую другой язык через JVM. Я хочу изучить живой стек до его разматывания. Я могу сделать это с помощью агента JVMTI, но такие агенты слишком общие: мне приходится слушать все исключения, большинство из которых меня не интересуют, что имеет большое потенциальное влияние на производительность. Что касается вызова метода, очевидно, можно «вызвать» конструктор 'StackOverflowError', а также [' Throwable.fillinStackTrace() '] (http://docs.oracle.com/javase/8/docs/api /java/lang/Throwable.html#fillInStackTrace--). – 0xbe5077ed

+0

, конечно, вы можете использовать основные классы ядра, там не будет никакого SecurityException ... Возможно, вам нужно будет поместить некоторые вещи в путь класса и/или выполнить '' 'retransformClasses()' '', хотя, поскольку большая часть ядра материал загружается до '' 'premain()' '' –

+0

Вы можете, конечно, использовать свой генерированный байт-код, чтобы отслеживать размер стека и вызывать функцию «предупреждение» на определенной отметке высокого уровня, поскольку вы уже генерируете это ... – BadZen

1

Есть несколько вещей, которые следует учитывать.

  • Можно переопределить java.lang.StackOverflowError. Я пробовал это успешно на 1.7.0_40. isModifiableClass(java.lang.StackOverflowError.class) возвращение true и я успешно переопределены это вставив вызов метода во всех своих конструкторах
  • Вы должны знать, что при вставке вызова метода в класс с помощью измерительных приборов вы все равно должны соблюдать видимость, налагаемых ClassLoader отношений. Поскольку StackOverflowError загружается загрузчиком загрузки, он может вызывать только вызовы классов, загружаемых загрузчиком загрузки. Вы должны были бы add the target method’s class(es) to the bootstrap loader
  • Это работает, если код приложения throw s a StackOverflowError вручную. Однако, когда происходит реальный поток stackoverflow, последнее, что JVM сделает, это вызвать дополнительные методы (помните, что говорит об ошибке, стек заполнена). Следовательно, он создает экземпляр StackOverflowError без вызова его конструктора (JVM может это сделать). Поэтому ваша аппаратура в этой ситуации бессмысленна.
  • Как уже указывалось другими, «Чистая Java-приложение» не должна полагаться на модифицированные классы JRE. В качестве дополнения можно использовать только Instrumentation, т. Е.разработки или инструмента управления JVM. Вы должны иметь в виду, что тот факт, что JVM Oracle 1.7.0_40 поддерживает переопределение StackOverflowError, не означает, что другие версии или другие JVM также работают.