{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/10303","labels_url":"https://api.github.com/repos/golang/go/issues/10303/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/10303/comments","events_url":"https://api.github.com/repos/golang/go/issues/10303/events","html_url":"https://github.com/golang/go/issues/10303","id":65533453,"number":10303,"title":"cmd/cgo: should make pointers passed to C functions escape","user":{"login":"jtolds","id":109603,"avatar_url":"https://avatars.githubusercontent.com/u/109603?v=3","gravatar_id":"","url":"https://api.github.com/users/jtolds","html_url":"https://github.com/jtolds","followers_url":"https://api.github.com/users/jtolds/followers","following_url":"https://api.github.com/users/jtolds/following{/other_user}","gists_url":"https://api.github.com/users/jtolds/gists{/gist_id}","starred_url":"https://api.github.com/users/jtolds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jtolds/subscriptions","organizations_url":"https://api.github.com/users/jtolds/orgs","repos_url":"https://api.github.com/users/jtolds/repos","events_url":"https://api.github.com/users/jtolds/events{/privacy}","received_events_url":"https://api.github.com/users/jtolds/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/golang/go/labels/repo-main","name":"repo-main","color":"ededed"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/golang/go/milestones/1","html_url":"https://github.com/golang/go/milestones/Go1.5","labels_url":"https://api.github.com/repos/golang/go/milestones/1/labels","id":905105,"number":1,"title":"Go1.5","description":"","creator":{"login":"bradfitz","id":2621,"avatar_url":"https://avatars.githubusercontent.com/u/2621?v=3","gravatar_id":"","url":"https://api.github.com/users/bradfitz","html_url":"https://github.com/bradfitz","followers_url":"https://api.github.com/users/bradfitz/followers","following_url":"https://api.github.com/users/bradfitz/following{/other_user}","gists_url":"https://api.github.com/users/bradfitz/gists{/gist_id}","starred_url":"https://api.github.com/users/bradfitz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradfitz/subscriptions","organizations_url":"https://api.github.com/users/bradfitz/orgs","repos_url":"https://api.github.com/users/bradfitz/repos","events_url":"https://api.github.com/users/bradfitz/events{/privacy}","received_events_url":"https://api.github.com/users/bradfitz/received_events","type":"User","site_admin":false},"open_issues":284,"closed_issues":225,"state":"open","created_at":"2014-12-16T02:26:41Z","updated_at":"2015-03-31T20:29:05Z","due_on":"2015-07-31T04:00:00Z","closed_at":null},"comments":2,"created_at":"2015-03-31T19:59:21Z","updated_at":"2015-03-31T21:06:53Z","closed_at":null,"body":"Assume you have some package foo that uses a C function:\r\n\r\n```\r\npackage foo\r\n\r\n/*\r\ntypedef struct Buf {\r\n} Buf;\r\n\r\nvoid Foo(Buf* buf) {\r\n}\r\n*/\r\nimport \"C\"\r\n\r\nfunc Foo() {\r\n    var buf C.Buf\r\n    C.Foo(&buf)\r\n}\r\n```\r\n\r\nIf you compile this package with Go 1.2 (what we use, until we can do some big audit of our cgo usage), we get this:\r\n\r\n```\r\nandrew@andrew-cb:~/escapeme/src/foo$ go version\r\ngo version go1.2 linux/amd64\r\nandrew@andrew-cb:~/escapeme/src/foo$ go build -gcflags \"-m -l -N\"\r\n# foo\r\n./foo.go:14: moved to heap: buf\r\n```\r\n\r\nThis is what we'd expect. Since the heap is (currently) a safe place to put Go-allocated memory referenced by C, we'd expect passing &buf to C.Foo to indicate buf should be heap-allocated.\r\n\r\nOn Go 1.4, we get this:\r\n\r\n```\r\nandrew@andrew-cb:~/escapeme/src/foo$ go version\r\ngo version go1.4.2 linux/amd64\r\nandrew@andrew-cb:~/escapeme/src/foo$ go build -gcflags \"-m -l -N\"\r\n# foo\r\n/tmp/go-build929685257/foo/_obj/_cgo_gotypes.go:12: leaking param: ptr to result ~r1\r\n:10[/tmp/go-build929685257/foo/_obj/_cgo_gotypes.go:27]: _Cfunc_Foo p0 does not escape\r\n:11[/tmp/go-build929685257/foo/_obj/_cgo_gotypes.go:28]: _Cfunc_Foo &p0 does not escape\r\n./foo.go:15: Foo &buf does not escape\r\nandrew@andrew-cb:~/escapeme/src/foo$\r\n```\r\n\r\nFoo &buf does not escape? It totally should! Since it didn't get escaped, we're now passing stack-allocated memory into C. Holy cow that's a bad idea with 1.4, cause stack allocated memory gets moved around.\r\n\r\nAnd here's tip:\r\n\r\n```\r\nandrew@andrew-cb:~/escapeme/src/foo$ go version\r\ngo version devel +f8fd550 Tue Mar 31 13:56:18 2015 +0000 linux/amd64\r\nandrew@andrew-cb:~/escapeme/src/foo$ go build -gcflags \"-m -l -N\"\r\n# foo\r\n/tmp/go-build207622607/foo/_obj/_cgo_gotypes.go:14: leaking param: ptr to result ~r1\r\n:19[/tmp/go-build207622607/foo/_obj/_cgo_gotypes.go:38]: _Cfunc_Foo p0 does not escape\r\n:20[/tmp/go-build207622607/foo/_obj/_cgo_gotypes.go:39]: _Cfunc_Foo &p0 does not escape\r\n./foo.go:15: Foo &buf does not escape\r\nandrew@andrew-cb:~/escapeme/src/foo$ \r\n```"},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/88247703","html_url":"https://github.com/golang/go/issues/10303#issuecomment-88247703","issue_url":"https://api.github.com/repos/golang/go/issues/10303","id":88247703,"user":{"login":"minux","id":135652,"avatar_url":"https://avatars.githubusercontent.com/u/135652?v=3","gravatar_id":"","url":"https://api.github.com/users/minux","html_url":"https://github.com/minux","followers_url":"https://api.github.com/users/minux/followers","following_url":"https://api.github.com/users/minux/following{/other_user}","gists_url":"https://api.github.com/users/minux/gists{/gist_id}","starred_url":"https://api.github.com/users/minux/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/minux/subscriptions","organizations_url":"https://api.github.com/users/minux/orgs","repos_url":"https://api.github.com/users/minux/repos","events_url":"https://api.github.com/users/minux/events{/privacy}","received_events_url":"https://api.github.com/users/minux/received_events","type":"User","site_admin":false},"created_at":"2015-03-31T21:06:53Z","updated_at":"2015-03-31T21:06:53Z","body":"well, this is not a escape analysis bug per-se.\n\nFor example, the example function call C.Foo(&buf) in the issue report\ngets translated to a call to this func:\nfunc _Cfunc_Foo(p0 *_Ctype_struct_Buf) (r1 _Ctype_void) {\n        _cgo_runtime_cgocall_errno(_cgo_0b9ef0be51ea_Cfunc_Foo,\nuintptr(unsafe.Pointer(&p0)))\n        return\n}\n\nAnd you can see the p0 really is not escaping.\nWe should add something like:\n        use(unsafe.Pointer(p0))\nwhere use is defined in assembly as a NOP, and have the prototype:\nfunc use(unsafe.Pointer)\n\nJust like what we did for the syscall package.\n\nThe reason I think it is not done is that we still are not clear about what\nkind of\nguarantee we want to provide for passing Go pointers to C code. In the pass\nwe talked about always making a copy, but apparently that proposal is\ndismissed\nafter hearing severe opposing voice from the community.\n"}}