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

cmd/cgo: opaque struct pointers are broken since Go 1.15.3 #42032

Open
aykevl opened this issue Oct 16, 2020 · 1 comment
Open

cmd/cgo: opaque struct pointers are broken since Go 1.15.3 #42032

aykevl opened this issue Oct 16, 2020 · 1 comment

Comments

@aykevl
Copy link

@aykevl aykevl commented Oct 16, 2020

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

$ go version
go version go1.15.3 linux/amd64

Does this issue reproduce with the latest release?

Yes, it reproduces since 76a2c87 (I bisected to that commit), see #41432.

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ayke/.cache/go-build"
GOENV="/home/ayke/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/ayke/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/ayke:/home/ayke:/home/ayke:/home/ayke:/home/ayke:/home/ayke:/home/ayke"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build700779300=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I ran the following program:

package main

import "tinygo.org/x/go-llvm"

type param struct {
	llvmType llvm.Type
	name     string
}

func main() {
	i8Type := llvm.Int8Type()
	println("i8Type:   ", i8Type.C)

	p := param{llvmType: i8Type}
	params := []param{p}
	params = append(params, p)

	println("params[0]:", params[0].llvmType.C)
	println("params[1]:", params[1].llvmType.C)
}

What did you expect to see?

In Go before 76a2c87 it gives output like this, with all pointers set:

i8Type:    0x900940
params[0]: 0x900940
params[1]: 0x900940

What did you see instead?

Since 76a2c87 (in Go 1.15.3), I get output like this:

i8Type:    0x239eab0
params[0]: 0x239eab0
params[1]: 0x0

The pointer values change each run, that's not the issue. The issue is that params[1] is nil. To be precise, it appears that values appended to the slice with append are nil.

Interestingly, when I remove the name field of the struct, the issue disappears.

While investigating this issue, I also found some other weird behavior that might be related:

package main

import "fmt"

// typedef struct OpaqueType* TypeRef;
// int a;
// TypeRef GetType(void) {
//     return (void*)&a;
// }
import "C"

func main() {
	fmt.Println(C.GetType())
}

Output:

panic: can't call pointer on a non-pointer Value

goroutine 1 [running]:
reflect.Value.pointer(...)
	/usr/local/go/src/reflect/value.go:95
reflect.Value.Pointer(0x4a8a00, 0x587438, 0x16, 0xc000045c70)
	/usr/local/go/src/reflect/value.go:1456 +0x1b6
fmt.(*pp).printValue(0xc000070750, 0x4a8a00, 0x587438, 0x16, 0x76, 0x0)
	/usr/local/go/src/fmt/print.go:876 +0x195f
fmt.(*pp).printArg(0xc000070750, 0x4a8a00, 0x587438, 0x76)
	/usr/local/go/src/fmt/print.go:716 +0x2b4
fmt.(*pp).doPrintln(0xc000070750, 0xc000045f68, 0x1, 0x1)
	/usr/local/go/src/fmt/print.go:1173 +0xb1
fmt.Fprintln(0x4de100, 0xc000010018, 0xc000045f68, 0x1, 0x1, 0x0, 0x0, 0x0)
	/usr/local/go/src/fmt/print.go:264 +0x58
fmt.Println(...)
	/usr/local/go/src/fmt/print.go:274
main.main()
	/home/ayke/tmp/cgo-bug-reproducer/main.go:34 +0x7a
exit status 2

(The result is the same in Go 1.15.3 and in the commit before 76a2c87). I'm including this as this smells like a bug somewhere, although I can't really say where. Maybe the code (2nd snippet) is wrong, but it looks correct to me.

@aykevl aykevl changed the title cgo: CGo is broken in Go 1.15.3 cgo: CGo opaque structs are broken since Go 1.15.3 Oct 16, 2020
@aykevl aykevl changed the title cgo: CGo opaque structs are broken since Go 1.15.3 cgo: opaque struct pointers are broken since Go 1.15.3 Oct 16, 2020
@ianlancetaylor ianlancetaylor changed the title cgo: opaque struct pointers are broken since Go 1.15.3 cmd/cgo: opaque struct pointers are broken since Go 1.15.3 Oct 16, 2020
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Oct 17, 2020

CC @randall77

Here llvm.Type is defined as

type Type struct {
	C C.LLVMTypeRef
}

LLVMTypeRef is defined, in C, as typedef struct LLVMOpaqueType *LLVMTypeRef; LLVMOpaqueType is not defined.

llvm.Int8Type is

func Int8Type() (t Type)  { t.C = C.LLVMInt8Type(); return }

I think the issue here is that because C.LLVMTypeRef is a pointer to an opaque struct, it is marked as notinheap. That is fine. However, when a field of a struct is notinheap, then the struct itself becomes notinheap. But here that is wrong.

@ianlancetaylor ianlancetaylor added this to the Go1.16 milestone Oct 17, 2020
aykevl added a commit to tinygo-org/tinygo that referenced this issue Oct 17, 2020
This works around a bug in Go 1.15.3 by pinning an older version.
See: golang/go#42032
deadprogram added a commit to tinygo-org/tinygo that referenced this issue Oct 17, 2020
This works around a bug in Go 1.15.3 by pinning an older version.
See: golang/go#42032
subosito added a commit to subosito/drafter-go that referenced this issue Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.