alibaba / alibaba/fastjson2

[BUG] JSON.parse("\"\\")` 在 UTF16 reader 中抛出 `ArrayIndexOutOfBoundsException

Open Beginner friendly
#7,790 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 字符串以反斜杠结尾、转义序列被截断时,`JSONReaderUTF16.readString` 会读取到缓冲区末尾之外,抛出 `ArrayIndexOutOfBoundsException`。

该异常不是 `JSONException` 的子类,因此调用方使用 `catch (JSONException)` 无法捕获。本应作为非法 JSON 处理的输入可能直接穿透业务异常处理,在服务端产生 500 响应。

同一输入通过 UTF8 reader 解析时会正确抛出 `JSONException`,两个 reader 的行为不一致。

### 环境信息

- OS信息:Ubuntu 20.04.6 LTS
- JDK信息:Java 8
- 版本信息:Fastjson2 2.0.64

### 重现步骤

1. 使用 `JSON.parse(String)` 解析字符串。
2. 输入由双引号和反斜杠组成的两个字符,即 JSON 文本 ``"\``。
3. UTF16 reader 抛出 `ArrayIndexOutOfBoundsException`。

```java
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;

import java.nio.charset.StandardCharsets;

public class Repro {
public static void main(String[] args) {
String input = "\"\\";

try {
JSON.parse(input);
} catch (JSONException error) {
// 实际无法捕获,因为抛出的是 ArrayIndexOutOfBoundsException
System.out.println("invalid JSON");
}

JSON.parse(input.getBytes(StandardCharsets.UTF_8));
// UTF8 reader 会正确抛出 JSONException
}
}
```

以下输入均可以复现:

| 输入(JSON 文本) | `JSON.parse(String)`(UTF16) | `JSON.parse(byte[])`(UTF8) |
|---|---|---|
| ``"\`` | `ArrayIndexOutOfBoundsException` | `JSONException` |
| ``{"a":"\`` | `ArrayIndexOutOfBoundsException` | `JSONException` |
| ``["\`` | `ArrayIndexOutOfBoundsException` | `JSONException` |
| ``"ab\`` | `ArrayIndexOutOfBoundsException` | `JSONException` |

另外,校验接口已经能够正确识别该输入非法:

```java
JSON.isValid("\"\\"); // false
JSON.parse("\"\\"); // ArrayIndexOutOfBoundsException
```

### 期待的正确结果

对于末尾转义序列被截断的非法 JSON,`JSON.parse(String)` 应抛出 `JSONException`,与 UTF8 reader 以及其他畸形输入的行为保持一致,不应暴露底层的 `ArrayIndexOutOfBoundsException`。

### 相关日志输出

```text
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at com.alibaba.fastjson2.JSONReaderUTF16.readString(JSONReaderUTF16.java:3287)
```

#### 附加信息

`JSONReaderUTF16.readString` 在处理反斜杠时直接递增下标并读取下一个字符:

```java
if (c == '\\') {
c = chars[++offset];
// ...
}
```

当反斜杠位于输入末尾时,递增后的 `offset` 等于 `end`,随后访问 `chars[offset]` 导致越界。建议在读取转义字符前检查 `offset == end`,并抛出 `JSONException`。

同一方法中的 `\u`、`\x` 截断分支已经存在类似的边界检查,例如 `"\u`、`"\u1` 和 `"\uD80` 均会正确抛出 `JSONException`;只有简单转义在末尾被截断时缺少检查。

Contributor guide

Open the contributing guide

Research direction

Start in JSONReaderUTF16.readString at JSONReaderUTF16.java:3287 and compare its truncated simple-escape handling with the UTF8 reader and existing \u/\x boundary checks. Add a regression test for a trailing backslash in JSON.parse(String), then run the relevant parser tests; done means it throws JSONException rather than ArrayIndexOutOfBoundsException and remains consistent with UTF8 parsing.

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
Active
Clarity
Clearly specified
Newbie friendliness
82/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.