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
Open

cmd/cgo: warning: built-in function ‘free’ declared as non-function #32411

yath opened this issue Jun 3, 2019 · 15 comments
Labels
help wanted NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@yath
Copy link

yath 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
Copy link
Contributor

Does the code work other than producing a warning?

@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 3, 2019
@ianlancetaylor ianlancetaylor added this to the Go1.14 milestone Jun 3, 2019
@yath
Copy link
Author

yath 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
Copy link
Contributor

gertcuykens 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

@ianlancetaylor ianlancetaylor added help wanted NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Jun 5, 2019
@qbradq
Copy link
Contributor

qbradq 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
Copy link
Author

yath 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
Copy link
Contributor

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
Copy link
Contributor

qbradq 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
Copy link
Author

yath 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
Copy link
Contributor

qbradq 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
Copy link
Author

yath 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
Copy link
Contributor

qbradq 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
Copy link
Contributor

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

@ianlancetaylor
Copy link
Contributor

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
Copy link
Contributor

qbradq 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
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants