alibaba / alibaba/fastjson2

[BUG]

Open Beginner friendly
#7,646 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Java
Stars
4.4k
Forks
613
Avg merge
1d 22h
Merged PRs (30d)
6

Description

### 问题描述

`JSON.parseObject(String)` 解析含超长字符串字段的 JSON 时,`JSONReaderUTF16.readString()` 中实例级重用缓冲区 `strBuf` 未做容量检查,导致 `System.arraycopy` 越界抛出 `ArrayIndexOutOfBoundsException`。

### 环境信息

- OS信息: macOS 14.2 (M1 pro)
- JDK信息: Openjdk 21
- 版本信息: Fastjson2 2.0.61

### 重现步骤

1. 构造如下 JSON,其中包含两个关键字段:
- `attachment`:值为含 `\"` 转义的短字符串(在 `readString()` 中首次分配 `strBuf = char[512]`)
- `noticeDetails`:值为超长富文本(>2000字符)且中间含 `\"` 转义
2. 调用 `JSON.parseObject(jsonString)` 解析
3. 解析到 `noticeDetails` 字段时,`stroff=2328 > strBuf.length=512`,`System.arraycopy` 越界

```java
// 测试代码
public class Test {
public static void main(String[] args) throws Exception {
String jsonString = new String(Files.readAllBytes(Paths.get("/path/to/json内容.json")));
JSONObject jsonObject = JSON.parseObject(jsonString);
System.out.println(jsonObject);
}
}
```

测试 JSON 结构:
```json
{
"attachment" : "{\"files\":[{\"code\":\"200\",\"contentType\":\"application/msword\",\"id\":\"***ENCRYPTED_ID***\",\"name\":\"3岁以下婴幼儿健康养育照护指南(试行).doc\",\"url\":\"v1/file-store/download/***ENCRYPTED***\",\"size\":\"***ENCRYPTED***\"}],\"notes\":\"\",\"attachmentItemMapping\":\"\"}",
"noticeDetails" : "

***脱敏-机构名称***资产管***有限公司(以下简称“招租方”)对:***脱敏-城市***市城投江南新城2#楼(***脱敏-城市***市城投)【 10层 ***脱敏-面积***㎡ ***脱敏-城市***市城投(延时的除外)在阿里资产平台进行公开进行,现就有关事项公告如下:
注:2025年4月7日10时起至2025年4月8日10时止(延时的除外)期间,此竞价入口为唯一指定入口!通过其他竞价平台报名或参与竞价均视为无效操作。
一、招租房产:***脱敏-城市***市江南新城华创产业园2#楼(人才公寓)【 10层 ***脱敏-面积***㎡ 】 、【 11层***脱敏-面积***㎡ 】房屋租赁。
起租价:***脱敏-金额***元/年,保证金:***脱敏-金额***元,加价幅度:***脱敏-金额***元或整倍数,租赁期限:***脱敏-年限***年 ,租金支付方式:一年一付,履约保证金:***脱敏-金额***元,房产用途:以《租赁合同》为准,是否可以联合承租:否。
二、房产概况:***脱敏-城市***市江南新城华创产业园2#楼(人才公寓)【 10层 ***脱敏-面积***㎡ 】 、【 11层***脱敏-面积***㎡ 】房屋。房屋建筑面积:***脱敏-面积***㎡,权利性质:国有,用途:其他,房屋结构:混合,租赁情况:闲置,抵押情况:未知。
三、特别告知:
1.房屋按现状出租,出租前的水、电、物业、包烧等一切费用由招租方当场结清,承租期间的水、电、包烧等一切费用由承租人承担并按实结算。target=\"_blank\">"
}
```

### 期待的正确结果

正常解析完成,不抛出异常。

### 相关日志输出

```
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: arraycopy: last destination index 2328 out of bounds for char[512]
at java.base/java.lang.System.arraycopy(Native Method)
at com.alibaba.fastjson2.JSONReaderUTF16.readString(JSONReaderUTF16.java:3259)
at com.alibaba.fastjson2.JSONReader.read(JSONReader.java:3544)
at com.alibaba.fastjson2.JSON.parseObject(JSON.java:476)
at com.bosssoft.asset.Test.main(Test.java:18)
```

### 根因分析

`JSONReaderUTF16.readString()` 第 3254-3259 行:

```java
char[] strBuf = this.strBuf;
if (strBuf == null) {
strBuf = new char[stroff + 512];
this.strBuf = strBuf;
}
System.arraycopy(chars, start, strBuf, 0, stroff); // 缺少容量校验
```

`strBuf` 是实例级重用缓冲区。当处理 `attachment` 这样含 `\` 的短字段时,`stroff` 很小(如 0),分配 `char[512]`。后续处理 `noticeDetails` 这样含 `\` 的超长字段时,快速扫描已累积 `stroff=2328`,但 `strBuf` 非 null 不会重新分配,`arraycopy` 直接将 2328 个字符写入 `char[512]` 导致越界。

**修复方案**:在 `System.arraycopy` 前增加 `strBuf` 容量检查:

```java
char[] strBuf = this.strBuf;
if (strBuf == null || stroff > strBuf.length) {
strBuf = new char[Math.max(stroff + 512, strBuf.length * 2)];
this.strBuf = strBuf;
}
System.arraycopy(chars, start, strBuf, 0, stroff);
```

### 附加信息

- 使用 `JSON.parseObject(byte[])`(如 `Files.readAllBytes`)可绕过此问题,因 `byte` 路径使用 `JSONReaderUTF8`,不受 `JSONReaderUTF16.strBuf` 影响

Contributor guide

Open the contributing guide

Research direction

Start at JSONReaderUTF16.readString() around lines 3254-3259 and reproduce the failure through JSON.parseObject(String) using the two-field JSON example. Verify the existing UTF16 path handles a later escaped, over-2000-character field after a shorter escaped field without throwing ArrayIndexOutOfBoundsException; completion is successful parsing of that input.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.