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/gob: serialize *string = "" and get *string = nil when deserializing #56316

Closed
gbataille opened this issue Oct 19, 2022 · 2 comments
Closed

Comments

@gbataille
Copy link

What version of Go are you using (go version)?

$ go version
go version go1.18.6 darwin/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN="/Users/gbataille/go/bin"
GOCACHE="/Users/gbataille/Library/Caches/go-build"
GOENV="/Users/gbataille/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/gbataille/go/pkg/mod"
GOOS="darwin"
GOPATH="/Users/gbataille/go"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go@1.18/1.18.6/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go@1.18/1.18.6/libexec/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.18.6"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/fs/21b7h4ms1k3669wh2kmjzj6w0000gp/T/go-build2442114366=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

if you deserialize a serialized struct which has a *string field and for which the value is a pointer to an empty string "", the deserialized value for the *string field is nil and not a pointer to the empty string anymore.

I think this is not how it should behave, should it?

type Bar struct {
	Str       string
	PStrNil   *string
	PStrEmpty *string
}

func TestTest(t *testing.T) {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	strEmpty := ""
	foo := Bar{
		Str:       "",
		PStrNil:   nil,
		PStrEmpty: &strEmpty,
	}
	err := enc.Encode(foo)
	require.NoError(t, err)
	fmt.Printf("%+v\n", foo)
	dec := gob.NewDecoder(buf)
	var res Bar
	err = dec.Decode(&res)
	require.NoError(t, err)
	fmt.Printf("%+v\n", res)
}

Gives, when run

=== RUN   TestTest
{Str: PStrNil:<nil> PStrEmpty:0xc000204bc0}
{Str: PStrNil:<nil> PStrEmpty:<nil>}
--- PASS: TestTest (0.00s)
PASS
ok      sandbox 0.295s
@robpike
Copy link
Contributor

robpike commented Oct 19, 2022

Yes, that's how it works. The encoding has two properties that explain this:

  1. All pointers are flattened to their pointed-to values, as no pointers are transmitted.
  2. Zero values are not transmitted.

The same would happen if you had a field with a pointer to an integer zero, or any other value.

@gbataille
Copy link
Author

ok I see. it's very confusing to me. I understand it similar to what protobuf does then. But in a protobuf definition, you don't have pointers, so it's clear.
Here it's feels non-obvious.

In any case, thanks for the quick answer

@golang golang locked and limited conversation to collaborators Oct 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants