aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-11-26 11:36:41 +0100
committerDmitry Vyukov <dvyukov@google.com>2024-11-26 11:32:06 +0000
commit7de7a5ecf43a5c41b5170d0cb70cb744fdf9de9f (patch)
tree56ad68cab4305fe256e4cb4ad3133018a14176f1 /pkg
parent6cf3ac235c99d92976346acbdc153d68fbb2c841 (diff)
pkg/compiler: allow manual consts to override auto-extracted consts
Currently if const values in 2 .const files have different value, the compiler produces an error. This is problematic for auto-extacted consts since we extract them for only 1 arch now. So if a const has different values for different arches, auto-extacted consts may not reflect that, and we can get a mismatch with manual descriptions that has correct values for all arches. So if both manual and auto-extacted consts have different values, silently prefer the manual ones. I've tried to do some whitelisting of consts during auto-extaction, but the list is large and changing over time. This solution is not perfect since the manual descriptions may have a bug, and the mismatch is actually pointing to that bug. Maybe in future we could extract for all arches separately, or do something else. But let's do this for now.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/compiler/compiler_test.go21
-rw-r--r--pkg/compiler/const_file.go37
-rw-r--r--pkg/compiler/consts.go2
-rw-r--r--pkg/compiler/testdata/auto.txt4
-rw-r--r--pkg/compiler/testdata/auto.txt.const6
-rw-r--r--pkg/compiler/testdata/auto0.txt4
-rw-r--r--pkg/compiler/testdata/auto0.txt.const6
7 files changed, 67 insertions, 13 deletions
diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go
index f43b2ccb3..711567163 100644
--- a/pkg/compiler/compiler_test.go
+++ b/pkg/compiler/compiler_test.go
@@ -137,6 +137,27 @@ func TestData(t *testing.T) {
}
}
+func TestAutoConsts(t *testing.T) {
+ t.Parallel()
+ eh := func(pos ast.Pos, msg string) {
+ t.Errorf("%v: %v", pos, msg)
+ }
+ desc := ast.ParseGlob(filepath.Join("testdata", "auto*.txt"), eh)
+ if desc == nil {
+ t.Fatalf("parsing failed")
+ }
+ constFile := DeserializeConstFile(filepath.Join("testdata", "auto*.txt.const"), eh)
+ if constFile == nil {
+ t.Fatalf("const loading failed")
+ }
+ target := targets.List[targets.TestOS][targets.TestArch64]
+ consts := constFile.Arch(targets.TestArch64)
+ prog := Compile(desc, consts, target, eh)
+ if prog == nil {
+ t.Fatalf("compilation failed")
+ }
+}
+
func TestFuzz(t *testing.T) {
t.Parallel()
for _, data := range []string{
diff --git a/pkg/compiler/const_file.go b/pkg/compiler/const_file.go
index 1968092a4..0220da555 100644
--- a/pkg/compiler/const_file.go
+++ b/pkg/compiler/const_file.go
@@ -26,6 +26,10 @@ type ConstFile struct {
type constVal struct {
name string
vals map[string]uint64 // arch -> value
+ // Set if the value for the arch is weak (come from auto.txt).
+ // Weak values are replaced on mismatch, instead of producing
+ // an error about mismatching values.
+ weak map[string]bool
}
const undefined = "???"
@@ -40,30 +44,38 @@ func NewConstFile() *ConstFile {
func (cf *ConstFile) AddArch(arch string, consts map[string]uint64, undeclared map[string]bool) error {
cf.arches[arch] = true
for name, val := range consts {
- if err := cf.addConst(arch, name, val, true); err != nil {
+ if err := cf.addConst(arch, name, val, true, false); err != nil {
return err
}
}
for name := range undeclared {
- if err := cf.addConst(arch, name, 0, false); err != nil {
+ if err := cf.addConst(arch, name, 0, false, false); err != nil {
return err
}
}
return nil
}
-func (cf *ConstFile) addConst(arch, name string, val uint64, declared bool) error {
+func (cf *ConstFile) addConst(arch, name string, val uint64, declared, weak bool) error {
cv := cf.m[name]
if cv.vals == nil {
cv.name = name
cv.vals = make(map[string]uint64)
- }
- if val0, declared0 := cv.vals[arch]; declared && declared0 && val != val0 {
- return fmt.Errorf("const=%v arch=%v has different values: %v[%v] vs %v[%v]",
- name, arch, val, declared, val0, declared0)
+ cv.weak = make(map[string]bool)
}
if declared {
+ val0, declared0 := cv.vals[arch]
+ if declared0 {
+ if weak {
+ return nil
+ }
+ if !cv.weak[arch] && val != val0 {
+ return fmt.Errorf("const=%v arch=%v has different values: %v[%v] vs %v[%v]",
+ name, arch, val, declared, val0, declared0)
+ }
+ }
cv.vals[arch] = val
+ cv.weak[arch] = weak
}
cf.m[name] = cv
return nil
@@ -196,6 +208,7 @@ func (cf *ConstFile) deserializeFile(data []byte, file, arch string, eh ast.Erro
eh(pos, fmt.Sprintf(msg, args...))
return false
}
+ weak := file == "auto.txt.const"
s := bufio.NewScanner(bytes.NewReader(data))
var arches []string
for ; s.Scan(); pos.Line++ {
@@ -224,7 +237,7 @@ func (cf *ConstFile) deserializeFile(data []byte, file, arch string, eh ast.Erro
}
continue
}
- if !cf.parseConst(arches, name, val, errf) {
+ if !cf.parseConst(arches, name, val, weak, errf) {
return false
}
}
@@ -236,7 +249,7 @@ func (cf *ConstFile) deserializeFile(data []byte, file, arch string, eh ast.Erro
type errft func(msg string, args ...interface{}) bool
-func (cf *ConstFile) parseConst(arches []string, name, line string, errf errft) bool {
+func (cf *ConstFile) parseConst(arches []string, name, line string, weak bool, errf errft) bool {
var dflt map[string]uint64
for _, pair := range strings.Split(line, ",") {
fields := strings.Split(pair, ":")
@@ -274,13 +287,13 @@ func (cf *ConstFile) parseConst(arches []string, name, line string, errf errft)
for _, arch := range fields[:len(fields)-1] {
arch = strings.TrimSpace(arch)
delete(dflt, arch)
- if err := cf.addConst(arch, name, val, defined); err != nil {
+ if err := cf.addConst(arch, name, val, defined, weak); err != nil {
return errf("%v", err)
}
}
}
for arch, val := range dflt {
- if err := cf.addConst(arch, name, val, true); err != nil {
+ if err := cf.addConst(arch, name, val, true, weak); err != nil {
return errf("%v", err)
}
}
@@ -292,7 +305,7 @@ func (cf *ConstFile) parseOldConst(arch, name, line string, errf errft) bool {
if err != nil {
return errf("failed to parse int: %v", err)
}
- if err := cf.addConst(arch, name, val, true); err != nil {
+ if err := cf.addConst(arch, name, val, true, false); err != nil {
return errf("%v", err)
}
return true
diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go
index 62de4aa51..5e1ed9188 100644
--- a/pkg/compiler/consts.go
+++ b/pkg/compiler/consts.go
@@ -42,7 +42,7 @@ func FabricateSyscallConsts(target *targets.Target, constInfo map[string]*ConstI
for _, info := range constInfo {
for _, c := range info.Consts {
if strings.HasPrefix(c.Name, target.SyscallPrefix) {
- cf.addConst(target.Arch, c.Name, 0, true)
+ cf.addConst(target.Arch, c.Name, 0, true, false)
}
}
}
diff --git a/pkg/compiler/testdata/auto.txt b/pkg/compiler/testdata/auto.txt
new file mode 100644
index 000000000..1e64e0a95
--- /dev/null
+++ b/pkg/compiler/testdata/auto.txt
@@ -0,0 +1,4 @@
+# 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.
+
+foo(a const[FOO])
diff --git a/pkg/compiler/testdata/auto.txt.const b/pkg/compiler/testdata/auto.txt.const
new file mode 100644
index 000000000..388aa936f
--- /dev/null
+++ b/pkg/compiler/testdata/auto.txt.const
@@ -0,0 +1,6 @@
+# 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.
+
+arches = 64
+SYS_foo = 11
+FOO = 22
diff --git a/pkg/compiler/testdata/auto0.txt b/pkg/compiler/testdata/auto0.txt
new file mode 100644
index 000000000..9c3608caf
--- /dev/null
+++ b/pkg/compiler/testdata/auto0.txt
@@ -0,0 +1,4 @@
+# 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.
+
+foo$auto(a const[FOO])
diff --git a/pkg/compiler/testdata/auto0.txt.const b/pkg/compiler/testdata/auto0.txt.const
new file mode 100644
index 000000000..4ba494b07
--- /dev/null
+++ b/pkg/compiler/testdata/auto0.txt.const
@@ -0,0 +1,6 @@
+# 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.
+
+arches = 64
+SYS_foo = 1
+FOO = 2