Skip to content
This repository was archived by the owner on Oct 23, 2024. It is now read-only.
This repository was archived by the owner on Oct 23, 2024. It is now read-only.

(已提供可复现的源码,求fix)fastjson无法反序列化超出某种限制的类 #2779

@zhaiyao

Description

@zhaiyao

几点说明:

  1. 我所在的项目密级很高,所以我需要项目相关的信息打码,抱歉更无法提供项目源码(更新,已经提供了一份脱敏的源码)
  2. 我会尽量用描述的方式描述清楚问题,并给出自己的分析过程

环境:
java 8
fastjson 1.2.61(1.2.58也试过)

背景:
我们有一个类SkDto.java,这个类的字段比较多,且含有一些内部static类。而且我们用lombok标注它。
我们用这种方式跑单测:
str = "{}"; // 原始值不是{},此处简化下,因为{}也能复现
SkDto skDto= JSON.parseObject(str, SkDto.class);

在一次升级之后,我们增加了几个字段之后,这一行代码无法通过单测。
报错是:
testcase XXXXXXXXXXXXXXX > testDTO: java.lang.VerifyError: (class: com/alibaba/fastjson/parser/deserializer/FastjsonASMDeserializer_4_SkDTO, method: deserialze signature: (Lcom/alibaba/fastjson/parser/DefaultJSONParser;Ljava/lang/reflect/Type;Ljava/lang/Object;I)Ljava/lang/Object;) Illegal target of jump or branch

我们给SkDTO.java删字段,发现删除long类型的一个成员变量之后,仍然无法工作。但是删除一个Arraylist类型的成员变量 或者随便多删除几个成员变量之后,即可工作。所以猜测我们是超出了某个大小限制,只有把类缩减到这个限制以下之后,才能工作。
这个限制不是简单的数量限制,因为删除一个long类型的成员变量 和删除一个Arraylist类型的成员变量 的结果不同。

开始验证猜测:

分别打开两个IDE,一个IDE用有问题的SkDTO.java,一个IDE用“删除一个Arraylist类型的成员变量 ”之后的SkDTO.java。

JSON.java 560行:return parseObject(text, clazz, new Feature[0]);
调用了

JSON.java 383行:T value = (T) parser.parseObject(clazz, null);
调用了

DefaultJSONParser.java 673行: ObjectDeserializer deserializer = config.getDeserializer(type);
调用了

ParseConfig.java 411行:return getDeserializer((Class<?>) type, type);
调用了
ParseConfig.java 678行:deserializer = createJavaBeanDeserializer(clazz, type);
调用了

ParseConfig.java 840行:return asmFactory.createJavaBeanDeserializer(this, beanInfo);
调用了

ASMDeserializerFactory.java 89-90行:
Class deserClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length); Constructor constructor = deserClass.getConstructor(ParserConfig.class, JavaBeanInfo.class);

在此之前,两个IDE的debug都看不出来明显区别,在这里出现了完全不同的反应:

其中一个IDE在90行抛出了异常。

分别在两个IDE的第90行打断点:
比较两个class,发现两个ASM类有明显不同,一个有构造函数,一个没有:
2
看构造的过程,都是ClassLoader的,唯一区别就是传入的参数:
3

本行之上都是描述事实,本行之下是猜想内容:

  1. 当类大小比较大的时候,或者触发了某个条件,ASM生成的字节码不正常。
  2. 当一个类的大小超过64K时候,用protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)生成的类和ASMSerializerFactory配合的不好;

我查了不少资料,我和这位朋友的状态非常相似:
#1207

和这个帖子里面的评论的朋友也有一些相似,但是不完全相同:
#1092
我的症状是只能减字段才能解决,不能加字段;他的症状是增减字段都能解决

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions