aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/compiler/check.go
diff options
context:
space:
mode:
authorHrutvik Kanabar <hrutvik@google.com>2022-10-25 10:13:51 +0000
committerAleksandr Nogikh <wp32pw@gmail.com>2022-11-21 11:06:14 +0100
commitd0405298b24db0e2a6b2abfdc8c7e5ebbe49d1a0 (patch)
treec022669ce377e0c09376d60b45a01584c67c0989 /pkg/compiler/check.go
parent7954d07c228dd9ce63b7ebd13239b4d1f2c35233 (diff)
prog, pkg/compiler: add `BufferCompressed` buffer type & `compressed_image` builtin
Create the `BufferCompressed` kind of `BufferType`, which will be used to represent compressed data. Create the corresponding `compressed_image` syzlang builtin, which is backed by `BufferCompressed`. For now, no syscalls use this feature - this will be introduced in future commits. We have to be careful to decompress the data before mutating, and re-compress before storing. We make sure that any deserialised `BufferCompressed` data is valid too. `BufferCompressed` arguments are mutated using a generic heatmap. In future, we could add variants of `BufferCompressed` or populate the `BufferType` sub-kind, using it to choose different kinds of heatmap for different uncompressed data formats. Various operations on compressed data must be forbidden, so we check for `BufferCompressed` in key places. We also have to ensure `compressed_image` can only be used in syscalls that are marked `no_{generate,minimize}`. Therefore, we add a generic compiler check which allows type descriptions to require attributes on the syscalls which use them.
Diffstat (limited to 'pkg/compiler/check.go')
-rw-r--r--pkg/compiler/check.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go
index 402e9a84e..4b2dd1330 100644
--- a/pkg/compiler/check.go
+++ b/pkg/compiler/check.go
@@ -341,8 +341,48 @@ func (comp *compiler) checkAttributeValues() {
comp.error(f.Pos, "%v type must not be used as output", f.Type.Ident)
}
}
+ case *ast.Call:
+ attrNames := make(map[string]bool)
+ descAttrs := comp.parseAttrs(callAttrs, n, n.Attrs)
+ for desc := range descAttrs {
+ attrNames[prog.CppName(desc.Name)] = true
+ }
+
+ checked := make(map[string]bool)
+ for _, a := range n.Args {
+ comp.checkRequiredCallAttrs(n, attrNames, a.Type, checked)
+ }
+ }
+ }
+}
+
+func (comp *compiler) checkRequiredCallAttrs(call *ast.Call, callAttrNames map[string]bool,
+ t *ast.Type, checked map[string]bool) {
+ desc := comp.getTypeDesc(t)
+ for attr := range desc.RequiresCallAttrs {
+ if !callAttrNames[attr] {
+ comp.error(call.Pos, "call %v refers to type %v and so must be marked %s", call.Name.Name, t.Ident, attr)
}
}
+
+ if desc == typeStruct {
+ s := comp.structs[t.Ident]
+ // Prune recursion, can happen even on correct tree via opt pointers.
+ if checked[s.Name.Name] {
+ return
+ }
+ checked[s.Name.Name] = true
+ fields := s.Fields
+ for _, fld := range fields {
+ comp.checkRequiredCallAttrs(call, callAttrNames, fld.Type, checked)
+ }
+ } else if desc == typeArray {
+ typ := t.Args[0]
+ comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
+ } else if desc == typePtr {
+ typ := t.Args[1]
+ comp.checkRequiredCallAttrs(call, callAttrNames, typ, checked)
+ }
}
func (comp *compiler) checkLenTargets() {