diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-04-03 14:35:27 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-04-03 13:17:55 +0000 |
| commit | d7ae3a111bd75df44dda69b37da945b50d5133e2 (patch) | |
| tree | 9797c351f3f4d30ae71068ae1447b457506afb7c | |
| parent | 012c639d904cf60a221b8b16833c02eed9b2514e (diff) | |
pkg/ifuzz: fix generate/build
Currently the commands we have in go:generate first create an empty file
and then write final contents. This breaks any parallel builds of the source.
Even running go generate ./... does not work.
Write output files atomically.
| -rw-r--r-- | pkg/ifuzz/arm64/arm64.go | 2 | ||||
| -rw-r--r-- | pkg/ifuzz/arm64/gen/gen.go | 14 | ||||
| -rw-r--r-- | pkg/ifuzz/x86/gen/gen.go | 14 | ||||
| -rw-r--r-- | pkg/ifuzz/x86/x86.go | 2 | ||||
| -rw-r--r-- | pkg/osutil/osutil.go | 13 | ||||
| -rw-r--r-- | sys/fuchsia/fidlgen/main.go | 2 |
6 files changed, 36 insertions, 11 deletions
diff --git a/pkg/ifuzz/arm64/arm64.go b/pkg/ifuzz/arm64/arm64.go index 3b835566f..a2d326339 100644 --- a/pkg/ifuzz/arm64/arm64.go +++ b/pkg/ifuzz/arm64/arm64.go @@ -1,7 +1,7 @@ // Copyright 2024 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. -//go:generate bash -c "go run gen/gen.go gen/json/arm64.json | gofmt > generated/insns.go" +//go:generate go run gen/gen.go gen/json/arm64.json generated/insns.go // Package arm64 allows to generate and mutate arm64 machine code. package arm64 diff --git a/pkg/ifuzz/arm64/gen/gen.go b/pkg/ifuzz/arm64/gen/gen.go index 659fea202..ef5afbd46 100644 --- a/pkg/ifuzz/arm64/gen/gen.go +++ b/pkg/ifuzz/arm64/gen/gen.go @@ -5,6 +5,7 @@ package main import ( + "bytes" "encoding/json" "fmt" "os" @@ -12,13 +13,14 @@ import ( "strings" "github.com/google/syzkaller/pkg/ifuzz/arm64" + "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/serializer" "github.com/google/syzkaller/pkg/tool" ) func main() { - if len(os.Args) != 2 { - tool.Failf("usage: gen arm64.json") + if len(os.Args) != 3 { + tool.Failf("usage: gen arm64.json output.file") } jsonStr, err := os.ReadFile(os.Args[1]) if err != nil { @@ -26,7 +28,8 @@ func main() { } insns := JSONToInsns(jsonStr) - fmt.Printf(`// Code generated by pkg/ifuzz/gen. DO NOT EDIT. + out := new(bytes.Buffer) + fmt.Fprintf(out, `// Code generated by pkg/ifuzz/gen. DO NOT EDIT. // go:build !codeanalysis @@ -42,7 +45,10 @@ func init() { var insns_arm64 = `) - serializer.Write(os.Stdout, insns) + serializer.Write(out, insns) + if err := osutil.WriteFileAtomically(os.Args[2], out.Bytes()); err != nil { + tool.Fail(err) + } fmt.Fprintf(os.Stderr, "handled %v\n", len(insns)) } diff --git a/pkg/ifuzz/x86/gen/gen.go b/pkg/ifuzz/x86/gen/gen.go index dc77ea497..c1af7a44e 100644 --- a/pkg/ifuzz/x86/gen/gen.go +++ b/pkg/ifuzz/x86/gen/gen.go @@ -7,6 +7,7 @@ package main import ( "bufio" + "bytes" "errors" "fmt" "os" @@ -16,14 +17,15 @@ import ( "github.com/google/syzkaller/pkg/ifuzz/iset" "github.com/google/syzkaller/pkg/ifuzz/x86" + "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/serializer" "github.com/google/syzkaller/pkg/tool" ) // nolint: gocyclo, gocognit, funlen, dupl func main() { - if len(os.Args) != 2 { - tool.Failf("usage: gen instructions.txt") + if len(os.Args) != 3 { + tool.Failf("usage: gen instructions.txt output.file") } f, err := os.Open(os.Args[1]) if err != nil { @@ -168,7 +170,8 @@ nextInsn: fmt.Fprintf(os.Stderr, "deduped %v instructions\n", len(insns)-len(deduped)) insns = deduped - fmt.Printf(` + out := new(bytes.Buffer) + fmt.Fprintf(out, ` // Code generated by pkg/ifuzz/x86/gen. DO NOT EDIT. //go:build !codeanalysis @@ -183,7 +186,10 @@ func init() { var insns = `) - serializer.Write(os.Stdout, insns) + serializer.Write(out, insns) + if err := osutil.WriteFileAtomically(os.Args[2], out.Bytes()); err != nil { + tool.Fail(err) + } fmt.Fprintf(os.Stderr, "handled %v, skipped %v\n", len(insns), skipped) } diff --git a/pkg/ifuzz/x86/x86.go b/pkg/ifuzz/x86/x86.go index a2825b9e5..053497176 100644 --- a/pkg/ifuzz/x86/x86.go +++ b/pkg/ifuzz/x86/x86.go @@ -1,7 +1,7 @@ // Copyright 2017 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. -//go:generate bash -c "go run gen/gen.go gen/all-enc-instructions.txt > generated/insns.go" +//go:generate go run gen/gen.go gen/all-enc-instructions.txt generated/insns.go // Package x86 allows to generate and mutate x86 machine code. package x86 diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go index 8e0ed7ea3..d16a76cb7 100644 --- a/pkg/osutil/osutil.go +++ b/pkg/osutil/osutil.go @@ -257,6 +257,19 @@ func WriteFile(filename string, data []byte) error { return os.WriteFile(filename, data, DefaultFilePerm) } +// WriteFileAtomically writes data to file filename without exposing and empty/partially-written file. +// This is useful for writing generated source files. Exposing an empty file may break tools +// that run on source files in parallel. +func WriteFileAtomically(filename string, data []byte) error { + // We can't use os.CreateTemp b/c it may be on a different mount, + // and Rename can't move across mounts. + tmpFile := filename + ".tmp" + if err := WriteFile(tmpFile, data); err != nil { + return err + } + return os.Rename(tmpFile, filename) +} + func WriteJSON[T any](filename string, obj T) error { jsonData, err := json.MarshalIndent(obj, "", "\t") if err != nil { diff --git a/sys/fuchsia/fidlgen/main.go b/sys/fuchsia/fidlgen/main.go index ab2bcf0cd..315d6a466 100644 --- a/sys/fuchsia/fidlgen/main.go +++ b/sys/fuchsia/fidlgen/main.go @@ -91,7 +91,7 @@ func main() { return pos.File == file })) - if err := osutil.WriteFile(file, desc); err != nil { + if err := osutil.WriteFileAtomically(file, desc); err != nil { tool.Fail(err) } } |
