24 MagicAccessorImpl can access the debugging of all methods

preface

I saw an article before java reflection calls private related 

A screenshot of the boss inside shows why the generated method accessor generated at runtime can access all methods

Hehe, to tell you the truth, this problem has not been considered before

However, the screenshot of the boss is still a little abstract and is not connected with the context of the specific runtime

Hehe, this article will sort out these things

This article mainly takes reflection call} as an example to walk through the general process

There are some basic articles about recurse that can be referred to

21 process of method invocation (invokestatic as an example)

14 debugging of compilation and execution of HelloWorld bytecode

15 stack frame information of main method

07 rewrite of runtime constant pool index

The following code, screenshot based on jdk9

test case

package com.hx.test05;

import com.hx.test03.Test26MethodOrder;

import java.lang.reflect.Method;

/**
 * GenerateMethodAccessor
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2020-04-25 19:17
 */
public class Test16GenerateMethodAccessor {

  // Test16GenerateMethodAccessor
  public static void main(String[] args) throws Exception {

    Method method = Test26MethodOrder.class.getDeclaredMethod("func008");
    method.setAccessible(true);
    for(int i=0; i<=16; i++) {
      method.invoke(null);
    }

  }

}

Test26MethodOrder.func008 is as follows

  // funcN
  private static int counter = 0;
  private static void func008() {
    System.out.println(counter++);
    if((counter == 16) || (counter == 17)) {
      Test25SynchronizeObject.doClone(new Test25SynchronizeObject());
    }
  }

clion based debugging

First, in Reflection::verify_class_access, Reflection::verify_ field_ Make a breakpoint in access

In JVM cpp JVM_ Put a breakpoint on clone

1. Then there will be hit with two or three breakpoints, which has been mentioned here

These two checks_ klass_ Accessibility mainly comes from {nativemethodaccessorimpl Invoke accesses these two classes, and then triggers class loading, verification, and so on. These two checks_ klass_ Accessibility is not that important for this article

p ((Method*)0x010f1c2f78)->print()
{method}
 - this oop:          0x000000010f1c2f78
 - method holder:     'jdk/internal/reflect/NativeMethodAccessorImpl'
 - constants:         0x000000010f1c2a18 constant pool [97] {0x000000010f1c2a18} for 'jdk/internal/reflect/NativeMethodAccessorImpl' cache=0x000000010f1c3170
 - access:            0x1  public 
 - name:              'invoke'
 - signature:         '(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;'
 - max stack:         8
 - max locals:        4
 - size of params:    3
 - method size:       11
 - vtable index:      5
 - i2i entry:         0x000000011302b700
 - adapters:          AHE@0x00007fa181041690: 0xbbb00000 i2c: 0x00000001131d37e0 c2i: 0x00000001131d3922 c2iUV: 0x00000001131d38f5
 - compiled entry     0x00000001131d3922
 - code size:         104
 - code start:        0x000000010f1c2ec0
 - code end (excl):   0x000000010f1c2f28
 - checked ex length: 2
 - checked ex start:  0x000000010f1c2f72
 - linenumber start:  0x000000010f1c2f28
 - localvar length:   4
 - localvar start:    0x000000010f1c2f40

2. Another verification comes from verifying whether the parent class can be accessed when loading after the GeneratedMethodAccessor1 is created

3. Then there are two more verifications. When creating the GeneratedMethodAccessor1 instance, you need to access the parent class and its constructor

4. Then the breakpoint comes to the} JVM_ Inside clone

This is test26methodorder Counter in func008 = = 16 breakpoint entered by condition

 
p obj()->print()
com.hx.test04.Test25SynchronizeObject 
{0x00000007bfb6f6b8} - klass: 'com/hx/test04/Test25SynchronizeObject'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x00000007bfb6f6e0} (f7f6dedc 0)

5. Then, generate methodaccessor1 needs to access test26methodorder Relevant verification of func008

These two verify_ class_ access, verify_ field_ One is to ensure access to Test26MethodOrder, and the other is to ensure access to Test26MethodOrder func008 

This corresponds to 21 process of method invocation (invokestatic as an example) Load relevant classes and methods, replace the symbolic reference in the constant pool with a direct reference, and some preparation work related to calling methods

6. The last breakpoint is test26methodorder counter == 17 in func008 = breakpoint of condition entry

