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

Regression for non-addressable structs #16

Merged
merged 1 commit into from
Dec 7, 2022
Merged

Conversation

swenson
Copy link

@swenson swenson commented Dec 7, 2022

When we removed the default, unsafe mode, it caused a regression where we are no longer able to deserialize things like

map[string]struct{A string}

when we are deserializing into an already existing struct instance. This is because the struct in the map is not addressable by default, which caused a runtime panic. The previous unsafe version wrote directly to the underlying memory and bypassed this check

We fix that by marking structs as an "immutable" type in the decoder, forcing it to recreate the struct rather than try to write to a non-addressable struct.

(This was found by testing hashicorp/nomad, which uses net-rpc-msgpack, which uses this pattern of decoding two messages into one value.)

When we removed the default, unsafe mode, it caused a regression
where we are no longer able to deserialize things like

```go
map[string]struct{A string}
```

when we are deserializing into an already existing `struct` instance.
This is because the `struct` in the map is not addressable by default,
which caused a runtime panic. The previous unsafe version wrote
directly to the underlying memory and bypassed this check

We fix that by marking structs as an "immutable" type in the decoder,
forcing it to recreate the `struct` rather than try to write to
a non-addressable `struct`.

(This was found by testing `hashicorp/nomad`, which uses
`net-rpc-msgpack`, which uses this pattern of decoding two messages
into one value.)
@swenson swenson requested review from tomhjp and kisunji December 7, 2022 00:46
@@ -437,7 +437,7 @@ var immutableKindsSet = [32]bool{
// reflect.Ptr
// reflect.Slice
reflect.String: true,
// reflect.Struct
reflect.Struct: true,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any handle on the performance impact of this? Could it lead to a lot of garbage if we decode elements into a large struct 1-by-1? (I haven't dug into the guts yet, so not sure if that's what it does)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely has a performance impact, but I haven't measured it. I don't feel comfortable with the unsafe code path, since it requires accessing the internal parts of pointers: https://github.com/hashicorp/go-msgpack/blob/v1.1.5/codec/helper_unsafe.go#L342-L346

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I do have a branch I am about to push that fixes the benchmarking so we can more easily measure this. I wanted to get this bug fixed first though.)

Copy link

@tomhjp tomhjp Dec 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be valuable to downstream consumers to know a ballpark level of impact so that they can take action if needed, but in general I'm fine with taking a performance hit for safety and maintainability. Ignore that actually, it doesn't really make sense given the bug, the only comparable thing would be the unsafe version.

@swenson
Copy link
Author

swenson commented Dec 7, 2022

Thanks!

@swenson swenson merged commit 810d5fd into main Dec 7, 2022
@swenson swenson deleted the safe-map-struct-fix branch December 7, 2022 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants