aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-09-04 19:52:51 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-09-04 20:25:22 +0200
commit8c64b078d1c954972b9f0132a753cdcec1b80d9b (patch)
treef6213a794bf72ccb3e38f6892d7fb229b2b78414 /pkg
parentb06c1bd324d3aff0f132381727c85940bcf93b2f (diff)
pkg/compiler: detect resources without ctors
Fixes #217
Diffstat (limited to 'pkg')
-rw-r--r--pkg/compiler/check.go76
-rw-r--r--pkg/compiler/compiler_test.go2
-rw-r--r--pkg/compiler/testdata/errors2.txt87
-rw-r--r--pkg/compiler/testdata/len.txt23
-rw-r--r--pkg/compiler/testdata/recursion.txt37
5 files changed, 162 insertions, 63 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 26898527e..16077e09d 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -13,8 +13,6 @@ import (
)
func (comp *compiler) check() {
- // TODO: no constructor for a resource
-
comp.checkNames()
comp.checkFields()
comp.checkTypes()
@@ -26,6 +24,7 @@ func (comp *compiler) check() {
}
comp.checkRecursion()
comp.checkLenTargets()
+ comp.checkConstructors()
}
func (comp *compiler) checkNames() {
@@ -218,6 +217,79 @@ func (comp *compiler) checkLenTarget(t *ast.Type, name, target string, fields []
comp.error(t.Pos, "%v target %v does not exist", t.Ident, target)
}
+type structDir struct {
+ Struct string
+ Dir sys.Dir
+}
+
+func (comp *compiler) checkConstructors() {
+ ctors := make(map[string]bool) // resources for which we have ctors
+ checked := make(map[structDir]bool)
+ for _, decl := range comp.desc.Nodes {
+ switch n := decl.(type) {
+ case *ast.Call:
+ for _, arg := range n.Args {
+ comp.checkTypeCtors(arg.Type, sys.DirIn, true, ctors, checked)
+ }
+ if n.Ret != nil {
+ comp.checkTypeCtors(n.Ret, sys.DirOut, true, ctors, checked)
+ }
+ }
+ }
+ for _, decl := range comp.desc.Nodes {
+ switch n := decl.(type) {
+ case *ast.Resource:
+ if !ctors[n.Name.Name] {
+ comp.error(n.Pos, "resource %v can't be created"+
+ " (never mentioned as a syscall return value or output argument/field)",
+ n.Name.Name)
+ }
+ }
+ }
+}
+
+func (comp *compiler) checkTypeCtors(t *ast.Type, dir sys.Dir, isArg bool,
+ ctors map[string]bool, checked map[structDir]bool) {
+ desc := comp.getTypeDesc(t)
+ if desc == typeResource {
+ // TODO(dvyukov): consider changing this to "dir == sys.DirOut".
+ // We have few questionable cases where resources can be created
+ // only by inout struct fields. These structs should be split
+ // into two different structs: one is in and second is out.
+ // But that will require attaching dir to individual fields.
+ if dir != sys.DirIn {
+ r := comp.resources[t.Ident]
+ for r != nil && !ctors[r.Name.Name] {
+ ctors[r.Name.Name] = true
+ r = comp.resources[r.Base.Ident]
+ }
+ }
+ return
+ }
+ if desc == typeStruct {
+ s := comp.structs[t.Ident]
+ name := s.Name.Name
+ key := structDir{name, dir}
+ if checked[key] {
+ return
+ }
+ checked[key] = true
+ for _, fld := range s.Fields {
+ comp.checkTypeCtors(fld.Type, dir, false, ctors, checked)
+ }
+ return
+ }
+ if desc == typePtr {
+ dir = genDir(t.Args[0])
+ }
+ _, args, _ := comp.getArgsBase(t, "", dir, isArg)
+ for i, arg := range args {
+ if desc.Args[i].Type == typeArgType {
+ comp.checkTypeCtors(arg, dir, false, ctors, checked)
+ }
+ }
+}
+
func (comp *compiler) checkRecursion() {
checked := make(map[string]bool)
for _, decl := range comp.desc.Nodes {
diff --git a/pkg/compiler/compiler_test.go b/pkg/compiler/compiler_test.go
index 40450f6a4..130c1fe5d 100644
--- a/pkg/compiler/compiler_test.go
+++ b/pkg/compiler/compiler_test.go
@@ -37,7 +37,7 @@ func TestErrors(t *testing.T) {
"C1": 1,
"C2": 2,
}
- for _, name := range []string{"errors.txt", "recursion.txt", "len.txt"} {
+ for _, name := range []string{"errors.txt", "errors2.txt"} {
name := name
t.Run(name, func(t *testing.T) {
em := ast.NewErrorMatcher(t, filepath.Join("testdata", name))
diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt
new file mode 100644
index 000000000..1687a1f9b
--- /dev/null
+++ b/pkg/compiler/testdata/errors2.txt
@@ -0,0 +1,87 @@
+# 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.
+
+# Recursive resources.
+
+resource r0[r0] ### recursive resource r0->r0
+resource r1[r2] ### recursive resource r1->r2->r1
+resource r2[r1] ### recursive resource r2->r1->r2
+
+foo$0(a0 ptr[out, r0], a1 ptr[out, r1], a2 ptr[out, r2])
+
+# Recursive structs/unions.
+
+sr1 {
+ f1 sr1 ### recursive declaration: sr1.f1 -> sr1 (mark some pointers as opt)
+}
+
+sr2 {
+ f1 sr3
+ f2 sr4
+}
+
+sr3 {
+ f1 ptr[in, sr3] ### recursive declaration: sr3.f1 -> sr3 (mark some pointers as opt)
+}
+
+sr4 {
+ f1 ptr[in, sr3]
+ f2 array[ptr[in, sr5], 4] ### recursive declaration: sr4.f2 -> sr5.f2 -> sr6.f1 -> sr4 (mark some pointers as opt)
+}
+
+sr5 [
+ f1 int32
+ f2 sr6
+]
+
+sr6 {
+ f1 sr4
+}
+
+sr7 {
+ f1 ptr[in, sr7, opt]
+}
+
+# Len target tests.
+
+foo$100(a int32, b len[a])
+foo$101(a len[a]) ### len target a refer to itself
+foo$102(a ptr[in, len[a, int8]]) ### len target a refer to itself
+foo$103(a int32, b len[c]) ### len target c does not exist
+foo$104(a len[parent]) ### len target parent does not exist
+foo$105(a ptr[in, int32], b ptr[in, array[len[a, int32]]])
+foo$106(a int32, b ptr[in, csum[a, inet, int32]])
+foo$107(a int32, b ptr[in, csum[c, inet, int32]]) ### csum target c does not exist
+
+s1 {
+ f1 len[s2, int32] ### len target s2 does not exist
+}
+
+s2 {
+ f1 s1
+}
+
+foo$200(a ptr[in, s2])
+foo$201(a ptr[in, s1])
+
+# Resource ctor tests.
+
+resource r100[int32] ### resource r100 can't be created (never mentioned as a syscall return value or output argument/field)
+resource r101[int32]
+resource r102[r101]
+resource r103[r102]
+resource r104[int8]
+resource r105[int8]
+resource r106[int8] ### resource r106 can't be created (never mentioned as a syscall return value or output argument/field)
+resource r107[int8] ### resource r107 can't be created (never mentioned as a syscall return value or output argument/field)
+
+foo$300(a ptr[out, array[r103]], b ptr[in, s300], c r107) r104
+
+s300 {
+ f1 ptr[inout, s301]
+ f2 r106
+}
+
+s301 {
+ f2 r105
+}
diff --git a/pkg/compiler/testdata/len.txt b/pkg/compiler/testdata/len.txt
deleted file mode 100644
index 2b7836bbd..000000000
--- a/pkg/compiler/testdata/len.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-# 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.
-
-foo$0(a int32, b len[a])
-foo$1(a len[a]) ### len target a refer to itself
-foo$2(a ptr[in, len[a, int32]]) ### len target a refer to itself
-foo$3(a int32, b len[c]) ### len target c does not exist
-foo$4(a len[parent]) ### len target parent does not exist
-foo$5(a ptr[in, int32], b ptr[in, array[len[a, int32]]])
-
-foo$100(a int32, b ptr[in, csum[a, inet, int32]])
-foo$101(a int32, b ptr[in, csum[c, inet, int32]]) ### csum target c does not exist
-
-s1 {
- f1 len[s2, int32] ### len target s2 does not exist
-}
-
-s2 {
- f1 s1
-}
-
-foo$200(a ptr[in, s2])
-foo$201(a ptr[in, s1])
diff --git a/pkg/compiler/testdata/recursion.txt b/pkg/compiler/testdata/recursion.txt
deleted file mode 100644
index 683049b91..000000000
--- a/pkg/compiler/testdata/recursion.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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.
-
-resource r6[r6] ### recursive resource r6->r6
-resource r7[r8] ### recursive resource r7->r8->r7
-resource r8[r7] ### recursive resource r8->r7->r8
-
-sr1 {
- f1 sr1 ### recursive declaration: sr1.f1 -> sr1 (mark some pointers as opt)
-}
-
-sr2 {
- f1 sr3
- f2 sr4
-}
-
-sr3 {
- f1 ptr[in, sr3] ### recursive declaration: sr3.f1 -> sr3 (mark some pointers as opt)
-}
-
-sr4 {
- f1 ptr[in, sr3]
- f2 array[ptr[in, sr5], 4] ### recursive declaration: sr4.f2 -> sr5.f2 -> sr6.f1 -> sr4 (mark some pointers as opt)
-}
-
-sr5 [
- f1 int32
- f2 sr6
-]
-
-sr6 {
- f1 sr4
-}
-
-sr7 {
- f1 ptr[in, sr7, opt]
-}