From f423d616b15302730c1b737a3b22afca315a7fbe Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Wed, 11 Nov 2020 15:33:39 -0500 Subject: [PATCH] cmd/cgo: fix initialization of empty argument types 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 Run-TryBot: Austin Clements TryBot-Result: Go Bot Reviewed-by: Cherry Zhang Reviewed-by: Ian Lance Taylor --- misc/cgo/test/issue42495.go | 15 +++++++++++++++ src/cmd/cgo/out.go | 10 +++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 misc/cgo/test/issue42495.go diff --git a/misc/cgo/test/issue42495.go b/misc/cgo/test/issue42495.go new file mode 100644 index 0000000000..509a67d9a3 --- /dev/null +++ b/misc/cgo/test/issue42495.go @@ -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) {} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 81b28e24e4..bb963799f6 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -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) } -- 2.50.0