Skip to content

cmd/cgo: detect incompatible C declarations #67699

Closed
@randall77

Description

@randall77

We already detect incompatible C declarations if both declarations are in the same file. For instance,

/*
void f();
int f();
*/
import "C"

Gives an error conflicting types for 'f'.

When the conflicting definitions are in different files, however, we don't detect it. That can lead to very tricky runtime failures. See #67670 for an example.

Here's a small reproducer:
test1.go:

package main

/*
int f(int x, int y, int z, int w);
*/
import "C"
import "fmt"

func main() {
	var x [4]uint64
	pre(&x)
	C.f(5, 6, 7, 8)
	post(&x)
	main2()
}

//go:noinline
func pre(p *[4]uint64) {
	for i := range p {
		p[i] = 0xaaaaaaaaaaaaaaaa
	}
}

//go:noinline
func post(p *[4]uint64) {
	for i := range p {
		if p[i] != 0xaaaaaaaaaaaaaaaa {
			fmt.Printf("%d %x\n", i, p[i])
			panic("bad")
		}
	}

}

test2.go:

package main

/*
void f(int x, int y, int z, int w) { }
*/
import "C"

func main2() {
	var x [4]uint64
	pre(&x)
	C.f(5, 6, 7, 8)
	post(&x)
}

When run with go run test1.go test2.go, we get (darwin/arm64):

0 aaaaaaaa00000005
panic: bad

goroutine 1 [running]:
main.post(0x14000080f18)
	/Users/khr/gowork/test1.go:29 +0xe4
main.main()
	/Users/khr/gowork/test1.go:13 +0x4c
exit status 2

Which means that a stack variable got partially overwritten by a cgo call.

I'm pretty sure what is happening is that at the callsite the compiler assumes C.f has no return value, so does not allocate space for it. But the cgo wrapper assumes C.f does have a return value, and generates code to move f's return value to the stack frame. That write lands on the local variable x.

I'm not sure how the compiler and/or cgo decide which version of f to use. Perhaps if they just chose consistently things would work. But probably better to detect the conflicting definitions and error out.

@ianlancetaylor

Metadata

Metadata

Assignees

No one assigned

    Labels

    FeatureRequestIssues asking for a new feature that does not need a proposal.NeedsFixThe path to resolution is known, but the work has not been done.compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions