[BUG] JSON.parse("\"\\")` 在 UTF16 reader 中抛出 `ArrayIndexOutOfBoundsException
- 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
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