首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在字节码级别,初始化java内部类的过程是什么?

在字节码级别,初始化java内部类的过程是什么?
EN

Stack Overflow用户
提问于 2020-08-02 21:58:09
回答 1查看 407关注 0票数 1

我编写了一个java代理来检测一个开源的基准测试commons-net。但我得到了以下错误:

代码语言:javascript
复制
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    org/apache/commons/net/util/SubnetUtils$SubnetInfo.<init>(Lorg/apache/commons/net/util/SubnetUtils;)V @9: invokestatic
  Reason:
    Type uninitializedThis (current frame, stack[2]) is not assignable to 'java/lang/Object'
  Current Frame:
    bci: @9
    flags: { flagThisUninit }
    locals: { uninitializedThis, 'org/apache/commons/net/util/SubnetUtils' }
    stack: { 'org/apache/commons/net/util/SubnetUtils', uninitializedThis, uninitializedThis }
  Bytecode:
    0x0000000: 12ca b800 cf2a 2b5f 59b8 00d3 5fb5 0002
    0x0000010: 2ab7 0003 b800 d6b1                    

    at...

代码语言:javascript
复制
Exception in thread "Thread-1" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    org/apache/commons/net/tftp/TFTPServer$TFTPTransfer.<init>(Lorg/apache/commons/net/tftp/TFTPServer;Lorg/apache/commons/net/tftp/TFTPPacket;)V @10: invokestatic
  Reason:
    Type uninitializedThis (current frame, stack[2]) is not assignable to 'java/lang/Object'
  Current Frame:
    bci: @10
    flags: { flagThisUninit }
    locals: { uninitializedThis, 'org/apache/commons/net/tftp/TFTPServer', 'org/apache/commons/net/tftp/TFTPPacket' }
    stack: { 'org/apache/commons/net/tftp/TFTPServer', uninitializedThis, uninitializedThis }
  Bytecode:
    0x0000000: 1301 84b8 0189 2a2b 5f59 b801 8d5f b500
    0x0000010: 012a b700 022a 035f 59b8 018d 5fb5 0003
    0x0000020: 2a01 5f59 b801 8d5f b500 042a 2c5f 59b8
    0x0000030: 018d 5fb5 0005 b801 90b1   

    at...

有趣的是,这两个错误都是在内部类中抛出的,并且堆栈框架非常相似。我猜这只是在初始化内部类时发生的,因为我在堆栈中看到了uninitializedThis

我的MethodVisitor适配器很长很复杂,所以我没有在这里发布它。我使用它来跟踪method_startmethod_endnew_objectobject_modifyPUTFIELDPUTSTATIC等事件。我需要通过调用我的方法之一的INVOKESTATIC来记录修改后的对象和新对象。我在NEW之后注释了插入的指令DUPINVOKESTATIC,但它仍然报告相同的错误。我想如果我知道内部类是如何初始化的,调试就会容易得多。

这两个<init>方法的源代码:

代码语言:javascript
复制
public class SubnetUtils {
    ...
    public final class SubnetInfo {
        /* Mask to convert unsigned int to a long (i.e. keep 32 bits) */
        private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL;

        private SubnetInfo() {}
        ...
    }
    ...
}
代码语言:javascript
复制
public class TFTPServer implements Runnable
{
    ...
    private class TFTPTransfer implements Runnable
    {
        private final TFTPPacket tftpPacket_;

        private boolean shutdownTransfer = false;

        TFTP transferTftp_ = null;

        public TFTPTransfer(TFTPPacket tftpPacket)
        {
            tftpPacket_ = tftpPacket;
        }
        ...
    }
    ...
}

我已经在我的MethodVisitor适配器类中找到了错误代码。我的意思是,当我注释这些代码时,错误似乎已经消失了。但是我仍然不知道为什么会发生这个错误。SubnetInfo的构造函数似乎没有修改任何字段的操作,我猜这可能是因为内部类初始化的一些隐藏功能?

代码语言:javascript
复制
    public void visitFieldInsn(int opc, String owner, String name, String desc){
        // Access Static Fields
        if ((opc == GETSTATIC || opc == PUTSTATIC) && shouldIncludeClass(owner)){
            mv.visitLdcInsn(owner);
            mv.visitMethodInsn(INVOKESTATIC, MyClass, MyMethod,
                    "(Ljava/lang/String;)V", false);
        }

        if (...){
            if (opc == PUTFIELD){
                Type t = Type.getType(desc);
                if (t.getSize() == 2){
                    mv.visitInsn(DUP2_X1);
                    mv.visitInsn(POP2);
                }else {
                    mv.visitInsn(SWAP);
                }
                mv.visitInsn(DUP);
                mv.visitMethodInsn(INVOKESTATIC, MyClass,
                        MyClass.TRACE_OBJ_MODIFY, "(Ljava/lang/Object;)V", false);
                if (t.getSize() == 2){
                    mv.visitInsn(DUP_X2);
                    mv.visitInsn(POP);
                }else {
                    mv.visitInsn(SWAP);
                }
            }else if (opc == PUTSTATIC){
                mv.visitMethodInsn(INVOKESTATIC, MyClass,
                        MyClass.TRACE_PUTSTATIC, "()V", false);
            }
        }
        mv.visitFieldInsn(opc, owner, name, desc);
    }

我在SubnetInfo的构造函数中只跟踪了一条PUTFIELD指令。在我的日志中:

代码语言:javascript
复制
Transform: org/apache/commons/net/util/SubnetUtils$SubnetInfo
**** PUTFIELD found ****
**** className org/apache/commons/net/util/SubnetUtils$SubnetInfo ****
**** methodName <init> ****
**** opc PUTFIELD ****
**** owner org/apache/commons/net/util/SubnetUtils$SubnetInfo ****
**** name this$0 ****
**** desc Lorg/apache/commons/net/util/SubnetUtils; ****

这条PUTFIELD指令是什么意思?是否将外部类的对象放到内部类的字段this$0中?有什么方法可以识别内部类的初始化吗?

EN

回答 1

Stack Overflow用户

发布于 2021-11-02 02:43:01

内部类将首先调用这个函数的初始化函数,与普通类不同,constructor.you必须在初始化操作后将其赋值给变量。

代码语言:javascript
复制
 public org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile(javax.servlet.http.Part, java.lang.String);
flags: ACC_PUBLIC
Code:
  stack=2, locals=3, args_size=3
     0: aload_0
     1: invokespecial #1                  // Method java/lang/Object."<init>":()V
     4: aload_0
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63216849

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档