cmd/cgo: make it safe to run gcc in parallel

Use a new filename for each invocation so invocations run
concurrently don't overwrite the same file.

Change-Id: I6a6a696478b596a4819f41b3ac738263d41bbabf
Reviewed-on: https://go-review.googlesource.com/c/go/+/699017
Reviewed-by: Michael Matloob <matloob@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
matloob 2025-08-25 17:36:30 -04:00 committed by Michael Matloob
parent 49a2f3ed87
commit d19e377f6e

View file

@ -27,6 +27,7 @@ import (
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@ -1756,17 +1757,20 @@ func gccMachine() []string {
return nil return nil
} }
var n atomic.Int64
func gccTmp() string { func gccTmp() string {
return *objDir + "_cgo_.o" c := strconv.Itoa(int(n.Add(1)))
return *objDir + "_cgo_" + c + ".o"
} }
// gccCmd returns the gcc command line to use for compiling // gccCmd returns the gcc command line to use for compiling
// the input. // the input.
func (p *Package) gccCmd() []string { func (p *Package) gccCmd(ofile string) []string {
c := append(gccBaseCmd, c := append(gccBaseCmd,
"-w", // no warnings "-w", // no warnings
"-Wno-error", // warnings are not errors "-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp "-o"+ofile, // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols "-gdwarf-2", // generate DWARF v2 debugging symbols
"-c", // do not link "-c", // do not link
"-xc", // input language is C "-xc", // input language is C
@ -1806,7 +1810,8 @@ func (p *Package) gccCmd() []string {
// gccDebug runs gcc -gdwarf-2 over the C program stdin and // gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and, if present, debug data block. // returns the corresponding DWARF data and, if present, debug data block.
func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) { func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
runGcc(stdin, p.gccCmd()) ofile := gccTmp()
runGcc(stdin, p.gccCmd(ofile))
isDebugInts := func(s string) bool { isDebugInts := func(s string) bool {
// Some systems use leading _ to denote non-assembly symbols. // Some systems use leading _ to denote non-assembly symbols.
@ -1856,11 +1861,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
} }
} }
if f, err := macho.Open(gccTmp()); err == nil { if f, err := macho.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := f.ByteOrder bo := f.ByteOrder
if f.Symtab != nil { if f.Symtab != nil {
@ -1934,11 +1939,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := elf.Open(gccTmp()); err == nil { if f, err := elf.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := f.ByteOrder bo := f.ByteOrder
symtab, err := f.Symbols() symtab, err := f.Symbols()
@ -2034,11 +2039,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := pe.Open(gccTmp()); err == nil { if f, err := pe.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := binary.LittleEndian bo := binary.LittleEndian
for _, s := range f.Symbols { for _, s := range f.Symbols {
@ -2106,11 +2111,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := xcoff.Open(gccTmp()); err == nil { if f, err := xcoff.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := binary.BigEndian bo := binary.BigEndian
for _, s := range f.Symbols { for _, s := range f.Symbols {
@ -2176,7 +2181,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
buildStrings() buildStrings()
return d, ints, floats, strs return d, ints, floats, strs
} }
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp()) fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", ofile)
panic("not reached") panic("not reached")
} }
@ -2196,7 +2201,7 @@ func gccDefines(stdin []byte, gccOptions []string) string {
// gcc to fail. // gcc to fail.
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string { func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
// TODO(rsc): require failure // TODO(rsc): require failure
args := p.gccCmd() args := p.gccCmd(gccTmp())
// Optimization options can confuse the error messages; remove them. // Optimization options can confuse the error messages; remove them.
nargs := make([]string, 0, len(args)+len(extraArgs)) nargs := make([]string, 0, len(args)+len(extraArgs))