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: warning: built-in function ‘free’ declared as non-function #32411

Open
yath opened this issue Jun 3, 2019 · 15 comments

Comments

@yath
Copy link

commented Jun 3, 2019

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

$ go version
go version go1.11.6 linux/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
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/yath/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/yath/go"
GOPROXY="https://proxy.golang.org,direct"
GORACE=""
GOROOT="/tmp/go"
GOTMPDIR=""
GOTOOLDIR="/tmp/go/pkg/tool/linux_amd64"
GCCGO="/usr/bin/gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
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-build688375222=/tmp/go-build -gno-record-gcc-switches"
GOROOT/bin/go version: go version devel +98100c56da Mon Jun 3 01:37:58 2019 +0000 linux/amd64
GOROOT/bin/go tool compile -V: compile version devel +98100c56da Mon Jun 3 01:37:58 2019 +0000
uname -sr: Linux 5.1.5
Distributor ID:	Debian
Description:	Debian GNU/Linux 10 (buster)
Release:	10
Codename:	buster
/lib/x86_64-linux-gnu/libc.so.6: GNU C Library (Debian GLIBC 2.28-10) stable release version 2.28.
lldb --version: lldb version 6.0.1
gdb --version: GNU gdb (Debian 8.2.1-2) 8.2.1

What did you do?

go run the following program that is using C.free as a value. (In actual code, it’s passed to a foo_set_free_fun(void (*)(void *)).) The warning is not emit when calling C.free(), nor is it when e.g. printing the address of C.getenv.

package main

// #include <stdlib.h>
import "C"
import "fmt"

func main() {
        fmt.Printf("%#v\n", C.free)
}

What did you expect to see?

(unsafe.Pointer)(0x402030)

What did you see instead?

# command-line-arguments
cgo-generated-wrappers:1:13: warning: built-in function ‘free’ declared as non-function [-Wbuiltin-declaration-mismatch]
(unsafe.Pointer)(0x402030)
@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jun 3, 2019

Does the code work other than producing a warning?

@ianlancetaylor ianlancetaylor added this to the Go1.14 milestone Jun 3, 2019
@yath

This comment has been minimized.

Copy link
Author

commented Jun 3, 2019

It’s actually a bit hard to trace in the real code, but the following code:

package main

// #include <stdlib.h>
// void __attribute__((noinline)) call_free(void (*f)(void *), char *p) { f(p); }
import "C"
import "fmt"

func main() {
        p := C.CString("test")
        fmt.Printf("p: %#v\n", p)
        C.call_free((*[0]byte)(C.free), p)
}

appears to work as expected:

% ltrace -e free ./main 2>&1|grep -A1 p:      
p: (*main._Ctype_char)(0xef4930)
main->free(0xef4930)                             = <void>
%
@gertcuykens

This comment has been minimized.

Copy link
Contributor

commented Jun 4, 2019

I can reproduce this doing

gert@debian:~/go/src/crawshaw.io/sqlite:master$ go test -v
# crawshaw.io/sqlite
cgo-generated-wrappers:7:13: warning: built-in function ‘free’ declared as non-function
@qbradq

This comment has been minimized.

Copy link
Contributor

commented Jul 12, 2019

@yath This occurs because you are referencing the free built-in as a variable. cgo creates forward declarations of all of the C variables you reference. In this case, it generates this code:

extern char free[];
void *_cgohack_free = free;

The extern declaration of free is what the compiler is (correctly) complaining about.

According to https://golang.org/cmd/cgo/#hdr-Go_references_to_C (you have to scroll down a bit), direct references to C function pointers are not supported. The document provides an example of how to work around this limitation in a non-trivial example.

@yath

This comment has been minimized.

Copy link
Author

commented Jul 16, 2019

Hi @qbradq,

According to https://golang.org/cmd/cgo/#hdr-Go_references_to_C (you have to scroll down a bit), direct references to C function pointers are not supported. The document provides an example of how to work around this limitation in a non-trivial example.

Sorry, I’m unable to find what you are referring to. The only mention of function pointers in the link you’ve provided is “Calling C function pointers is currently not supported”, but I’m not calling a function pointer, I’m just passing it to a different function. I can’t find anything about free (the only symbol that exposes this behavior) being special either.

What am I missing?

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

Note that that warning is coming from the C compiler. It's not coming from any Go tool. It is the C compiler that considers free to be a built-in function.

@qbradq

This comment has been minimized.

Copy link
Contributor

commented Jul 16, 2019

@yath I pointed out the documentation because I thought it might provide you with a solution to the real-world problem behind this ticket. I assumed there was a real-world problem behind the trivialized example given.

@yath

This comment has been minimized.

Copy link
Author

commented Jul 17, 2019

@qbradq, the example you are referring to is the one following “Calling C function pointers is currently not supported, however you can declare Go variables which hold C function pointers and pass them back and forth between Go and C. C code may call function pointers received from Go. For example:”?

If so, then that’s exactly what I’m doing here, except that C.fortytwo is called C.free in my case. The real-world code is calling tvb_set_free_sb and I’m working around the warning by having a void my_free(void *p) { free(p); } that I’m passing instead.

If you are referring to a different example, please provide a more specific link.

@qbradq

This comment has been minimized.

Copy link
Contributor

commented Jul 22, 2019

@yath This is the work-around I was suggesting. Maybe we could add an example to the documentation about how to work around C built-in symbols specifically.

I am not sure a compile-time check would be appropriate as you can never be 100% sure what a C compiler will complain about. But one can be added for the symbols in a specific C standard. I'm just not sure what the Go team's policy is on how compatible they want cgo to be with strange and unusual compilers :)

@yath

This comment has been minimized.

Copy link
Author

commented Jul 22, 2019

As I wrote initially, this is only happening with free, not with getenv for example. Both are defined in stdlib.h, so I’d expect the same amount of built-in-ness from both symbols, but free is somehow special.

I’m not saying that what I’m doing (passing C.free as a value) is necessarily sensible. I just don’t see where the documentation disagrees, and the fact that it does actually work and no warning is produced with a different symbol suggests that I don’t actually have to wrap every C library function with my own one.

@qbradq

This comment has been minimized.

Copy link
Contributor

commented Jul 22, 2019

Unfortunately this is going to be one of those, "Your mileage may vary" kind of things.

Do you think adding the following to the Cgo documentation would have helped you?

Cgo may generate code that produces warnings depending on the target C compiler. For example:

package main

// #include <stdlib.h>
import "C"
import "fmt"

func main() {
        fmt.Printf("%#v\n", C.free)
}

Gives the warning built-in function ‘free’ declared as non-function on many systems.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 22, 2019

@yath free is special because your C compiler considers it to be special.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 22, 2019

It may be possible to work around this problem by having cgo pass -fno-builtin to the relevant invocation of the C compiler. I'm not sure. But I would recommend that if someone wants to look into fixing this.

@qbradq

This comment has been minimized.

Copy link
Contributor

commented Jul 23, 2019

If -fno-builtin does get added to cgo build flags it seems like there also needs to be a way to explicitly disable the option. Depending on compiler and code it may have an impact on performance of the compiled program.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Jul 24, 2019

I think that it would only be needed when invoking the C compiler to determine the types of the functions, I don't think it would be needed for the final build.

@rsc rsc modified the milestones: Go1.14, Backlog Oct 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.