Добавление проверки нулевого объекта в байт-код JVM

avatar
knt5784
8 апреля 2018 в 03:47
314
1
0

Я использую ASM для изменения байт-кода любого класса Java, чтобы добавить проверку нуля для каждого объекта.

Например, для этого фрагмента кода:

Object a = new Object();
a.doSomething();

Я хочу изменить байт-код, чтобы он выглядел так:

Object a = new Object();
assertNotNull(a);
a.doSomething();

или это:

Object a = new Object();
if(a != null){
a.doSomething();}
else return 1 //or throw exception

Я застрял, потому что не знаю, какое число следует за ALOAD. Я думаю, что ALOAD всегда идет с ALOAD 1 (или в этом формате ALOAD n). Что я могу сделать, чтобы получить номер, который идет с ALOAD? Вот моя работа (с использованием Junit assertNotNull)

/*
 * Use JUnit assertNotNull to check object/item for null
 */
private void addAssertNullMethod() {
    //need to add ALOAD here, but I don't know the location of the object on the stack.
    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/junit/Assert", "assertNull", "(Ljava/lang/Object;)V", false);
    mv.visitEnd();
}
Источник
Holger
9 апреля 2018 в 08:23
0

Вы не показали логику своей программы, чтобы решить, когда вызывать addAssertNullMethod(). Когда вы вызываете его прямо перед доступом другого члена, применяется ответ апангина, значение будет в стеке операндов. Но независимо от того, где вы его вызываете, вызов mv.visitEnd(); в середине метода никогда не будет правильным. И, кстати, я не могу понять назначение этой аппаратуры. Вы просто заменяете NullPointerException другим исключением. Кроме того, ваш «assertNotNull» в тексте вашего вопроса стал assertNull в коде…

Ответы (1)

avatar
apangin
8 апреля 2018 в 06:39
1

Вместо этого вам нужен байт-код DUP.

ALOAD относится к локальным переменным, но для данного объекта не может быть назначен слот локальной переменной. Перед вызовом doSomething() в стек выражений уже помещается ссылка на объект (с байт-кодом ALOAD или каким-то другим — не важно). Итак, все, что вам нужно, это скопировать эту ссылку на объект (с DUP), а затем вызвать ваш метод assert.