File tree Expand file tree Collapse file tree 4 files changed +43
-12
lines changed Expand file tree Collapse file tree 4 files changed +43
-12
lines changed Original file line number Diff line number Diff line change @@ -14,7 +14,6 @@ import (
14
14
"errors"
15
15
"fmt"
16
16
"reflect"
17
- "runtime"
18
17
"strconv"
19
18
"unicode"
20
19
"unicode/utf16"
@@ -168,13 +167,19 @@ func (e *InvalidUnmarshalError) Error() string {
168
167
return "json: Unmarshal(nil " + e .Type .String () + ")"
169
168
}
170
169
170
+ // jsonError is an error wrapper type for internal use only.
171
+ // Panics with errors are wrapped in jsonError so that the top-level recover
172
+ // can distinguish intentional panics from this package.
173
+ type jsonError struct { error }
174
+
171
175
func (d * decodeState ) unmarshal (v interface {}) (err error ) {
172
176
defer func () {
173
177
if r := recover (); r != nil {
174
- if _ , ok := r .(runtime.Error ); ok {
178
+ if je , ok := r .(jsonError ); ok {
179
+ err = je .error
180
+ } else {
175
181
panic (r )
176
182
}
177
- err = r .(error )
178
183
}
179
184
}()
180
185
@@ -295,9 +300,9 @@ func (d *decodeState) init(data []byte) *decodeState {
295
300
return d
296
301
}
297
302
298
- // error aborts the decoding by panicking with err.
303
+ // error aborts the decoding by panicking with err wrapped in jsonError .
299
304
func (d * decodeState ) error (err error ) {
300
- panic (d .addErrorContext (err ))
305
+ panic (jsonError { d .addErrorContext (err )} )
301
306
}
302
307
303
308
// saveError saves the first err it is called with,
Original file line number Diff line number Diff line change @@ -2166,3 +2166,17 @@ func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) {
2166
2166
}
2167
2167
}
2168
2168
}
2169
+
2170
+ type unmarshalPanic struct {}
2171
+
2172
+ func (unmarshalPanic ) UnmarshalJSON ([]byte ) error { panic (0xdead ) }
2173
+
2174
+ func TestUnmarshalPanic (t * testing.T ) {
2175
+ defer func () {
2176
+ if got := recover (); ! reflect .DeepEqual (got , 0xdead ) {
2177
+ t .Errorf ("panic() = (%T)(%v), want 0xdead" , got , got )
2178
+ }
2179
+ }()
2180
+ Unmarshal ([]byte ("{}" ), & unmarshalPanic {})
2181
+ t .Fatalf ("Unmarshal should have panicked" )
2182
+ }
Original file line number Diff line number Diff line change @@ -17,7 +17,6 @@ import (
17
17
"fmt"
18
18
"math"
19
19
"reflect"
20
- "runtime"
21
20
"sort"
22
21
"strconv"
23
22
"strings"
@@ -286,21 +285,20 @@ func newEncodeState() *encodeState {
286
285
func (e * encodeState ) marshal (v interface {}, opts encOpts ) (err error ) {
287
286
defer func () {
288
287
if r := recover (); r != nil {
289
- if _ , ok := r .(runtime.Error ); ok {
288
+ if je , ok := r .(jsonError ); ok {
289
+ err = je .error
290
+ } else {
290
291
panic (r )
291
292
}
292
- if s , ok := r .(string ); ok {
293
- panic (s )
294
- }
295
- err = r .(error )
296
293
}
297
294
}()
298
295
e .reflectValue (reflect .ValueOf (v ), opts )
299
296
return nil
300
297
}
301
298
299
+ // error aborts the encoding by panicking with err wrapped in jsonError.
302
300
func (e * encodeState ) error (err error ) {
303
- panic (err )
301
+ panic (jsonError { err } )
304
302
}
305
303
306
304
func isEmptyValue (v reflect.Value ) bool {
Original file line number Diff line number Diff line change @@ -981,3 +981,17 @@ func TestMarshalRawMessageValue(t *testing.T) {
981
981
}
982
982
}
983
983
}
984
+
985
+ type marshalPanic struct {}
986
+
987
+ func (marshalPanic ) MarshalJSON () ([]byte , error ) { panic (0xdead ) }
988
+
989
+ func TestMarshalPanic (t * testing.T ) {
990
+ defer func () {
991
+ if got := recover (); ! reflect .DeepEqual (got , 0xdead ) {
992
+ t .Errorf ("panic() = (%T)(%v), want 0xdead" , got , got )
993
+ }
994
+ }()
995
+ Marshal (& marshalPanic {})
996
+ t .Error ("Marshal should have panicked" )
997
+ }
You can’t perform that action at this time.
0 commit comments