"errors"
"fmt"
"reflect"
- "runtime"
"strconv"
"unicode"
"unicode/utf16"
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)
}
}()
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,
}
}
}
+
+type unmarshalPanic struct{}
+
+func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) }
+
+func TestUnmarshalPanic(t *testing.T) {
+ defer func() {
+ if got := recover(); !reflect.DeepEqual(got, 0xdead) {
+ t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
+ }
+ }()
+ Unmarshal([]byte("{}"), &unmarshalPanic{})
+ t.Fatalf("Unmarshal should have panicked")
+}
"fmt"
"math"
"reflect"
- "runtime"
"sort"
"strconv"
"strings"
func (e *encodeState) marshal(v interface{}, opts encOpts) (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)
}
- if s, ok := r.(string); ok {
- panic(s)
- }
- err = r.(error)
}
}()
e.reflectValue(reflect.ValueOf(v), opts)
return nil
}
+// error aborts the encoding by panicking with err wrapped in jsonError.
func (e *encodeState) error(err error) {
- panic(err)
+ panic(jsonError{err})
}
func isEmptyValue(v reflect.Value) bool {
}
}
}
+
+type marshalPanic struct{}
+
+func (marshalPanic) MarshalJSON() ([]byte, error) { panic(0xdead) }
+
+func TestMarshalPanic(t *testing.T) {
+ defer func() {
+ if got := recover(); !reflect.DeepEqual(got, 0xdead) {
+ t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
+ }
+ }()
+ Marshal(&marshalPanic{})
+ t.Error("Marshal should have panicked")
+}