Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/json: panic on recover #3614

Closed
krasin opened this issue May 11, 2012 · 8 comments

Comments

Projects
None yet
5 participants
@krasin
Copy link

commented May 11, 2012

$ go version
go version go1.0.1

The bug exists in the tip of the tree as well.

I see the following stack trace:

panic: reflect.Value.SetString using unaddressable value [recovered]
    panic: interface conversion: string is not error: missing method Error

goroutine 1 [running]:
encoding/json._func_001(0x7f1761674c38, 0x7f1761678100, 0x7f1761678fb8, 0x7f1761678b68)
    /usr/local/go/src/pkg/encoding/json/decode.go:123 +0xaf
----- stack segment boundary -----
reflect.flag.mustBeAssignable(0x182, 0x1800000182)
    /usr/local/go/src/pkg/reflect/value.go:268 +0x166
reflect.Value.SetString(0x52f9c0, 0xf840229170, 0x182, 0xf8400a7c58, 0x500000005, ...)
    /usr/local/go/src/pkg/reflect/value.go:1336 +0x25
encoding/json.(*decodeState).literalStore(0xf8400740d0, 0xf8401c29c0, 0x5900000007,
0x52f9c0, 0xf840229170, ...)
    /usr/local/go/src/pkg/encoding/json/decode.go:651 +0x730
encoding/json.(*decodeState).literal(0xf8400740d0, 0x52f9c0, 0xf840229170, 0x182)
    /usr/local/go/src/pkg/encoding/json/decode.go:581 +0xb7
----- stack segment boundary -----
encoding/json.(*decodeState).value(0xf8400740d0, 0x52f9c0, 0xf840229170, 0x182)
    /usr/local/go/src/pkg/encoding/json/decode.go:252 +0x1b1
encoding/json.(*decodeState).object(0xf8400740d0, 0x5b6400, 0xf840229150, 0x192)
    /usr/local/go/src/pkg/encoding/json/decode.go:550 +0xa1c
encoding/json.(*decodeState).value(0xf8400740d0, 0x52c020, 0xf8400adf48, 0x146)
    /usr/local/go/src/pkg/encoding/json/decode.go:249 +0x1da
encoding/json.(*decodeState).object(0xf8400740d0, 0x5aea40, 0xf8400adf40, 0x196)
    /usr/local/go/src/pkg/encoding/json/decode.go:550 +0xa1c
encoding/json.(*decodeState).value(0xf8400740d0, 0x525fb8, 0xf84007a388, 0x160)
    /usr/local/go/src/pkg/encoding/json/decode.go:249 +0x1da
encoding/json.(*decodeState).unmarshal(0xf8400740d0, 0x525fa8, 0xf84007a388, 0x0, 0x0,
...)
    /usr/local/go/src/pkg/encoding/json/decode.go:136 +0x159
encoding/json.Unmarshal(0xf8401c2990, 0x8900000059, 0x525fa8, 0xf84007a388, 0x0, ...)
    /usr/local/go/src/pkg/encoding/json/decode.go:65 +0xef

It's because the code in encoding/json assumes (in its recover section) that it was
thrown runtime.Error or error. See
http://code.google.com/p/go/source/browse/src/pkg/encoding/json/decode.go#123

At the same time, reflect.Value is happy to panic with string:
http://code.google.com/p/go/source/browse/src/pkg/reflect/value.go#268

This is an inconsistency that masks the real cause and confuses the programmer.
@rsc

This comment has been minimized.

Copy link
Contributor

commented May 15, 2012

Comment 1:

The real bug is that json is using reflect incorrectly.
This is a bug in json itself.  What type are you passing to Unmarshal?
@krasin

This comment has been minimized.

Copy link
Author

commented May 15, 2012

Comment 2:

I am very sorry: I have lost the code that reproduces this problem. I have just spent
~10 minutes to recall it, but I can't.
@rsc

This comment has been minimized.

Copy link
Contributor

commented May 15, 2012

Comment 3:

My guess is that you passed a struct (not a struct pointer) to
encoding/json and that the string was one of the fields in the struct.
It would be good to test this theory and if so make Unmarshal give a
better error.
I will do this if no one else beats me to it, but probably not soon.

Labels changed: added go1.0.2.

@krasin

This comment has been minimized.

Copy link
Author

commented May 15, 2012

Comment 4:

You're right. I have attached the reproducer. It currently fails with the same stack
trace:
panic: reflect.Value.SetString using unaddressable value [recovered]
    panic: interface conversion: string is not error: missing method Error
