Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON 解析中处理转义字符有问题导致崩溃 #9

Closed
dawndiy opened this issue Mar 27, 2018 · 1 comment
Closed

JSON 解析中处理转义字符有问题导致崩溃 #9

dawndiy opened this issue Mar 27, 2018 · 1 comment

Comments

@dawndiy
Copy link
Contributor

dawndiy commented Mar 27, 2018

问题

在特定的 JSON 文本环境,Ext 中 encoding/json 部分对转义字符处理实现有问题,会导致 go 的标准库 encoding/json 直接崩溃。特定环境是,当 JSON 文本的第 512 个字节刚好是 \ 的时候,会造成崩溃。因为我刚好遇到了 JSON 文本刚好第 512 个字节开始是 path 部分,如:\/v2ray.com

表现

v2ray -config test.json 
V2Ray 3.14 (die Commanderin) Custom
An unified platform for anti-censorship.
panic: runtime error: slice bounds out of range

goroutine 1 [running]:
encoding/json.(*Decoder).refill(0xc4201d0000, 0x22, 0x1)
        /usr/local/go/src/encoding/json/stream.go:160 +0x23f
encoding/json.(*Decoder).readValue(0xc4201d0000, 0x0, 0x0, 0xace560)
        /usr/local/go/src/encoding/json/stream.go:134 +0x23d
encoding/json.(*Decoder).Decode(0xc4201d0000, 0xa1cae0, 0xc4201ce000, 0xd0, 0xa83840)
        /usr/local/go/src/encoding/json/stream.go:63 +0x78
v2ray.com/ext/tools/conf/serial.LoadJSONConfig(0xb704c0, 0xc4200b0000, 0xc42019a6c0,0xc42006bee8, 0x410319)
        /home/dawndiy/workspace/golang/src/v2ray.com/ext/tools/conf/serial/loader.go:18 +0xd1
v2ray.com/ext/tools/conf/command.init.0.func1(0xc4200b4000, 0x0, 0x0)
        /home/dawndiy/workspace/golang/src/v2ray.com/ext/tools/conf/command/command.go:15 +0x4b
main.main()
        src/v2ray.com/ext/tools/control/main/main.go:31 +0xeb

Main: failed to read config file: test.json > Main|Json: failed to execute v2ctl to convert config file. > exit status 2

环境

  • Go 1.10
  • Ext 库最新 commit(f43f74d)

分析

崩溃的原因是 io.Reader.Read() 返回的结果长度大于传入 []byte 的长度。

io.Reader.Read() 的注释里有如下描述:

// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.

在 Go 的 encoding/json 标准库的 decoder 中先会用长度为 512 的 []byte 来调用 io.Reader.Read() (ext 的实现) ,当第 512 字节是转义符号的时候处理是没有追加到返回中,而是跳过了。这时候 io.Reader.Reader() 返回的 n 是 511。然后如果剩下的内容还很长,第二次继续读取的时候会以 1025 长度的输入来调用函数,然而 ext 中的实现,因为上一次是标记了转义(这里导致少返回一个字节),这次会多插入一个字节(这里导致多插入一个字节,并且由于 p := b[:0] 这里会导致 p 提前后移,后面的内容就都重复了)。

简单尝试了一下在 Reader 结构中加一个 buffer []byte 来存多余的部分,但由于现在的实现 p 有的时候会一次追加 2 个字节导致循环过程修改了本身内容,不太好做,可以讨论一下有什么好的办法。

上面我应该描述清楚了,简单写了个测试用例可以来测试: dawndiy@da0a47f#diff-7d2da6197eab2fafc43d39c5180a853c

@DarienRaymond
Copy link
Contributor

感谢测试并反馈。你的测试用例我merge到上游了,然后修复了转义时产生的问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants