]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: fix initialization of empty argument types
authorAustin Clements <austin@google.com>
Wed, 11 Nov 2020 20:33:39 +0000 (15:33 -0500)
committerAustin Clements <austin@google.com>
Fri, 13 Nov 2020 15:15:15 +0000 (15:15 +0000)
CL 258938 changed the way C to Go calls work such that they now
construct a C struct on the C side for the arguments and space for the
results. Any pointers in the result space must be zeroed, so we just
zero the whole struct.

However, C makes it surprisingly hard to robustly zero any struct
type. We had used a "{0}" initializer, which works in the vast
majority of cases, but fails if the type is empty or effectively
empty.

This CL fixes this by changing how the cgo tool zero-initializes the
argument struct to be more robust.

Fixes #42495.

Change-Id: Id1749b9d751e59eb7a02a9d44fec0698a2bf63cd
Reviewed-on: https://go-review.googlesource.com/c/go/+/269337
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
misc/cgo/test/issue42495.go [new file with mode: 0644]
src/cmd/cgo/out.go

diff --git a/misc/cgo/test/issue42495.go b/misc/cgo/test/issue42495.go
new file mode 100644 (file)
index 0000000..509a67d
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+// typedef struct { } T42495A;
+// typedef struct { int x[0]; } T42495B;
+import "C"
+
+//export Issue42495A
+func Issue42495A(C.T42495A) {}
+
+//export Issue42495B
+func Issue42495B(C.T42495B) {}
index 81b28e24e4b23b540754daeb07b4c3429e2625a1..bb963799f6bb55ae32db8c509074dd95b92ddf60 100644 (file)
@@ -985,7 +985,15 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
                // The results part of the argument structure must be
                // initialized to 0 so the write barriers generated by
                // the assignments to these fields in Go are safe.
-               fmt.Fprintf(fgcc, "\t%s %v _cgo_a = {0};\n", ctype, p.packedAttribute())
+               //
+               // We use a local static variable to get the zeroed
+               // value of the argument type. This avoids including
+               // string.h for memset, and is also robust to C++
+               // types with constructors. Both GCC and LLVM optimize
+               // this into just zeroing _cgo_a.
+               fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute())
+               fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n")
+               fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n")
                if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
                        fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
                }