aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-04-03 14:35:27 +0200
committerDmitry Vyukov <dvyukov@google.com>2025-04-03 13:17:55 +0000
commitd7ae3a111bd75df44dda69b37da945b50d5133e2 (patch)
tree9797c351f3f4d30ae71068ae1447b457506afb7c
parent012c639d904cf60a221b8b16833c02eed9b2514e (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.go2
-rw-r--r--pkg/ifuzz/arm64/gen/gen.go14
-rw-r--r--pkg/ifuzz/x86/gen/gen.go14
-rw-r--r--pkg/ifuzz/x86/x86.go2
-rw-r--r--pkg/osutil/osutil.go13
-rw-r--r--sys/fuchsia/fidlgen/main.go2
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)
}
}