goroutine 1 [running]:
encoding/json._func_001(0x7fa2a20e0e88, 0x7fa2a1fc0100, 0x7fa2a1fc0fb8, 0x7fa2a1fc0b98)
    /usr/local/go/src/pkg/encoding/json/decode.go:123 +0xaf
----- stack segment boundary -----
reflect.flag.mustBeAssignable(0x182, 0x1800000000)
    /usr/local/go/src/pkg/reflect/value.go:268 +0x166
reflect.Value.SetString(0x4626a0, 0xf84002e230, 0x182, 0xf84003c130, 0x200000002, ...)
    /usr/local/go/src/pkg/reflect/value.go:1336 +0x25
encoding/json.(*decodeState).literalStore(0xf840059000, 0xf84002e24a, 0x600000004,
0x4626a0, 0xf84002e230, ...)
    /usr/local/go/src/pkg/encoding/json/decode.go:651 +0x730
----- stack segment boundary -----
encoding/json.(*decodeState).literal(0xf840059000, 0x4626a0, 0xf84002e230, 0x182)
    /usr/local/go/src/pkg/encoding/json/decode.go:581 +0xb7
encoding/json.(*decodeState).value(0xf840059000, 0x4626a0, 0xf84002e230, 0x182)
    /usr/local/go/src/pkg/encoding/json/decode.go:252 +0x1b1
encoding/json.(*decodeState).object(0xf840059000, 0x473fd8, 0xf84002e230, 0x192)
    /usr/local/go/src/pkg/encoding/json/decode.go:550 +0xa1c
encoding/json.(*decodeState).value(0xf840059000, 0x461198, 0xf84002e220, 0x146)
    /usr/local/go/src/pkg/encoding/json/decode.go:249 +0x1da
encoding/json.(*decodeState).object(0xf840059000, 0x473f60, 0xf84002e220, 0x196)
    /usr/local/go/src/pkg/encoding/json/decode.go:550 +0xa1c
encoding/json.(*decodeState).value(0xf840059000, 0x4600b8, 0xf84002e220, 0x160)
    /usr/local/go/src/pkg/encoding/json/decode.go:249 +0x1da
encoding/json.(*decodeState).unmarshal(0xf840059000, 0x4600a8, 0xf84002e220, 0x0, 0x0,
...)
    /usr/local/go/src/pkg/encoding/json/decode.go:136 +0x159
encoding/json.Unmarshal(0xf84002e240, 0x1000000010, 0x4600a8, 0xf84002e220,
0xf84002e230, ...)
    /usr/local/go/src/pkg/encoding/json/decode.go:65 +0xef
main.main()
    /home/krasin/json.go:11 +0x11c
goroutine 2 [syscall]:
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:221
exit status 2

Attachments:

  1. json.go (291 bytes)
@robpike

This comment has been minimized.

Copy link
Contributor

commented Jun 1, 2012

Comment 5:

Owner changed to builder@golang.org.

Status changed to Accepted.

@adg

This comment has been minimized.

Copy link
Contributor

commented Jun 7, 2012

Comment 6:

Here's a smaller test case:
func TestInterfaceSet(t *testing.T) {
    b := struct{ X interface{} }{"foo"}
    const blob = `{"X":"bar"}`
    if err := Unmarshal([]byte(blob), &b); err != nil {
        t.Errorf("%v", err)
    }
}
It's trying to update a string value that isn't addressable because it's stored as an
interface value. The containing struct is addressable, so the json package could be
clever enough to walk back up and the value correctly. Not sure that it's worth it,
though.
@rsc

This comment has been minimized.

Copy link
Contributor

commented Jun 7, 2012

Comment 7:

Thank you for the smaller case. Nice.
@rsc

This comment has been minimized.

Copy link
Contributor

commented Jun 7, 2012

Comment 8:

This issue was closed by revision 09b736a.

Status changed to Fixed.

@krasin krasin added fixed labels Jun 7, 2012

@rsc rsc added this to the Go1.0.2 milestone Apr 14, 2015

@rsc rsc removed the go1.0.2 label Apr 14, 2015

rsc added a commit that referenced this issue May 11, 2015

[release-branch.go1] encoding/json: fix panic unmarshaling into non-n…
…il interface value

««« backport bee83c1509a3
encoding/json: fix panic unmarshaling into non-nil interface value

Fixes #3614.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/6306051

»»»

@golang golang locked and limited conversation to collaborators Jun 24, 2016

This issue was closed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.