使用ASM注入字节码时触发StringIndexOutOfBoundsException异常原因排查
解决ASM注入代码时的StringIndexOutOfBoundsException问题
这个异常的根源非常明确——你调用visitMethodInsn时传入的方法名字段是空字符串"",ASM在处理这个空字符串时,尝试访问它的第0个字符(用于内部语法校验或逻辑处理),直接触发了StringIndexOutOfBoundsException。
具体问题出在哪?
在JVM字节码规范里,所有类的构造方法在字节码层面的固定名称是<init>,而不是类名或者空字符串。你从ASMifier复制的代码里,所有构造方法调用的名字都被错误地写成了空字符串:
- SimpleDateFormat构造方法调用:
// 错误写法 mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", "", "(Ljava/lang/String;)V", false); - Date构造方法调用:
// 错误写法 mv.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "", "()V", false); - StringBuilder构造方法调用:
// 错误写法 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false);
这些空字符串是导致异常的直接原因——ASM内部会尝试解析方法名的结构,空字符串没有任何字符,自然会触发索引越界。
修正后的代码
把所有构造方法调用的名字改成<init>即可,修正后的关键代码片段如下:
// 初始化SimpleDateFormat mv.visitTypeInsn(NEW, "java/text/SimpleDateFormat"); mv.visitInsn(DUP); mv.visitLdcInsn("yyyy.MM.dd.HH.mm.ss"); // 修正:方法名改为<init> mv.visitMethodInsn(INVOKESPECIAL, "java/text/SimpleDateFormat", "<init>", "(Ljava/lang/String;)V", false); // 初始化Date mv.visitTypeInsn(NEW, "java/util/Date"); mv.visitInsn(DUP); // 修正:方法名改为<init> mv.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "<init>", "()V", false); // 初始化StringBuilder mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); // 修正:方法名改为<init> mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
为什么必须用<init>?
JVM要求所有构造方法的字节码名称必须是<init>,这是字节码层面的硬性规范。ASM作为字节码操作库,严格遵循这个规范,当你传入不符合要求的方法名(比如空字符串)时,内部的校验逻辑就会抛出异常。
修正这几处之后,你的注入代码应该就能正常执行,不会再触发这个索引越界异常了。
内容的提问来源于stack exchange,提问作者Emanuele
相关产品推荐
相关产品推荐

