encoding/json: make error capture logic in recover more type safe

Rather than only ignoring runtime.Error panics, which are a very
narrow set of possible panic values, switch it such that the json
package only captures panic values that have been properly wrapped
in a jsonError struct. This ensures that only intentional panics
originating from the json package are captured.

Fixes #23012

Change-Id: I5e85200259edd2abb1b0512ce6cc288849151a6d
Reviewed-on: https://go-review.googlesource.com/94019
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Joe Tsai 2017-12-05 22:53:48 -08:00 committed by Joe Tsai
parent 70a04f6880
commit 91a6a2a30f
4 changed files with 43 additions and 12 deletions

View file

@ -14,7 +14,6 @@ import (
"errors"
"fmt"
"reflect"
"runtime"
"strconv"
"unicode"
"unicode/utf16"
@ -168,13 +167,19 @@ func (e *InvalidUnmarshalError) Error() string {
return "json: Unmarshal(nil " + e.Type.String() + ")"
}
// jsonError is an error wrapper type for internal use only.
// Panics with errors are wrapped in jsonError so that the top-level recover
// can distinguish intentional panics from this package.
type jsonError struct{ error }
func (d *decodeState) unmarshal(v interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
if je, ok := r.(jsonError); ok {
err = je.error
} else {
panic(r)
}
err = r.(error)
}
}()
@ -295,9 +300,9 @@ func (d *decodeState) init(data []byte) *decodeState {
return d
}
// error aborts the decoding by panicking with err.
// error aborts the decoding by panicking with err wrapped in jsonError.
func (d *decodeState) error(err error) {
panic(d.addErrorContext(err))
panic(jsonError{d.addErrorContext(err)})
}
// saveError saves the first err it is called with,