go encoding/json: document Valid allows invalid utf8

irtuqstp  于 5个月前  发布在  Go
关注(0)|答案(4)|浏览(73)

你正在使用哪个版本的Go( go version )?

$ go version
go version go1.20 linux/amd64

这个问题在最新版本中是否会重现?

是的。

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/lukeshu/.cache/go-build"
GOENV="/home/lukeshu/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/lukeshu/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/lukeshu/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/run/user/1000/tmpdir/go-build2160073961=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

我传递了一个用 " 引号包裹的二进制垃圾到 json.Valid

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	jsonStr := "\"0\x85\xcd\xc0\xf3\xcb\xc1\xb3\xf2\xf5\xa4\xc1\xd40\xba\xe9\""
	fmt.Println(json.Valid([]byte(jsonStr)))
}

https://go.dev/play/p/rrtmrEL3Ipd

你期望看到什么?

由于JSON被指定为“Unicode代码点的序列”(ECMA-404)或“以UTF-8、UTF-16或UTF-32编码”(RFC 7159),我期望包含无法解释为Unicode代码点的字节的JSON文档不被认为是有效的。

你实际上看到了什么?

它认为文档是有效的,尽管它包含了无法解释为Unicode代码点的字节。

zyfwsgd6

zyfwsgd61#

@LukeShu 请注意,json.Unmarshal文档中提到了这一点:
在解析带引号的字符串时,无效的UTF-8或无效的UTF-16代理对不会被视为错误。相反,它们会被替换为Unicode替换字符U+FFFD。
由于json.Unmarshal和json.Valid共享底层代码,您的示例看起来符合预期行为。
也许可以改进一下文档?

k4ymrczo

k4ymrczo2#

我理解 UnmarshalValid 共享底层代码,但 Unmarshal 对无效输入持宽松态度并不意味着 Valid 应该将其识别为有效(至少在文档中没有自己的备注时不应该)。

我发现这种不一致是因为各种函数之间的不一致性,我原本以为即使它们有怪癖,由于共享底层实现,它们至少会保持一致。我发现 json.Unmarshal(any)json.MarshalIndent() 会将二进制垃圾转换为 U+FFFD,而 json.Indent()json.Compact() 会原样通过。我认为对无效 JSON 的不同行为是合理的,但后来惊讶地发现 json.Valid() 将它识别为有效。(尽管这种不同的行为令人惊讶,但我真的不能说这是一个bug;而 json.Valid() 将它识别为有效对我来说是一个明显的bug。)

7lrncoxx

7lrncoxx4#

遗憾的是,json包允许无效的UTF-8,因为RFC 8259第8.1节明确指出JSON必须是UTF-8。
鉴于我们已经口头承诺在Unmarshal中处理无效的UTF-8,我们还应该记录Valid中它的操作方式。

相关问题