p obj()->print()
com.hx.test04.Test25SynchronizeObject 
{0x00000007bfb6f7d8} - klass: 'com/hx/test04/Test25SynchronizeObject'
 - ---- fields (total size 5 words):
 - 'f01' 'I' @12  0
 - 'f02' 'I' @16  0
 - 'f03' 'I' @20  0
 - 'f04' 'I' @24  0
 - 'f05' 'I' @28  0
 - private 'identStr' 'Ljava/lang/String;' @32  "xyz"{0x00000007bfb6f6e0} (f7f6dedc 0)

Take a look at the breakpoints above

The first four breakpoints are in the related business processing of {NativeMethodAccessorImpl

The last two breakpoints are triggered in the generated method accessor1

Why can {MagicAccessorImpl access all classes and methods

LinkResolver::resolve_ index in invoke?

As shown in the figure below, the # generated methodaccessor1 accesses # test26methodorder Analysis triggered when func008

Hehe, shit, isn't invokestatic followed by a MethodRef index?, Why is it so big?  

Where the index is obtained, you can see that the original index should be 0, but the actual pass through is 65536

About CP_CACHE_INDEX_TAG is defined as follows

When debugging in the program, CPCACHE_INDEX_TAG shows 0, but the real use is 0x10000. Hehe, I don't know if it's a bug

Then, if such a large index is passed, how to calculate the index in the constant pool corresponding to the operand in the future?  

Attach the constant pool information of # generated methodaccessor1

{constant pool}
 - holder: 0x00000007c0098430
 - cache: 0x000000011200e5c8
 - resolved_references: 0x0000000000000000
 - reference_map: 0x0000000000000000
 -   1 : Utf8 : 'jdk/internal/reflect/GeneratedMethodAccessor1'
 -   2 : Unresolved Class : 'jdk/internal/reflect/GeneratedMethodAccessor1'
 -   3 : Utf8 : 'jdk/internal/reflect/MethodAccessorImpl'
 -   4 : Class : 'jdk/internal/reflect/MethodAccessorImpl' {0x00000007c0009b18}
 -   5 : Utf8 : 'com/hx/test03/Test26MethodOrder'
 -   6 : Unresolved Class : 'com/hx/test03/Test26MethodOrder'
 -   7 : Utf8 : 'func008'
 -   8 : Utf8 : '()V'
 -   9 : NameAndType : name_index=7 signature_index=8
 -  10 : Method : klass_index=6 name_and_type_index=9
 -  11 : Utf8 : 'invoke'
 -  12 : Utf8 : '(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;'
 -  13 : Utf8 : 'java/lang/Throwable'
 -  14 : Unresolved Class : 'java/lang/Throwable'
 -  15 : Utf8 : 'java/lang/ClassCastException'
 -  16 : Unresolved Class : 'java/lang/ClassCastException'
 -  17 : Utf8 : 'java/lang/NullPointerException'
 -  18 : Unresolved Class : 'java/lang/NullPointerException'
 -  19 : Utf8 : 'java/lang/IllegalArgumentException'
 -  20 : Unresolved Class : 'java/lang/IllegalArgumentException'
 -  21 : Utf8 : 'java/lang/reflect/InvocationTargetException'
 -  22 : Unresolved Class : 'java/lang/reflect/InvocationTargetException'
 -  23 : Utf8 : '<init>'
 -  24 : Utf8 : '()V'
 -  25 : NameAndType : name_index=23 signature_index=24
 -  26 : Method : klass_index=18 name_and_type_index=25
 -  27 : Method : klass_index=20 name_and_type_index=25
 -  28 : Utf8 : '(Ljava/lang/String;)V'
 -  29 : NameAndType : name_index=23 signature_index=28
 -  30 : Method : klass_index=20 name_and_type_index=29
 -  31 : Utf8 : '(Ljava/lang/Throwable;)V'
 -  32 : NameAndType : name_index=23 signature_index=31
 -  33 : Method : klass_index=22 name_and_type_index=32
 -  34 : Method : klass_index=4 name_and_type_index=25
 -  35 : Utf8 : 'java/lang/Object'
 -  36 : Unresolved Class : 'java/lang/Object'
 -  37 : Utf8 : 'toString'
 -  38 : Utf8 : '()Ljava/lang/String;'
 -  39 : NameAndType : name_index=37 signature_index=38
 -  40 : Method : klass_index=36 name_and_type_index=39
 -  41 : Utf8 : 'Code'
 -  42 : Utf8 : 'Exceptions'
 -  43 : Utf8 : 'valueOf'
 -  44 : Utf8 : 'java/lang/Boolean'
 -  45 : Unresolved Class : 'java/lang/Boolean'
 -  46 : Utf8 : '(Z)Ljava/lang/Boolean;'
 -  47 : NameAndType : name_index=43 signature_index=46
 -  48 : Method : klass_index=45 name_and_type_index=47
 -  49 : Utf8 : 'booleanValue'
 -  50 : Utf8 : '()Z'
 -  51 : NameAndType : name_index=49 signature_index=50
 -  52 : Method : klass_index=45 name_and_type_index=51
 -  53 : Utf8 : 'java/lang/Byte'
 -  54 : Unresolved Class : 'java/lang/Byte'
 -  55 : Utf8 : '(B)Ljava/lang/Byte;'
 -  56 : NameAndType : name_index=43 signature_index=55
 -  57 : Method : klass_index=54 name_and_type_index=56
 -  58 : Utf8 : 'byteValue'
 -  59 : Utf8 : '()B'
 -  60 : NameAndType : name_index=58 signature_index=59
 -  61 : Method : klass_index=54 name_and_type_index=60
 -  62 : Utf8 : 'java/lang/Character'
 -  63 : Unresolved Class : 'java/lang/Character'
 -  64 : Utf8 : '(C)Ljava/lang/Character;'
 -  65 : NameAndType : name_index=43 signature_index=64
 -  66 : Method : klass_index=63 name_and_type_index=65
 -  67 : Utf8 : 'charValue'
 -  68 : Utf8 : '()C'
 -  69 : NameAndType : name_index=67 signature_index=68
 -  70 : Method : klass_index=63 name_and_type_index=69
 -  71 : Utf8 : 'java/lang/Double'
 -  72 : Unresolved Class : 'java/lang/Double'
 -  73 : Utf8 : '(D)Ljava/lang/Double;'
 -  74 : NameAndType : name_index=43 signature_index=73
 -  75 : Method : klass_index=72 name_and_type_index=74
 -  76 : Utf8 : 'doubleValue'
 -  77 : Utf8 : '()D'
 -  78 : NameAndType : name_index=76 signature_index=77
 -  79 : Method : klass_index=72 name_and_type_index=78
 -  80 : Utf8 : 'java/lang/Float'
 -  81 : Unresolved Class : 'java/lang/Float'
 -  82 : Utf8 : '(F)Ljava/lang/Float;'
 -  83 : NameAndType : name_index=43 signature_index=82
 -  84 : Method : klass_index=81 name_and_type_index=83
 -  85 : Utf8 : 'floatValue'
 -  86 : Utf8 : '()F'
 -  87 : NameAndType : name_index=85 signature_index=86
 -  88 : Method : klass_index=81 name_and_type_index=87
 -  89 : Utf8 : 'java/lang/Integer'
 -  90 : Unresolved Class : 'java/lang/Integer'
 -  91 : Utf8 : '(I)Ljava/lang/Integer;'
 -  92 : NameAndType : name_index=43 signature_index=91
 -  93 : Method : klass_index=90 name_and_type_index=92
 -  94 : Utf8 : 'intValue'
 -  95 : Utf8 : '()I'
 -  96 : NameAndType : name_index=94 signature_index=95
 -  97 : Method : klass_index=90 name_and_type_index=96
 -  98 : Utf8 : 'java/lang/Long'
 -  99 : Unresolved Class : 'java/lang/Long'
 - 100 : Utf8 : '(J)Ljava/lang/Long;'
 - 101 : NameAndType : name_index=43 signature_index=100
 - 102 : Method : klass_index=99 name_and_type_index=101
 - 103 : Utf8 : 'longValue'
 - 104 : Utf8 : '()J'
 - 105 : NameAndType : name_index=103 signature_index=104
 - 106 : Method : klass_index=99 name_and_type_index=105
 - 107 : Utf8 : 'java/lang/Short'
 - 108 : Unresolved Class : 'java/lang/Short'
 - 109 : Utf8 : '(S)Ljava/lang/Short;'
 - 110 : NameAndType : name_index=43 signature_index=109
 - 111 : Method : klass_index=108 name_and_type_index=110
 - 112 : Utf8 : 'shortValue'
 - 113 : Utf8 : '()S'
 - 114 : NameAndType : name_index=112 signature_index=113
 - 115 : Method : klass_index=108 name_and_type_index=114

reference resources

java reflection calls private related

21 process of method invocation (invokestatic as an example)

14 debugging of compilation and execution of HelloWorld bytecode

15 stack frame information of main method

07 rewrite of runtime constant pool index

Keywords: Java

Added by lookee on Sat, 12 Feb 2022 13:47:14 +0200