Skip to content

Commit 30fe2a4

Browse files
authored
Merge pull request #17 from breml/issue_14
Omit safe for encoding/json.Encoder
2 parents 7c1c56a + 9632243 commit 30fe2a4

File tree

3 files changed

+19
-13
lines changed

3 files changed

+19
-13
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ Forbidden basic types:
114114
Any composed types (struct, map, slice, array) containing a forbidden basic type. Any map
115115
using a key with a forbidden type (`bool`, `float32`, `float64`, `struct`).
116116

117+
## Accepted edge case
118+
119+
For `encoding/json.MarshalIndent`, there is a (pathological) edge case, where this
120+
function could [return an error](https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/encoding/json/scanner.go;drc=refs%2Ftags%2Fgo1.18;l=181) for an otherwise safe argument, if the argument has
121+
a nesting depth larger than [`10000`](https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/encoding/json/scanner.go;drc=refs%2Ftags%2Fgo1.18;l=144) (as of Go 1.18).
122+
117123
## Bugs found during development
118124

119125
During the development of `errcheckjson`, the following issues in package `encoding/json` of the Go standard library have been found and PR have been merged:

errchkjson.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
5959

6060
switch fn.FullName() {
6161
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
62-
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier)
62+
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier, e.omitSafe)
6363
case "(*encoding/json.Encoder).Encode":
64-
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier)
64+
e.handleJSONMarshal(pass, ce, fn.FullName(), blankIdentifier, true)
6565
default:
6666
e.inspectArgs(pass, ce.Args)
6767
}
@@ -85,9 +85,9 @@ func (e *errchkjson) run(pass *analysis.Pass) (interface{}, error) {
8585

8686
switch fn.FullName() {
8787
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
88-
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[1]))
88+
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[1]), e.omitSafe)
8989
case "(*encoding/json.Encoder).Encode":
90-
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[0]))
90+
e.handleJSONMarshal(pass, ce, fn.FullName(), evaluateMarshalErrorTarget(as.Lhs[0]), true)
9191
default:
9292
return true
9393
}
@@ -115,7 +115,7 @@ const (
115115
functionArgument // the returned error from the JSON marshal function is passed to an other function as argument.
116116
)
117117

118-
func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fnName string, errorTarget marshalErrorTarget) {
118+
func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fnName string, errorTarget marshalErrorTarget, omitSafe bool) {
119119
t := pass.TypesInfo.TypeOf(ce.Args[0])
120120
if t == nil {
121121
// Not sure, if this is at all possible
@@ -143,11 +143,11 @@ func (e *errchkjson) handleJSONMarshal(pass *analysis.Pass, ce *ast.CallExpr, fn
143143
pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked: %v", fnName, err)
144144
}
145145
}
146-
if err == nil && errorTarget == variableAssignment && !e.omitSafe {
146+
if err == nil && errorTarget == variableAssignment && !omitSafe {
147147
pass.Reportf(ce.Pos(), "Error return value of `%s` is checked but passed argument is safe", fnName)
148148
}
149149
// Report an error, if err for json.Marshal is not checked and safe types are omitted
150-
if err == nil && errorTarget == blankIdentifier && e.omitSafe {
150+
if err == nil && errorTarget == blankIdentifier && omitSafe {
151151
pass.Reportf(ce.Pos(), "Error return value of `%s` is not checked", fnName)
152152
}
153153
}
@@ -296,9 +296,9 @@ func (e *errchkjson) inspectArgs(pass *analysis.Pass, args []ast.Expr) {
296296

297297
switch fn.FullName() {
298298
case "encoding/json.Marshal", "encoding/json.MarshalIndent":
299-
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument)
299+
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument, e.omitSafe)
300300
case "(*encoding/json.Encoder).Encode":
301-
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument)
301+
e.handleJSONMarshal(pass, ce, fn.FullName(), functionArgument, true)
302302
default:
303303
e.inspectArgs(pass, ce.Args)
304304
}

testdata/src/standard/a.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ func JSONMarshalSafeTypes() {
4141
_ = err
4242

4343
enc := json.NewEncoder(ioutil.Discard)
44-
_ = enc.Encode(nil) // nil is safe
45-
enc.Encode(nil) // nil is safe
46-
err = enc.Encode(nil) // want "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is checked but passed argument is safe"
44+
_ = enc.Encode(nil) // want "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is not checked"
45+
enc.Encode(nil) // want "Error return value of `\\([*]encoding/json.Encoder\\).Encode` is not checked"
46+
err = enc.Encode(nil) // nil is safe, but encoding/json.Encoder may return non json related errors
4747
_ = err
4848

4949
var b bool
@@ -611,7 +611,7 @@ func JSONMarshalInvalidTypes() {
611611
_, err = json.Marshal(mapC128Str) // want "`encoding/json.Marshal` for unsupported type `complex128` as map key found"
612612
_ = err
613613

614-
mapStructStr := map[structKey]string{structKey{1}: "str"}
614+
mapStructStr := map[structKey]string{{1}: "str"}
615615
_, _ = json.Marshal(mapStructStr) // want "`encoding/json.Marshal` for unsupported type `standard.structKey` as map key found"
616616
_, err = json.Marshal(mapStructStr) // want "`encoding/json.Marshal` for unsupported type `standard.structKey` as map key found"
617617
_ = err

0 commit comments

Comments
 (0)